У меня уже есть приложение с графическим интерфейсом, написанное на QT с использованием PySide. Я хочу написать тесты для этого без изменения реализации, когда это возможно. Для этого я собираюсь исправить некоторые методы, в основном, чтобы зарегистрировать ссылки на некоторые объекты QT, которые создаются в приложении. Во время этого я наткнулся на странное поведение класса QMenu
, который оказался устойчивым к обезьяньим пятнам.
Вот простой код, который продемонстрирует это:
from PySide.QtGui import QApplication, QMainWindow, QMenu, QDialog
class Window(QDialog):
def __index__(self, main_window):
self.setWindowTitle('Dialog')
def contextMenuEvent(self, event):
menu = self.prepare_menu()
menu.exec_(event.globalPos())
def prepare_menu(self):
menu = QMenu(self)
close_action = menu.addAction('Close')
close_action.triggered.connect(self.close)
return menu
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = QMainWindow()
main_window.show()
Window().exec_()
app.exec_()
Это очень простое приложение, которое отображает только два окна. У одного из них есть контекстное меню, которое позволяет закрыть окно.
Чтобы показать правильное поведение, я обезьяна исправлю QDialog.exec_
, добавив следующую строку:
QDialog.exec_ = lambda x: print('QDialog.exec_()')
Когда я выполню код с этой строкой, второе окно не появится, и вместо него будет напечатано QDialog.exec_()
.
Теперь, когда я доказал, что это работает, я изменил строку примерно так:
QMenu.exec_ = lambda x: print('QMenu.exec_()')
Но, что удивительно, это не влияет на поведение класса QMenu. Он работает точно так же, как и раньше.
Однако вот еще один фрагмент кода, который работает как ожидалось:
old_prepare_menu = Window.prepare_menu
def new_prepare_menu(self):
menu = old_prepare_menu(self)
menu.exec_ = lambda x: print('menu.exec_()')
return menu
Window.prepare_menu = new_prepare_menu
При запуске программы теперь не будет отображаться контекстное меню после щелчка правой кнопкой мыши, а вместо этого будет напечатано menu.exec_()
.
Так что в основном - класс QDialog
может быть исправлен, класс QMenu
не может, но снова экземпляр QMenu
может.
Вот еще одна интересная вещь, которую я заметил:
>>> from PySide.QtGui import QMenu, QDialog
>>> QDialog.exec_
<method 'exec_' of 'PySide.QtGui.QDialog' objects>
>>> QMenu.exec_
<built-in method exec_ of Shiboken.ObjectType object at 0x5694F380>
Я не понимаю, почему он так себя ведет. Класс exec_()
класса QMenu
отличается от типа QDialog
, но я не понимаю, почему он влияет на исправление обезьян.
Любые подсказки, почему он так себя ведет? Есть ли возможность изменить это?
Протестировано на PySide-1.2.4 с Python 3.6 для Windows и CentOS.