【问题标题】:Pyside2 QQmlPropertyMap's slot not accessible from QML; Python version of old C++ bug?Pyside2 QQmlPropertyMap 的插槽无法从 QML 访问; Python 版本的旧 C++ 错误?
【发布时间】:2020-06-29 18:57:42
【问题描述】:

我遇到了一个看起来很像现代 Python 版本的错误,该错误是多年前在 (C++) Qt 中修复的:Can't call slot or Q_INVOKABLE from QML in subclass of QQmlPropertyMap

我在我的系统上测试了问题中的示例(Qt 5.15.0,根据需要修改语法)并验证它确实已修复;对象的槽被正确访问,无论是继承自 QObject 还是 QQmlPropertyMap。

但是,仍然使用 Qt 5.15.0,从 PySide2 工作似乎复制了同样的问题:

main.py:

from PySide2.QtCore import QObject, Property, Slot
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine, QQmlPropertyMap

class MyObj(QObject):
    @Property(str)
    def field(self):
        return 'Field from QObject'
    
    @Slot()
    def test_func(self):
        print('QObject signal worked')

class MyMap(QQmlPropertyMap):
    def __init__(self):
        super().__init__()
        self.insert('field', 'Field from QQmlPropertyMap')
    
    @Slot()
    def test_func(self):
        print('QQmlPropertyMap signal worked')

app = QGuiApplication()
engine = QQmlApplicationEngine()

qobj = MyObj()
engine.rootContext().setContextProperty('qobj', qobj)

qmap = MyMap()
engine.rootContext().setContextProperty('qmap', qmap)

engine.load('main.qml')
app.exec_()

main.qml:

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    visible: true
    width: 200
    height: 200

    Text {
        text: qobj.field + '\n' + qmap.field
        anchors.centerIn: parent
    }
    
    MouseArea {
        anchors.fill: parent
        onClicked: {
            qobj.test_func();
            qmap.test_func();
        }
    }
}

这两个字段都在生成的窗口中正确显示,但单击它会产生此控制台输出:

QObject slot worked
file:///Users/charles/Projects/qt/map-signal-test/main.qml:20: TypeError: Property 'test_func' of object QQmlPropertyMap(0x7fb954f5f460) is not a function

我不太了解 PySide2 是如何实现的。这是同一个错误,未修复还是重新出现?或者是别的什么?无论哪种情况,是否有解决方法?

编辑: 回应 eyllanesc 在下面的回答。虽然您发布的代码重现了 C++ 中的错误,但这个略有不同的类定义(源自上面链接的旧问题)可以正常工作:

class MyMap: public QQmlPropertyMap {
    Q_OBJECT
public:
    MyMap(QObject* parent = 0): QQmlPropertyMap(this, parent) {}
public slots:
    Q_INVOKABLE void test_func() {
        qDebug() << "QQmlPropertyMap signal worked";
    }
};

我对 C++ 了解不够,无法理解其中的含义。

【问题讨论】:

    标签: python qt qml pyside2


    【解决方案1】:

    不幸的是,这是一个 Qt 错误,请检查 QTBUG-29836 中的 cmets。我已经使用 Qt 5.15 使用以下 MRE 对其进行了验证:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QQmlPropertyMap>
    
    class MyMap: public QQmlPropertyMap{
        Q_OBJECT
    public:
        using QQmlPropertyMap::QQmlPropertyMap;
        Q_INVOKABLE void test_func(){
            qDebug() << "QQmlPropertyMap signal worked";
        }
    };
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        MyMap qmap;
        engine.rootContext()->setContextProperty("qmap", &qmap);
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    
    #include "main.moc"
    
    import QtQuick 2.15
    import QtQuick.Window 2.15
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
        MouseArea {
            anchors.fill: parent
            onClicked: {
                qmap.test_func()
            }
        }
    }
    

    更新:

    似乎该错误的解决方法是使用使用派生类的QMetaObject的protected constructor,与仅访问QQmlProperty的QMetaObject的default constructor不同,因此像Q_SLOTS,Q_INVOKABLES等元素新类的映射。不幸的是,无法从 Python 访问该构造函数。

    【讨论】:

    • @CrazyChucky 你确定吗?我已经在 QtCreator 中使用 Qt 5.15 执行了它,并在“应用程序输出”的控制台中得到:qrc:/main.qml:12: TypeError: Property 'test_func' of object QQmlPropertyMap(0x7fffc6dc5a40) is not a function
    • 看来我从旧问题中复制和修剪得到的结果略有不同。它有效,而您的无效。我对 C++ 了解不足,无法理解这些差异。我应该将其编辑到我的问题中吗?
    • @CrazyChucky 添加适合您的代码在您帖子的末尾
    • 好的,已发布。 (不确定您是否会收到默认通知。)
    • P.S.我为 PySide 提交了一个错误报告,以防可以修复它以使用正确的构造函数:bugreports.qt.io/browse/PYSIDE-1341
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    相关资源
    最近更新 更多