Почему виджет с абсолютным позиционированием не отображается? - PullRequest
0 голосов
/ 30 апреля 2020

Использование Qt5 Я пытаюсь заставить работать виджет, используя абсолютное позиционирование. Код ниже - это минимальный рабочий пример того, что я пытаюсь сделать. Быстрый просмотр кода:

  • CentralWidget является центральным виджетом главного окна и содержит MyWidget, используя абсолютное позиционирование, например, без использования каких-либо макетов.
  • MyWidget не устанавливает свои дочерние виджеты немедленно, но предоставляет метод SetData, который сначала удаляет все текущие дочерние виджеты, а затем добавляет новые дочерние виджеты в свой макет.
  • SetData запускается с помощью таймера в главном окне.

Я закомментировал две строки кода. Первый «включает» относительное позиционирование с использованием макетов, добавляя макет к CentralWidget. Эта строка показывает, чего я пытаюсь достичь, но с абсолютным позиционированием. Второй комментарий включает некоторую отладочную информацию:

MyWidget
  layout.count: 3
  size: PyQt5.QtCore.QSize(-1, -1)
  sizeHint: PyQt5.QtCore.QSize(200, 100)

CentralWidget
  size: PyQt5.QtCore.QSize(18, 18)
  sizeHint: PyQt5.QtCore.QSize(18, 18)

Что я делаю неправильно для того, чтобы MyWidget был виден при абсолютном позиционировании?

Код:

from PyQt5 import QtCore, QtWidgets
import sys


class MyWidget(QtWidgets.QWidget):
    z = 0

    def __init__(self, parent):
        super().__init__(parent)

        self._layout = QtWidgets.QVBoxLayout(self)

    def SetData(self):
        while self._layout.count() > 0:
            widget = self._layout.takeAt(0).widget()
            widget.hide()
            widget.deleteLater()

        for i in range(3):
            self._layout.addWidget(QtWidgets.QLabel(str(MyWidget.z * 10 + i)))

        MyWidget.z += 1


class CentralWidget(QtWidgets.QWidget):
    def __init__(self, parent):
        super().__init__(parent)

        self._myWidget = MyWidget(self)

        # QtWidgets.QHBoxLayout(self).addWidget(self._myWidget)

    def SetData(self):
        self._myWidget.SetData()
        # print("MyWidget\n  layout.count: {}\n  size: {}\n  sizeHint: {}\n\nCentralWidget\n  size: {}\n  sizeHint: {}\n\n".format(self._myWidget.layout().count(), self.sizeHint(), self.size(), self._myWidget.sizeHint(), self._myWidget.size()))


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        centralWidget = CentralWidget(self)
        self.setCentralWidget(centralWidget)

        self._timer = QtCore.QTimer(self)
        self._timer.timeout.connect(centralWidget.SetData)
        self._timer.start(500)


def main():
    app = QtWidgets.QApplication(sys.argv)

    mainWindow = MainWindow()
    mainWindow.show()

    app.exec_()


if __name__ == "__main__":
    main()

1 Ответ

1 голос
/ 30 апреля 2020

Причина такого поведения напрямую связана с тем, что виджет не добавляется в макет , а его содержимое добавляется после отображения.

Фактически, если вы вызываете centralWidget.SetData() после инициализации и до mainWindow.show() он будет работать как положено.

Многое происходит, когда вы добавляете дочерний виджет в макет, и это обычно включает в себя несколько вызовов дочерних подсказок размера, позволяя родителю адаптировать свою подсказку о размере, и, после этого , адаптировать его размер и размер его дочерних элементов.

Если этот «контейнерный виджет» сам содержится в другом макете, то размер виджета будет автоматически изменен (в зависимости от его подсказки) в следующем цикле событий, но в вашем случае этого не происходит, так как ваш - «бесплатный» виджет.

Функция, которую вы ищете, QWidget.adjustSize(), но по вышеупомянутым причинам вы не можете вызвать его сразу после добавления дочерних виджетов.
Чтобы решить вашу проблему, вы можете позвонить QApplication.processEvents() до adjustSize(), или, в конце концов, используйте 0-основанный одиночный выстрел QTimer:

    def SetData(self):
        while self._layout.count() > 0:
            widget = self._layout.takeAt(0).widget()
            widget.hide()
            widget.deleteLater()

        for i in range(3):
            self._layout.addWidget(QtWidgets.QLabel(str(MyWidget.z * 10 + i)))

        MyWidget.z += 1

        QtCore.QTimer.singleShot(0, self.adjustSize)
...