从 C++ (Qt5) 向 QML 项目发送信号
我有一个包含以下内容的 QML 文件:
I have a QML file containing this:
Text {
id: testData
onTaskClicked:{
testData.text = task.name
}
}
关键是这个 taskClicked 信号.它由另一个小部件 (C++) 发出,需要中继到 QML.
The catch is this taskClicked signal. It is emitted by another widget (C++) and needs to be relayed to QML.
这类似于 这个 SO 问题,除了那里发布的解决方案不起作用(为什么写在下面).
This is similar to this SO question, except that the solution posted there doesn't work (why is written below).
C++ 代码:
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
是一个 QListView
子类,它发出 taskClicked(HolidayTask* task)
信号(来自 .h 文件):
m_view
is a QListView
subclass that emits the taskClicked(HolidayTask* task)
signal (from the .h file):
Q_SIGNALS:
void taskClicked(HolidayTask* task);
color
和 m_model
在 QML 中注册并在其他地方使用.信号中的对象已经在 QML 中注册.view
是我的 QQuickView
.
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);
但是,myElement
始终为空(并且我收到关于不存在插槽的运行时警告).
However, myElement
is always null (and I get a runtime warning about a non existent slot).
如果我尝试将视图(QListView)指针设置为 QML 视图的上下文属性,它仍然不起作用.
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?
编辑以澄清一些细节:HolidayTask
是一个自定义 QObject 子类,信号 taskClicked
是在 C++ 中定义的(在 QListView
子类中)
EDIT to clarify some details: HolidayTask
is a custom QObject subclass, and the signal taskClicked
is defined in C++ (in a QListView
subclass)
我们正在接近,但没有雪茄:
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)));
和
Text {
id: testData
objectName: "testData"
signal taskClicked(HolidayTask task)
onTaskClicked: {
testData.text = task.name
console.log("CLICk!")
}
}
产量
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')
更多细节:HolidayTask,我的自定义 QObject 子类,在代码中注册为
More details: HolidayTask, my custom QObject subclass, is registered in the code as
qmlRegisterType<HolidayTask>("HolidayPlanner", 1, 0, "HolidayTask");
带有数据的最小 QML:
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")
}
}
}
最终的工作代码是(请参阅有关原因的答案)
The final, working code is (see answers on why)
connect(m_view, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)),
myElement, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)));
这仅通过使用具有完整命名空间的对象起作用.否则 QML 中的签名将不匹配.
This worked only through the use of objects with full namespaces. Otherwise the signature will not match in QML.
推荐答案
但是,
myElement
始终为空(并且我收到关于一个不存在的插槽).
However,
myElement
is always null (and I get a runtime warning about a non existent slot).
您正在尝试根据 id 查找子项,而它是基于 objectName 属性的.您需要将 objectName 属性设置为实际找到它所需的值.
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.
此外,您似乎没有在 QML 文本项中声明信号.我不确定它是自定义 C++ 项还是内置项.不幸的是,您没有共享足够的代码来理解这一点.无论哪种方式,根据文档声明您的信号一个>.
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.
因此,试试这段代码:
Text {
id: testData
objectName: "testData"
// ^^^^^^^^^^^^^^^^^^^
signal taskClicked (HolidayTask task)
// ^^^^^^^^^^^^^^^^^^^
onTaskClicked:{
testData.text = task.name
}
}
一旦完成,您就差不多准备好了.您需要确保将您的 HolidayTask 注册到 QML,并且您还需要更改 main.cpp 中的连接语法,如下所示:
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)));
简而言之,您需要以这种方式触发 QML 信号处理程序,而不是通过 SLOT
.
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.
相关文章