我一直在为基于 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/