Изменение макета в событии изменения размера

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", затем "2".

eyllanesc 09.04.2019 22:56

@eyllanesc у меня работает правильно, только если изменение размера начинается, когда обе кнопки скрыты: imgur.com/a/MNGcsQW

Winand 09.04.2019 23:32

В моем случае PyQt5 5.12.2 в Linux не вызывает этой проблемы, не могли бы вы попробовать обновленную версию? если это работает, то проблема будет в ошибке используемой вами версии, если нет, то, возможно, проблема в ошибке Qt, но только для вашей ОС.

eyllanesc 09.04.2019 23:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
1 449
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

then some constraint comes into place and the container cannot be reduced in size

layout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)

Я думаю, вы должны реализовать это в этом коде, как это.

layout = QtWidgets.QHBoxLayout(form)
layout.setSpacing(0)  # for simplicity
layout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)

Спасибо, это дало мне подсказку. На самом деле мой пример не был полным, потому что в моем проекте кнопки находятся внутри виджета-контейнера, который является подклассом QFrame. Поэтому мне нужно переопределить minimumSizeHint в моем классе-контейнере и позволить Qt делать все остальное.

Winand 10.04.2019 17:11

Можно поместить кнопки в виджет-контейнер и переопределить метод minimumSizeHint, чтобы Qt не пытался вычислить это сам.

def minimumSizeHint(self):
    return QtCore.QSize(150, 30)

Обновление: я реализовал логику отображения/скрытия в функции пользовательский макетsetGeometry.

В моем случае у меня была такая же проблема после выполнения вашего кода. Я решил ее с помощью setSizeConstraint. Виджет стал плавно перемещаться без mouseRelease. Честно говоря, мой ответ состоял в том, чтобы предложить одно решение. Это может быть напрасно. Ваш ответ полезно для моего обучения, в правиле SOF, я даю вам второй upvode. Спасибо.

Haru 11.04.2019 02:07

Другие вопросы по теме