QWidget Geometry() 不更新

Posted

技术标签:

【中文标题】QWidget Geometry() 不更新【英文标题】:QWidget Geometry() not updating 【发布时间】:2014-06-04 16:43:39 【问题描述】:

我将QWidgets 排在QVBoxLayout 内的QScrollAreasetWidgetResizable(True)

当我调整QWidgets 之一的大小时,QWidgets 在图形用户界面中相应地重新定位,但它们的geometry() 属性并没有反映这一点,geometry().x()geometry().y() 仍然是搬家前后一样。

到目前为止,我发现更新x()y() 坐标的唯一方法是hide()show() QScrollArea

我尝试了update()updateGeometry()repaint(),但都没有成功。

这是我为总结问题而制作的示例测试代码:

import sys
from PySide import QtGui, QtCore


class MainWindow(QtGui.QMainWindow):

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

        self.showMaximized()
        self.widget_window = QtGui.QWidget()
        self.scrollarea = QtGui.QScrollArea()
        self.v_layout = QtGui.QVBoxLayout()
        self.test_1 = QtGui.QPushButton('Test 1')
        self.test_2 = QtGui.QPushButton('Test 2')
        self.v_layout.addWidget(self.test_1)
        self.v_layout.addWidget(self.test_2)
        self.widget_window.setLayout(self.v_layout)
        self.scrollarea.setWidgetResizable(True)
        self.scrollarea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.scrollarea.setAlignment(QtCore.Qt.AlignCenter)
        self.scrollarea.setWidget(self.widget_window)
        self.setCentralWidget(self.scrollarea)
        print(self.test_2.geometry().x())
        print(self.test_2.geometry().y())
        self.test_1.setFixedHeight(1000)
        #uncommenting the following next two lines, solves the problem
        #self.scrollarea.hide()
        #self.scrollarea.show()
        print(self.test_2.geometry().x())
        print(self.test_2.geometry().y())

def main():
    app = QtGui.QApplication(sys.argv)
    main = MainWindow()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

我的问题是:

    有更好的解决方案吗? updateGeometry() 不应该实际更新geometry() 吗? 为什么会发生这种行为? (即为什么它以图形方式而不是以编程方式更新?) 可以连续使用hide()show() 在其他上下文中导致一些问题(窗口闪烁或其他...)?

【问题讨论】:

本例中QScrollArea是如何添加到VLayout中的? 其实布局是针对一个QWidget,它是QScrollArea的内部小部件。 QScrollArea 不是任何布局的一部分。 【参考方案1】:

当您更新 GUI 时,它不是即时的。它在您将控制权交给事件循环时执行。在这种情况下,它在__init__ 完成之后 完成,这显然是在你的prints 之后。因此,您将看到旧位置。

hide/show 在那个时候强制更新。这就是你得到正确值的原因。但是,这不是最好的方法,因为您可能会在 hide/show 工作时观察到闪烁。

更好的方法是告诉事件循环在继续之前处理事件。这将确保 GUI 得到更新:

    #...
    print(self.test_2.geometry().x())
    print(self.test_2.geometry().y())
    self.test_1.setFixedHeight(1000)
    QtGui.QApplication.processEvents()
    print(self.test_2.geometry().x())
    print(self.test_2.geometry().y())
    #...

PS:我假设,你有充分的理由这样做。大多数情况下,您不会关心 GUI 何时更新。

【讨论】:

谢谢,这解决了我的问题。还有一件事我不明白,GUI 如何在不更新 geometry().x()geometry().y() 值的情况下自行更新?一般来说,情况正好相反(即代码更新但不是 GUI)? @IlyesFerchiou:当您调用self.test_1.setFixedHeight(1000) 时,GUI 和geometry 都不会更新。 geometry 的视觉更新或重新计算不是即时的。这是“排队”。一旦 Qt 事件循环有机会处理这些事件,就会执行更新。 .processEvents() 基本上“暂停”__init__ 并让 Qt 事件循环处理那些更新事件。 换句话说,在您的原始版本中,GUI 没有在这些打印调用之间更新。它发生在之后。

以上是关于QWidget Geometry() 不更新的主要内容,如果未能解决你的问题,请参考以下文章

MySQL的GIS、GEO入门笔记

空间分析开源库GEOS

d3.geo.path 矩形包裹错误的方式

java.lang.ClassCastException:com.google.android.gms.maps.model.LatLng 无法转换为 com.mapbox.mapboxsdk.geo

Postgresql Geometry与wkt互转及长度计算

将 golang S2 Geometry 库与 dynamodb 一起使用