Как использовать @pyqtSlot decorator с другими декораторами в QML?

1

РЕШЕННО: см. Мой ответ ниже. Я не могу принять в течение 2 дней.

У меня есть объект Python, полученный из QObject, методы которого я вызываю из QML. Эти методы, конечно, украшены @pyqtSlot. Однако есть проблема, когда я стараюсь сочетаться с моими собственными декораторами, например:

@pyqtSlot()
@decorator
def call(self):
    print('Called!')

Я получаю file:X.qml:99: TypeError: Property 'call' of object X(0x7fed4c07fa50) is not a function ошибки file:X.qml:99: TypeError: Property 'call' of object X(0x7fed4c07fa50) is not a function

Это декоратор, который я использую:

def decorator(f):
    def wrapped(self):
        print('get decorated')
        return f(self)
    return wrapped

Может ли кто-нибудь объяснить, почему это не работает? Некоторое поведение PyQt? Или я делаю что-то неправильно?

ПРИМЕЧАНИЕ. Он будет работать, если декоратор просто возвращает f, проблемы возникают, когда декоратор возвращает вложенную функцию, такую как wrapped.

  • 1
    Измените return f () чтобы return f (self)
  • 0
    Извините, это была опечатка. Я получаю те же результаты с return f(self)
Показать ещё 1 комментарий
Теги:
pyqt5
pyqt
qml

3 ответа

1

Использование библиотеки декораторов не создает проблем, в следующей части приведен пример:

main.py

import sys
from PyQt5 import QtCore, QtGui, QtQml
import decorator


@decorator.decorator
def foo_decorator(f, *args, **kwargs):
    print('get decorated')
    return f(*args, **kwargs)


class Helper(QtCore.QObject):    
    @foo_decorator
    @QtCore.pyqtSlot()
    def call(self):
        print('Called!')


if __name__ == "__main__":

    app = QtGui.QGuiApplication(sys.argv)
    obj = Helper()
    engine = QtQml.QQmlApplicationEngine()
    engine.rootContext().setContextProperty("obj", obj)
    engine.load(QtCore.QUrl.fromLocalFile('main.qml'))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_()) 

main.qml

import QtQuick 2.11
import QtQuick.Controls 2.4

ApplicationWindow {
    title: "Hello World"
    width: 640
    height: 480
    visible: true

    Component.onCompleted: obj.call()
}

Выход:

get decorated
Called!
  • 0
    Да! Это работает ... но почему? Я бы предпочел не использовать внешнюю библиотеку для основных языковых функций.
  • 0
    @ user985779 Эта библиотека очень легкая, если вы не хотите использовать ее в качестве зависимости, просто загрузите следующий файл: raw.githubusercontent.com/micheles/decorator/master/src/…
0

Хорошо, с помощью @eyllanesc ответ я смог дойти до корня проблемы: это то, что декоратор, который я использовал, не сохранял подпись функции моего слота.

Простое изменение моего декоратора на это устраняет проблему:

def decorator(f):
    def call(self):
        print('get decorated')
        return f(self)
    return wrapped

Однако этот декоратор не очень многократно используется из-за имени функции жесткой кодировки. "Правильный" (только с использованием стандартных библиотек) способ исправить это с помощью декоратора wraps из functools:

from functools import wraps
def decorator(f):
    @wraps(f)
    def any_name_you_want(self):
        print('get decorated')
        return f(self)
    return any_name_you_want
0

Попытайся:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui     import *
from PyQt5.QtCore    import *

def decorator(f):
    def wrapped(self):
        print('get decorated')
        return f(self)
    return wrapped

class App(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyQt5 button")
        self.setGeometry(500, 100, 320, 200)
        button = QPushButton('  \n   PyQt5\n   button\n  ', self)
        button.setIcon(QIcon("E:/_Qt/img/qt-logo.png"))
        button.setIconSize(QSize(34, 34))
        button.setToolTip('This is an example button')
        button.setFlat(True) 
        button.move(120,70) 
        button.clicked.connect(self.on_click)

    @pyqtSlot()
    @decorator
    def on_click(self):
        print('PyQt5 button click')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    ex.show()
    sys.exit(app.exec_())

Изображение 174551

  • 0
    Python не создает эту проблему, но из QML.
  • 0
    Мой случай другой. Я использую QQmlApplicationEngine и вызываю Python @pyqtSlot напрямую из QML.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню