如何将QML信号连接到C++槽?

9

我在QML中遇到了关于MessageDialog信号的问题。在我的MessageDialog中,我有两个按钮分别用于选择。我想将每个按钮与一个信号连接起来。

这是我的qml文件:

import QtQuick 2.2
import QtQuick.Dialogs 1.1

Item{
    MessageDialog {
        signal qmlYesSig(string msg)
        signal qmlNoSig (string msg)
        title: "Send data?"
        icon: StandardIcon.Question
        text: "Do you want to save your data on the online platform?"
        detailedText: "Click Yes "
        standardButtons: StandardButton.Yes | StandardButton.No
        Component.onCompleted: visible = true
        onYes: qmlYesSig("From yes")
        onNo: qmlNoSig("From no")
    }
}

这是我的插槽:

class MyClass : public QObject
{
    Q_OBJECT
public slots:
    void cppSlot(const QString &msg) {
        qDebug() << "Called the C++ slot with message:" << msg;
    }
};

这是我在主函数中如何使用它:

QQuickView view(QUrl::fromLocalFile("window.qml"));
QObject *item = view.rootObject();
AddData myClass;
QObject::connect(item, SIGNAL(qmlSignal(QString)),
                 &myClass, SLOT(cppSlot(QString)));

view.show();

我遇到了以下错误:

C2665: 'QObject::connect': 没有一种重载能够将所有参数类型转换

我已经尝试了多次,但无法使QML信号和C++槽函数正常工作。 同时,我也尝试了Qt文档中的示例,但仍然出现相同的错误。

是否有人可以给我一个思路,如何连接QML信号和C++槽函数以实现MessageDialog


你在哪里定义了 qmlSignal 信号?不是在 QObject *item = view.rootObject(); 中。 - xander
这是我第一次使用来自qml的信号。我不太明白还需要做什么。当按钮被按下时,它会发出一个信号,应该在C++中捕获,对吗? - Adrian
仍然可以调试您的 view.rootObject() 并查看信号定义不在您的 MessageDialog 中。所以要么在根 Item 中定义它,要么在 C++ 中获取 MessageDialog 子对象以连接信号。 - xander
1
qmlSignal 应该改为 qmlYesSig 吗? - stefaanv
好的,我会尝试修复这个问题。但是从你的角度来看,QML 是正确的吗? - Adrian
显示剩余7条评论
2个回答

8

您可以将 C++ QObject 提供给 QML 引擎并从 QML 端连接到 C++ QObject 的槽函数:

在 C++ 文件中:

view.rootContext()->setContextProperty("object", this); // replace this with appropriate object

在 Qml 中:

qmlYesSig.connect(object.cppSlot);

3
希望提供更详细的示例,例如在QML中应该放置连接代码?如何设置连接类型为排队连接? - Curtwagner1984
1
不知道如何将您的答案转化为可行的示例。您能否发布一个完整的工作示例? - TSG
这需要在一个函数内完成,请参见此处 - isudfv

8

您的QML文件是:

Item{
    MessageDialog {
        signal qmlYesSig(string msg)
        signal qmlNoSig (string msg)

        [...]
    }
}

你的C++代码如下:

QObject *item = view.rootObject();
AddData myClass;
QObject::connect(item, SIGNAL(qmlSignal(QString)),
                 &myClass, SLOT(cppSlot(QString)));

这意味着您正在查找名为“qmlSignal”的信号,并在您的QML文件的根项中寻找它。这个根项就是:
Item{}

正如您所看到的,没有名为“qmlSignal”的信号。

您需要在根项目中定义信号,并从消息框发出它。

Item{
    signal qmlSignal(string msg)

    MessageDialog {
        onYes: parent.qmlSignal("From yes")
        onNo: parent.qmlSignal("From no")
    }
}

谢谢dydil。这个可以工作,但是当我使用“QObject item = view.rootObject();”时,出现了一些错误。它说:“无法将'QQuickItem'转换为'QObject*'”。你有任何想法为什么会这样吗? - Adrian
1
@Adi QQuickItem是一个QObject,所以问题可能是您忘记了#include <QQuickItem> - dydil
是的,那就是 :) 謝謝。 - Adrian
将rootObject连接到信号。当Item为PushButton且您有2个或更多按钮时怎么办?或者您不仅有按钮,还有许多其他具有信号的项。您是否想通过按钮类型命名每个信号?确定按钮具有okSignal,取消按钮具有cancelSignal等等... 不!那不是正确的方法。 - peter70
1
parent.qmlSignal 中使用 parent 似乎对我无效:我得到了 TypeError: Property 'qmlSignal' of object QQuickRootItem(0x83e620) is not a function。解决方法是为顶层项分配一个 id,并使用它代替 parent - Joseph Quinsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接