为什么没有显示绝对定位的小部件?
Why is an absolute positioned widget not shown?
我正在使用 Qt5 尝试使用绝对定位使小部件工作。下面的代码是我正在尝试做的事情的最小工作示例。快速浏览代码:
CentralWidget
是主要 window 的中央小部件,并使用绝对定位保持 MyWidget
,例如不使用任何布局。
MyWidget
不会立即设置其子控件,但会提供一个 SetData
方法,该方法首先删除所有当前子控件,然后将新的子控件添加到其布局中。
SetData
在 window. 中使用定时器触发
我注释掉了两行代码。通过向 CentralWidget
添加布局,第一个 "enables" 使用布局的相对定位。这条线显示了我想要实现的目标,但具有绝对定位。第二个注释启用一些调试信息:
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()
此行为的原因与小部件未添加到布局这一事实直接相关并且其内容是在显示后添加的。
事实上,如果您在初始化时和 mainWindow.show()
之前调用 centralWidget.SetData()
,它将按预期工作。
当您将子部件添加到布局时会发生很多事情,这通常涉及对子部件尺寸提示的多次调用,允许父部件调整自己的尺寸提示,并且,之后that,调整其大小及其子项的大小。
如果 "container widget" 本身包含在另一个布局中,则该小部件将在下一个事件周期中自动调整大小(基于其提示),但这不会发生在你的情况下,因为你的是一个 "free" 小部件。
您要查找的函数是QWidget.adjustSize()
,但是,由于上述原因,您无法在添加子控件后立即调用它。
要解决您的问题,您可以在 adjustSize()
之前调用 QApplication.processEvents()
,或者最终使用基于 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)
我正在使用 Qt5 尝试使用绝对定位使小部件工作。下面的代码是我正在尝试做的事情的最小工作示例。快速浏览代码:
CentralWidget
是主要 window 的中央小部件,并使用绝对定位保持MyWidget
,例如不使用任何布局。MyWidget
不会立即设置其子控件,但会提供一个SetData
方法,该方法首先删除所有当前子控件,然后将新的子控件添加到其布局中。SetData
在 window. 中使用定时器触发
我注释掉了两行代码。通过向 CentralWidget
添加布局,第一个 "enables" 使用布局的相对定位。这条线显示了我想要实现的目标,但具有绝对定位。第二个注释启用一些调试信息:
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()
此行为的原因与小部件未添加到布局这一事实直接相关并且其内容是在显示后添加的。
事实上,如果您在初始化时和 mainWindow.show()
之前调用 centralWidget.SetData()
,它将按预期工作。
当您将子部件添加到布局时会发生很多事情,这通常涉及对子部件尺寸提示的多次调用,允许父部件调整自己的尺寸提示,并且,之后that,调整其大小及其子项的大小。
如果 "container widget" 本身包含在另一个布局中,则该小部件将在下一个事件周期中自动调整大小(基于其提示),但这不会发生在你的情况下,因为你的是一个 "free" 小部件。
您要查找的函数是QWidget.adjustSize()
,但是,由于上述原因,您无法在添加子控件后立即调用它。
要解决您的问题,您可以在 adjustSize()
之前调用 QApplication.processEvents()
,或者最终使用基于 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)