问题
I try to figure out how to get signal from QML code and connect it to slot located in C++ class.
I take code from this answer and the control shown on the screen but I can't get the signal.
Here is the relevant code:
test.qml:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
Switch{
id: swt;
checked:true;
onCheckedChanged: swt.qmlSignal();
}
menu.cpp:
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:" ;
}
I've looked at the examples here but I can't make it to work.
This is the error I get :
qrc:/test.qml:10: TypeError: Property 'qmlSignal' of object Switch_QMLTYPE_4(0x291ac70) is not a function
回答1:
Simple, mark it as slot
Seems you have a C++ Object and you need to call a slot, so mark the function as a slot
, then it is exposed automatically. No need for weird connect() in C++.
// Seems Switch is a QML Item
Switch{
id: swt;
checked:true;
onCheckedChanged: myCppObj.slot(); // calls the object's slot
}
There are other ways to do it, but it seems this covers your case. If not, please elaborate and we'll refine it.
回答2:
I hope that your example is sufficient and that switch item is the root one as well. This is usually solved like:
Switch {
id: swt
signal gmlSignal
checked:true;
onCheckedChanged: {
qmlSignal();
}
}
The Qt article with details. Also you can have qualifier swt
when needed so swt.qmlSignal()
from the other context within that file.
Also, C++ part needs to be fixed as well:
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()));
}
I did changes by looking at own code that emits similar signal and did not actually try but you need to connect to signal exposed from the rootObject
of QML view
and not widget container of it.
回答3:
You can not create an additional signal in qml, but use the standard properties of objects.
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
Switch{
id: swt;
checked:true;
}
C++:
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>();
...
}
}
using:
QQuickView* view = ...;
QObject* quickItem = view->rootObject();
const QQmlProperty* qmlProperty = new QQmlProperty( quickItem, "checked" );
MyHandler* myHandler = new MyHandler( *quickItem, *qmlProperty );
Thus, the method MyHandler::handleNotify
will be called when the property checked
changes (if it exists for the object quickItem
).
P.S. You can also connect a qml property with a signal.
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 );
}
}
using
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>();
...
}
} );
来源:https://stackoverflow.com/questions/31728098/get-signal-from-qml-into-c-class-in-qt