I've been working on some debugging/testing infrastructure for my PyQt-based project. I'm tagging most widgets with special debugging attributes, even if the widgets were created on the C++ side.
However, multiple accesses to the same button in a QFileDialog
seem to result in new sip wrapper instances. That is, if I access the 'Cancel' button more than once, PyQt doesn't return the same Python object each time.
Here's a minimal test program you can use to reproduce the issue:
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)
I would expect this to program to output something like this:
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
...but instead, here's what I actually see. Note that the cancelButton
object has a different address each time, and the debugging attribute I added is lost:
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
So it seems like PyQt is "losing" the Python object it created previously, and is then making a "new" one for each repeated access. Is that expected?
BTW, this test program behaves the same on both Mac OS X (10.7) and Linux (Ubuntu 12). I'm using PyQt 4.8.5.