#python #pyqt #pyqt5 #qlayout
#python #pyqt #pyqt5 #qlayout
Вопрос:
PyQt 5.9.2, Python 3.6.6, Windows 10
Я хочу динамически скрывать / показывать виджеты в зависимости от текущей ширины их виджета контейнера. Если space
занимает менее 10% от всей ширины, кнопка «Один» скрыта, затем кнопка «Два». Когда пользователь увеличивает контейнер, кнопки снова отображаются: «Два», затем «Один».
Вот очень простая версия моей реализации, которая в основном работает, но есть одна большая проблема. Я начинаю изменять размер, кнопка «Один» скрывается, но затем вступает в силу некоторое ограничение, и контейнер больше не может быть уменьшен в размере. Я должен отпустить кнопку мыши и снова запустить процесс, чтобы скрыть кнопку «Два» тоже.
import sys
from PyQt5 import QtWidgets
form, space, widgets = None, None, None
def resize_event(event):
if free_space_width() < 0:
visible_w = [w for w in widgets if w.isVisible()]
if len(visible_w) > 1: # do not hide the last one
for w in visible_w:
w.hide()
if free_space_width(w.width()) >= 0:
break # enough space
else:
invisible_w = [w for w in widgets if not w.isVisible()]
for w in reversed(invisible_w):
if free_space_width(-w.width()) < 0:
break
w.show()
def free_space_width(shift=0):
"Free space should be at least 10% of the bar width"
return space.width() shift - 0.1 * form.width()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
form = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(form)
layout.setSpacing(0) # for simplicity
form.resize(480, 64)
form.resizeEvent = resize_event
widgets = [QtWidgets.QPushButton("test button %d" % (i 1), form)
for i in range(3)]
for i in widgets:
layout.addWidget(i)
space = QtWidgets.QWidget(form) # stretchable space
s_policy = space.sizePolicy()
s_policy.setHorizontalStretch(1)
space.setSizePolicy(s_policy)
layout.addWidget(space)
form.show()
sys.exit(app.exec_())
Комментарии:
1. с помощью предоставленного вами кода я вижу, что он работает правильно. То есть, если я перемещаю мышь влево с нажатой мышью, не отпуская ее, виджеты скрыты, сначала «1», затем «2» скрыты.
2. @eyllanesc для меня это работает правильно, только если изменение размера начинается, когда обе кнопки скрыты: imgur.com/a/MNGcsQW
3. В моем случае PyQt5 5.12.2 в Linux не создает этой проблемы, не могли бы вы попробовать обновленную версию? если это сработает, то проблема будет связана с ошибкой в используемой вами версии, если нет, то, возможно, проблема связана с ошибкой Qt, но только для вашей ОС.
Ответ №1:
Можно поместить кнопки в виджет контейнера и переопределить minimumSizeHint
метод, чтобы Qt не пытался вычислить это самостоятельно.
def minimumSizeHint(self):
return QtCore.QSize(150, 30)
Обновление: я реализовал логику отображения / скрытия в функции пользовательского макета setGeometry
.
Комментарии:
1. В моем случае у меня была такая же проблема после выполнения вашего кода. Я решил это с помощью
setSizeConstraint
. Виджет стал плавно перемещаться безmouseRelease
. Честно говоря, мой ответ состоял в том, чтобы предложить одно решение. Это может быть напрасно. Ваш ответ полезен для моего обучения, в правиле SOF я даю вам второй upvode. Спасибо.
Ответ №2:
затем вступает в силу некоторое ограничение, и контейнер не может быть уменьшен в размере
layout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)
Я думаю, вы должны реализовать его в этом коде следующим образом.
layout = QtWidgets.QHBoxLayout(form)
layout.setSpacing(0) # for simplicity
layout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)
Комментарии:
1. Спасибо, это дало мне подсказку. На самом деле мой пример не был завершен, потому что в моем проекте кнопки находятся внутри виджета контейнера, который является подклассом
QFrame
. Поэтому мне нужно переопределитьminimumSizeHint
в моем классе контейнера и позволить Qt делать все остальное.