python - pyqt:如何获得对 QFileDialog 中按钮的一致访问

标签 python testing pyqt qfiledialog

我一直在为基于 PyQt 的项目开发一些调试/测试基础设施。我用特殊的调试属性标记大多数小部件,即使这些小部件是在 C++ 端创建的。

但是,对 QFileDialog 中同一按钮的多次访问似乎会导致新的 sip 包装器实例。也就是说,如果我多次访问“取消”按钮,PyQt 不会每次都返回相同的 Python 对象。

这是一个可用于重现问题的最小测试程序:

from PyQt4.QtCore import QTimer
from PyQt4.QtGui import QApplication, QFileDialog, QDialogButtonBox

def print_debug_stuff():
    # Find the dialog from among the top-level widgets
    dlg = filter( lambda w: isinstance(w, QFileDialog), QApplication.topLevelWidgets() )[0]

    # Find the button box in the dialog, then find the cancel button
    buttonBox = dlg.findChild(QDialogButtonBox, "buttonBox")
    cancelButton = buttonBox.children()[2]

    # Does it have our debug attribute? Can we add it?
    print "Tagging button: '{}' ({})".format( cancelButton.text(), cancelButton )
    print "...had my_debug_tag?", hasattr(cancelButton, "my_debug_tag")

    # Add the debug attribute
    buttonBox.children()[2].my_debug_tag = "hello"
    print "...has my_debug_tag?", hasattr(cancelButton, "my_debug_tag")

app = QApplication([])

# Repeatedly print debug info until the program quits
timer = QTimer(timeout=print_debug_stuff)
timer.setInterval( 100.0 )
timer.start()

# Open a (non-native!) file save dialog
QFileDialog.getSaveFileName(options=QFileDialog.DontUseNativeDialog)

期望这个程序可以输出如下内容:

Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8cb0>)
...had my_debug_tag? False
...has my_debug_tag? True
Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8cb0>)
...had my_debug_tag? True
...has my_debug_tag? True
Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8cb0>)
...had my_debug_tag? True
...has my_debug_tag? True

...但是,这就是我实际看到的。请注意,cancelButton 对象每次都有不同的地址,并且我添加的调试属性丢失了:

Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8cb0>)
...had my_debug_tag? False
...has my_debug_tag? True
Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8ef0>)
...had my_debug_tag? False
...has my_debug_tag? True
Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8e60>)
...had my_debug_tag? False
...has my_debug_tag? True
Tagging button: 'Cancel' (<PyQt4.QtGui.QPushButton object at 0x1013c8dd0>)
...had my_debug_tag? False
...has my_debug_tag? True

因此,PyQt 似乎正在“丢失”它之前创建的 Python 对象,然后为每次重复访问创建一个"new"对象。这是预期的吗?

顺便说一句,这个测试程序在 Mac OS X (10.7) 和 Linux (Ubuntu 12) 上的行为是相同的。我正在使用 PyQt 4.8.5。

最佳答案

您尝试引用的按钮是一个内部 Qt 对象,它没有相应的 python 等效项。因此,每次访问 PyQt 时,PyQt 自然都必须为其创建一个新的 python 包装器。如果您执行print dlg,您将看到也为此创建了一个新的包装器。

考虑到这一点,显然标记 python 包装器是行不通的,因为包装器在超出范围后将立即被垃圾收集。

要解决此问题,您需要标记内部 Qt 对象本身。一种简单的方法是使用 properties :

    prop = cancelButton.property("my_debug_tag")
    print "...had my_debug_tag?", p.isValid()

    cancelButton.setProperty("my_debug_tag", "hello")

    prop = cancelButton.property("my_debug_tag")
    print "...has my_debug_tag?", p.isValid()

显然,这种技术仅适用于继承 QObject 的 Qt 类。

关于python - pyqt:如何获得对 QFileDialog 中按钮的一致访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21221877/

相关文章:

javascript - 为什么 Jest 在没有标志 --runInBand 的情况下会失败?

ruby-on-rails - 如何测试回形针 URL?

python - 从 1 列 Pandas 创建多列

python - 请求工具带上传一个巨大的文件

python - 如何将语句写入两行?

ruby-on-rails - 确保记录关联到仅由具有规范的父级拥有的记录相关联的测试验证

python - 如何使用QPainterPath?

python - 如何在 PyQt 中向现有 API 添加重载

python - 如何在 PyQt5 的选项卡小部件中添加堆叠布局?

python - 何时以及为何 socket.send() 在 python 中返回 0?