2014-01-19 6 views
2

Я работал над некоторой инфраструктурой отладки/тестирования для моего проекта на основе PyQt. Я отмечаю большинство виджетов со специальными атрибутами отладки, даже если виджеты были созданы на стороне C++.pyqt: Как получить последовательный доступ к кнопкам в QFileDialog

Однако множественные обращения к одной и той же кнопке в QFileDialog, похоже, приводят к новым экземплярам обертки. То есть, если я получаю доступ к кнопке «Отмена» более одного раза, 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 является «потери» Питон объект он создал ранее, а затем делает " новый "по одному для каждого повторного доступа. Это ожидалось?

BTW, эта тестовая программа ведет себя одинаково как на Mac OS X (10.7), так и на Linux (Ubuntu 12). Я использую PyQt 4.8.5.

ответ

2

Кнопка, с которой вы пытаетесь ссылаться, является внутренним объектом Qt, который не имеет соответствующего эквивалента питона. Поэтому, естественно, 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() 

Очевидно, что этот метод будет работать только для классов Qt, которые наследуют QObject.

+0

Мне было интересно, если обертки собирали мусор, поэтому я попробовал 'gc.disable()'. Но, подумав немного больше, очевидно, что это не повлияет. Сборщик мусора здесь не играет, поскольку счетчик ссылок падает до нуля. Спасибо за указание на это! –

+0

И спасибо за отзыв о свойствах. Это определенно правильный способ исправить мою проблему. –

+0

«Очевидно, что этот метод будет работать только для классов Qt, которые наследуют« QObject ». Из любопытства существуют ли классы Qt, которые * не * наследуют от 'QObject'? Или вы просто указываете, что это не будет работать для простых классов Python? –

Смежные вопросы