I have a QML file containing this:
Text {
id: testData
onTaskClicked:{
testData.text = task.name
}
}
The catch is this taskClicked signal. It is emitted by another widget (C++) and needs to be relayed to QML.
This is similar to this SO question, except that the solution posted there doesn't work (why is written below).
The C++ code:
ctxt->setContextProperty(QLatin1Literal("holiday"), m_model);
ctxt->setContextProperty(QLatin1Literal("bgcolor"), color);
view->setResizeMode(QQuickView::SizeRootObjectToView);
auto mainPath = QStandardPaths::locate(QStandardPaths::DataLocation,
QLatin1Literal("taskview.qml"));
view->setSource(QUrl::fromLocalFile(mainPath));
ctxt->setContextProperty(QLatin1Literal("viewer"), m_view);
m_view
is a QListView
subclass that emits the taskClicked(HolidayTask* task)
signal (from the .h file):
Q_SIGNALS:
void taskClicked(HolidayTask* task);
color
and m_model
are registered in QML and are used elsewhere. The object from the signal is already registered in QML. view
is my QQuickView
.
First I tried the solution presented in the question above:
auto root = view->rootObject();
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData");
connect(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement,
SLOT(taskClicked(HolidayTask* task);
However, myElement
is always null (and I get a runtime warning about a non existent slot).
If I try to set the view (the QListView) pointer as a context property of the QML view, it still doesn't work.
In all cases, I get also:
QML Connections: Cannot assign to non-existent property "onTaskClicked"
What could I possibly be doing wrong here?
EDIT to clarify some details: HolidayTask
is a custom QObject subclass, and the signal taskClicked
is defined in C++ (in a QListView
subclass)
EDIT2: We're getting close, but no cigar:
auto root = quickView->rootObject();
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData"));
connect(m_view, SIGNAL(taskClicked(HolidayTask*)),
myElement, SIGNAL(taskClicked(HolidayTask* task)));
and
Text {
id: testData
objectName: "testData"
signal taskClicked(HolidayTask task)
onTaskClicked: {
testData.text = task.name
console.log("CLICk!")
}
}
yields
QObject::connect: No such signal QQuickText_QML_0::taskClicked(HolidayTask* task) in /home/lb/Coding/cpp/holiday-planner/src/mainwindow.cpp:178
QObject::connect: (receiver name: 'testData')
More details: HolidayTask, my custom QObject subclass, is registered in the code as
qmlRegisterType<HolidayTask>("HolidayPlanner", 1, 0, "HolidayTask");
Minimal QML with the data:
import QtQuick 2.0
import QtQml 2.2
import HolidayPlanner 1.0
Rectangle {
id: container
objectName: "container"
color: bgcolor
Text {
id: testData
objectName: "testData"
signal taskClicked(HolidayTask task)
onTaskClicked: {
testData.text = task.name
console.log("CLICK")
}
}
}
EDIT3: The final, working code is (see answers on why)
connect(m_view, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)),
myElement, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)));
This worked only through the use of objects with full namespaces. Otherwise the signature will not match in QML.
A signal is automatically emitted when the value of a QML property changes. This type of signal is a property change signal and signal handlers for these signals are written in the form on<Property>Changed, where <Property> is the name of the property, with the first letter capitalized.
All QML signals are automatically available to C++, and can be connected to using QObject::connect() like any ordinary Qt C++ signal. In return, any C++ signal can be received by a QML object using signal handlers.
To call the QML classes in C++, you need to set the objectName property. Like that: QQmlApplicationEngine engine; QQmlComponent component(&engine, QUrl(QLatin1String("qrc:/main. qml"))); QObject *mainPage = component.
However,
myElement
is always null (and I get a runtime warning about a non existent slot).
You are trying to find the child based on id, whereas it is based on the objectName property. You would need to set the objectName property to the desired to actually find it.
Also, you do not seem to declare the signal in your QML Text item. I am not sure if it is a custom C++ item or a built-in one. You have not shared enough code unfortunately to understand that bit. Either way, declare your signal as per documentation.
Therefore, try this code out:
Text {
id: testData
objectName: "testData"
// ^^^^^^^^^^^^^^^^^^^
signal taskClicked (HolidayTask task)
// ^^^^^^^^^^^^^^^^^^^
onTaskClicked:{
testData.text = task.name
}
}
Once that is done, you are almost ready. You need to have your HolidayTask registered to QML for sure, and you also need to change the connect syntax in your main.cpp as follows:
connect(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement, SIGNAL(taskClicked(HolidayTask* task)));
In short, you need to trigger your QML signal handler this way, and not via SLOT
.
Also, note that your connect syntax is broken as it is missing the closing brackets at the end. That needs to be fixed.
I would even consider removing the pointer assignment and use value or reference based passing for this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With