从QML获取信号到Qt中的C ++类

Get signal from qml into c++ class in Qt

我试图弄清楚如何从QML代码中获取信号并将其连接到C ++类中的插槽。

我从此答案和屏幕上显示的控件中获取代码,但无法获取信号。

以下是相关代码:

test.qml:

1
2
3
4
5
6
7
8
9
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1

Switch{
    id: swt;
    checked:true;
    onCheckedChanged: swt.qmlSignal();
}

menu.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Menu::Menu(QWidget *parent) :
QWidget(parent),
        ui(new Ui::Menu)
{
    ui->setupUi(this);
    QQuickView *view = new QQuickView();
    QWidget *container = QWidget::createWindowContainer(view, this);

    container->setMaximumSize(50, 20);

    QObject::connect(container, SIGNAL(qmlSignal()),
                     this, SLOT(receiveFromQml()));

    view->setSource(QUrl("qrc:/test.qml"));
    ui->verticalLayout->addWidget(container);



}
void Menu::receiveFromQml()
{
    qDebug() <<"Called the C++ slot with message:" ;
}

我在这里查看了示例,但无法使其正常工作。

这是我得到的错误:

qrc:/test.qml:10: TypeError: Property 'qmlSignal' of object Switch_QMLTYPE_4(0x291ac70) is not a function


简单,将其标记为插槽

似乎您有一个C ++对象,您需要调用一个插槽,因此将该函数标记为slot,然后它将自动公开。在C ++中,不需要怪异的connect()。

1
2
3
4
5
6
// Seems Switch is a QML Item
Switch{
 id: swt;
 checked:true;
 onCheckedChanged: myCppObj.slot(); // calls the object's slot
}

还有其他方法可以执行此操作,但这似乎可以解决您的问题。如果没有,请详细说明,我们将对其进行完善。


您无法在qml中创建其他信号,但可以使用对象的标准属性。

1
2
3
4
5
6
7
8
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1

Switch{
    id: swt;
    checked:true;
}

C ++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class MyHandler : public QObject
{
    Q_OBJECT
    public:
        MyHandler( const QObject& object, const QQmlProperty& qmlProperty );
    private slots:
        void handleNotify();
    private:
        const QQmlProperty& m_qmlProperty;
};

MyHandler::MyHandler( const QObject& object, const QQmlProperty& qmlProperty ) :
    QObject(),
    m_qmlProperty( qmlProperty )
{
    static const QMetaMethod metaSlot = this->metaObject()->method( this->metaObject()->indexOfSlot("handleNotify" ) );
    if( metaSlot.isValid() )
    {
        const QMetaMethod metaQmlPropSignal = qmlProperty.property().notifySignal();
        if( metaQmlPropSignal.isValid() )
            QObject::connect( &object, metaQmlPropSignal, this, metaSlot );
    }
}

MyHandler::handleNotify()
{
    if( m_qmlProperty.isValid() )
    {
        const int qmlPropertyValue = m_qmlProperty.read().value<bool>();
        ...
    }
}

使用:

1
2
3
4
QQuickView* view = ...;
QObject* quickItem = view->rootObject();
const QQmlProperty* qmlProperty = new QQmlProperty( quickItem,"checked" );
MyHandler* myHandler = new MyHandler( *quickItem, *qmlProperty );

因此,当属性checked更改时(如果对象quickItem存在),将调用方法MyHandler::handleNotify

附言您还可以将qml属性与信号连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class QmlPropertyWrapper : public QObject
{
    Q_OBJECT
    public:
        QmlPropertyWrapper( const QObject& object, const QQmlProperty& qmlProperty );
    signals:
        void triggered();
};

QmlPropertyWrapper::QmlPropertyWrapper( const QObject& object, const QQmlProperty& qmlProperty ) :
    QObject()
{
    static const QMetaMethod metaSignal = QMetaMethod::fromSignal( &QmlPropertyWrapper::triggered );
    if( metaSignal.isValid() )
    {
        const QMetaMethod metaQmlPropSignal = qmlProperty.property().notifySignal();
        if( metaQmlPropSignal.isValid() )
            QObject::connect( &object, metaQmlPropSignal, this, metaSignal );
    }
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
QQuickView* view = ...;
QObject* quickItem = view->rootObject();
const QQmlProperty* qmlProperty = new QQmlProperty( quickItem,"checked" );
QmlPropertyWrapper* qmlPropertyWrapper = new QmlPropertyWrapper( *quickItem, *qmlProperty );
QObject::connect( qmlPropertyWrapper, &QmlPropertyWrapper::triggered, [ qmlProperty ]()
{
    if( m_qmlProperty->isValid() )
    {
        const int qmlPropertyValue = m_qmlProperty->read().value<bool>();
        ...
    }
} );

我希望您的示例足够了,并且切换项也是根源。通常可以这样解决:

1
2
3
4
5
6
7
8
9
10
Switch {
    id: swt

    signal gmlSignal

    checked:true;
    onCheckedChanged: {
        qmlSignal();
    }
}

有关详细信息的Qt文章。同样,您可以在需要时使用限定符swt,以便在该文件中的其他上下文中使用swt.qmlSignal()

另外,C ++部分也需要修复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Menu::Menu(QWidget *parent) :
QWidget(parent),
ui(new Ui::Menu)
{
   ui->setupUi(this);
   QQuickView *view = new QQuickView();
   QWidget *container = QWidget::createWindowContainer(view, this);

   container->setMaximumSize(50, 20);

   view->setSource(QUrl("qrc:/test.qml"));
   ui->verticalLayout->addWidget(container);

   QObject::connect((QObject*)view->rootObject(), SIGNAL(qmlSignal()),
                     this, SLOT(receiveFromQml()));
}

我通过查看发出类似信号的自己的代码进行了更改,但实际上并没有尝试,但是您需要连接到从QML viewrootObject暴露的信号,而不是其窗口小部件容器。