Классы обезьян Patching PySide

голоса
0

У меня уже есть графический интерфейс приложения , написанные на 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«s экземпляр может.

Вот еще одна интересная вещь, которую я заметил:

>>> 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.

Задан 07/11/2018 в 19:58
источник пользователем
На других языках...                            

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more