C++信号到 Qt 中的 QML 槽

发布于 2024-12-26 10:15:03 字数 701 浏览 5 评论 0原文

我想将信号从 C++ 发送到 QML 文件中的槽。 我已经让它在没有原始类型参数的情况下工作,尽管如果我想将 QString 发送到我的 QML 插槽,我在连接时会收到错误。

我在 main.cpp 中连接

QObject *contentView = rootObject->findChild<QObject*>(QString("contentView"));
QObject::connect(&myObj,      SIGNAL(finishedGatheringDataForItem(QString)), 
                 contentView, SLOT(updateViewWithItem(QString)));

qml 文件的相关部分

Rectangle {
        objectName: "contentView"
        function updateViewWithItem(string) { console.log('got some Items'); }  // slot
}

错误:

Object::connect: No such slot QDeclarativeRectangle_QML_2::updateViewWithItem(QString)

I want to send a Signal from C++ to a Slot in my QML File.
I already got it working without and primitive type parameters, although if I want to send a QString to my QML Slot I get an error whilst connecting.

I connect in main.cpp

QObject *contentView = rootObject->findChild<QObject*>(QString("contentView"));
QObject::connect(&myObj,      SIGNAL(finishedGatheringDataForItem(QString)), 
                 contentView, SLOT(updateViewWithItem(QString)));

the relavant part of my qml File

Rectangle {
        objectName: "contentView"
        function updateViewWithItem(string) { console.log('got some Items'); }  // slot
}

Error:

Object::connect: No such slot QDeclarativeRectangle_QML_2::updateViewWithItem(QString)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

此刻的回忆 2025-01-02 10:15:03

您应该在此使用 连接情况(也许这是唯一的连接方式)。

  1. 通过setContextProperty将对象myObj放入QML文件

    qmlVectorForm->rootContext()->setContextProperty("YourObject", myOb);
    
  2. 您的信号是

    finishedGatheringDataForItem(QString signalString)
    
  3. 在 QML 文件中,添加如下所示的 Connectios:

    连接 {
        目标:你的对象 
        onFinishedGatheringDataForItem: {
            qmlString = 信号字符串
        }
    }
    

You should use Connections in this case (maybe it's the only way to connect).

  1. Put your object myObj to QML file by setContextProperty

    qmlVectorForm->rootContext()->setContextProperty("YourObject", myOb);
    
  2. Your signal is

    finishedGatheringDataForItem(QString signalString)
    
  3. In QML file, add Connectios likes below:

    Connections {
        target: YourObject 
        onFinishedGatheringDataForItem: {
            qmlString = signalString
        }
    }
    
风轻花落早 2025-01-02 10:15:03

我认为最好检查本教程:

http://doc.qt.io /qt-4.8/qtbinding.html

特别是本节:

http://doc.qt.io/qt-4.8/qtbinding.html#receiving-signals

我认为您在这种情况下的错误可能是您没有将其声明为插槽或者您没有使其可调用。 Qt 教程中对这两个选项进行了解释。

此外,您需要使用 QVariant 以便在 C++ 和 QML 之间交换数据。
您还可以注册类型,例如小部件等,以便您可以在 QML 中将它们用作“本机”类型(如矩形)。在大多数情况下,不建议这样做,除非您需要某些特定的外部类或某些无法在 QML 界面中显示的数据。

QVariant 的原因是 QML 基于脚本的方法。 QVariant 基本上包含您的数据和数据类型的描述,以便 QML 知道如何正确处理它。这就是为什么你必须在QML中用String、int等指定参数。但是与C++的原始数据交换仍然是QVariant

我之前使用过qmlRegisterType,但对于简单数据类型来说这是一个非常不方便的解决方案。它更适用于更复杂的数据,例如 QML 本身不支持或扩展的自定义小部件、画布或视频元素 QStandardItemModels 。这是一种在 QML 和 C++ 之间交换数据的更方便的方法,并且首先不需要信号或槽,因为 QStandardItemModel 会自动更新 GUI。要使用 QStandardItemModel,您需要使用 qmlRegisterType.. 注册类型。然后,该模型可以在基于模型的视图(例如 ListView 等)中使用。

我附加了该主题的教程,它描述了如何使用 QListModel。

http://doc.qt.io/qt-4.8/qdeclarativemodels.html

I think it would be best if you check this tutorial:

http://doc.qt.io/qt-4.8/qtbinding.html

especially this section:

http://doc.qt.io/qt-4.8/qtbinding.html#receiving-signals

I think your mistake in this case might either be that you didn't declare it as a slot or you didn't make it invocable. Both options are explained in the Qt Tutorial.

Also, you need to use a QVariant in order to exchange data between C++ and QML.
You can also register types, e.g. Widgets and stuff, so that you can use them in QML as a "native" type like a rectangle. In most cases this is not recommended, except if you need some certain extern class or some data that you cannot display otherwise in your QML Interface.

The reason for the QVariant is the Script based approach of QML. The QVariant basically contains your data and a desription of the data type, so that the QML knows how to handle it properly. That's why you have to specify the parameter in QML with String, int etc.. But the original data exchange with C++ remains a QVariant

I have used the qmlRegisterType before, but it is a very inconvenient Solution for simple data types. It is rather used for more complex data, such as custom Widgets, Canvas or Video elements that QML does not natively support or extended QStandardItemModels . It is a more convenient way to exchange data between QML and C++ and does not need Signals or Slots in first instance, because the QStandardItemModel updates the GUI automatically. For using the QStandardItemModel you need to register the Type with qmlRegisterType.. . The Model can then be used in Model based Views such as the ListView etc.

I attached a tutorial for this topic, it describes how to use the QListModel.

http://doc.qt.io/qt-4.8/qdeclarativemodels.html

追我者格杀勿论 2025-01-02 10:15:03

没有连接和任何上下文的解决方案是连接信号-信号而不是信号槽。找到此处
示例代码如下。

qml:

Window{
    signal qmlSend(string textOut)
    signal qmlReceive(string textIn)
    onQmlReceive:{
      console.log(textIn)
    }
}

Background类的头文件包含

public signals:
    void cppSend(QString textOut);
public slots:
    void cppReceive(QString textIn);

并且main.cpp以这种方式连接它们:

1.从qml到cpp:

QObject::connect(qmlRootObject, SIGNAL(qmlSend(QString)),
                backgroundObject, SLOT(cppReceive(QString)));

2.从cpp到qml:

QObject::connect(backgroundObject, SIGNAL(cppSend(QString)),
                 qmlRootObject, SIGNAL(qmlReceive(QString)));

Solution without Connections and any context is by connecting not signal-slot, but signal-signal. Found here.
Example code is as follows.

qml:

Window{
    signal qmlSend(string textOut)
    signal qmlReceive(string textIn)
    onQmlReceive:{
      console.log(textIn)
    }
}

Header file of Background class contains

public signals:
    void cppSend(QString textOut);
public slots:
    void cppReceive(QString textIn);

And main.cpp connects them in this way:

1.From qml to cpp:

QObject::connect(qmlRootObject, SIGNAL(qmlSend(QString)),
                backgroundObject, SLOT(cppReceive(QString)));

2.From cpp to qml:

QObject::connect(backgroundObject, SIGNAL(cppSend(QString)),
                 qmlRootObject, SIGNAL(qmlReceive(QString)));
嘿嘿嘿 2025-01-02 10:15:03

我尝试了很多解决方案来成功地从 C++ 信号更新 QML,但很多都不起作用。
该解决方案有效并且已经过测试,它基于以下答案:https://stackoverflow.com/a/59502860/2486332 (by @Adriano Campos)

您可以使用信号将数据从 C++ 发送到 qml,如下所示:

main.cpp:

#include <QQmlContext>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    // Class init
    YourClass yourObject;

    // Embedding C++ Objects into QML with Context Properties
    QQmlContext* ctx = engine.rootContext();
    ctx->setContextProperty("yourObject", &yourObject);

    return app.exec();
}

main.qml:

import QtQuick 2.6

Window {
    id: mainWindow

    Connections {
        target: yourObject
        onSignalData: {
            console.log("Data: " + signal_param)
            textToChange.text = "Changed to: " + signal_param
        }
    }

    Text {
        id: textToChange
        text: "beforeChange"
    }
}

yourClass.h:

class YourClass : public QObject
{
Q_OBJECT
signals:
    // Signal from YourClass
    void signalData(QString signal_param);
}

yourClass.cpp:

emit signalData("Hello QML"); // Signal from yourClass

有关“如何将带有信号和槽的 Qt C++ 类公开到 QML”的完整教程可在此页面上找到:https://felgo.com/cross-platform-development/how-to-expose-a-qt-cpp-class-with-signals-and-slots-to-qml

I have tried a lot of solutions to succeed in just update QML from a C++ signal but many did not work.
This solution works and has been tested, it is based on this answer: https://stackoverflow.com/a/59502860/2486332 (by @Adriano Campos)

You can send data from C++ to qml using signals, like this:

main.cpp:

#include <QQmlContext>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    // Class init
    YourClass yourObject;

    // Embedding C++ Objects into QML with Context Properties
    QQmlContext* ctx = engine.rootContext();
    ctx->setContextProperty("yourObject", &yourObject);

    return app.exec();
}

main.qml:

import QtQuick 2.6

Window {
    id: mainWindow

    Connections {
        target: yourObject
        onSignalData: {
            console.log("Data: " + signal_param)
            textToChange.text = "Changed to: " + signal_param
        }
    }

    Text {
        id: textToChange
        text: "beforeChange"
    }
}

yourClass.h:

class YourClass : public QObject
{
Q_OBJECT
signals:
    // Signal from YourClass
    void signalData(QString signal_param);
}

yourClass.cpp:

emit signalData("Hello QML"); // Signal from yourClass

A complete tutorial about "How to Expose a Qt C++ Class with Signals and Slots to QML" is available on this page: https://felgo.com/cross-platform-development/how-to-expose-a-qt-cpp-class-with-signals-and-slots-to-qml

岁月流歌 2025-01-02 10:15:03

对于那些也偶然发现这个问题的人,我想说一切都简单得多。您只需要来自 C++ 的信号即可拥有 QVariant 参数。例如:

QObject::connect(&recipient, SIGNAL(resTalk(QVariant)), engine.rootObjects().at(0)->findChild<QObject*>("winSettings"),
                     SLOT(showWithErrorNetwork(QVariant)));

我的信号声明如下:

signals:
    void resTalk(QVariant res);

所以我调用信号:

emit resTalk(true); //For more complex types, use  'emit yourSignal(QVariant(yourArg))'

这是我在 QML 中的插槽:

    function showWithErrorNetwork(isNoError=false) {
        if(!isNoError) {
            visible = true
            warningText.text = "Network error. Check the data."
            warningText.visible = true
        }
    }

For those who also stumbled upon this question, I want to say that Everything is much simpler. You just need the signal from C++ to have QVariant arguments. For example:

QObject::connect(&recipient, SIGNAL(resTalk(QVariant)), engine.rootObjects().at(0)->findChild<QObject*>("winSettings"),
                     SLOT(showWithErrorNetwork(QVariant)));

My signal is declared like this:

signals:
    void resTalk(QVariant res);

So I'm calling the signal:

emit resTalk(true); //For more complex types, use  'emit yourSignal(QVariant(yourArg))'

And here is the slot I have in QML:

    function showWithErrorNetwork(isNoError=false) {
        if(!isNoError) {
            visible = true
            warningText.text = "Network error. Check the data."
            warningText.visible = true
        }
    }
污味仙女 2025-01-02 10:15:03

为什么不使用rootContext?

在 c++ 方面,你有:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

//--------------------------------------------------------
#include <myClass.h>
//--------------------------------------------------------

int main(int argc, char *argv[])
{

    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    //--------------------------------------------------------
    myClass * myobj = new myClass(&app);
    //--------------------------------------------------------

    //--------------------------------------------------------
    engine.rootContext()->setContextProperty("myobj",myobj);
    //--------------------------------------------------------

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    return app.exec();
}

在 qml 方面,你有:

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    id: window
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    //--------------------------------------------------------
    Component.onCompleted: {
       myobj.onSomeSignal.connect(signalHandling) 
    }
    //--------------------------------------------------------

    //--------------------------------------------------------
    function signalHandling(){
       console.log("Signal emitted from c++ side")
    }
    //--------------------------------------------------------
}

Why not use rootContext?

in c++ side you have:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

//--------------------------------------------------------
#include <myClass.h>
//--------------------------------------------------------

int main(int argc, char *argv[])
{

    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    //--------------------------------------------------------
    myClass * myobj = new myClass(&app);
    //--------------------------------------------------------

    //--------------------------------------------------------
    engine.rootContext()->setContextProperty("myobj",myobj);
    //--------------------------------------------------------

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    return app.exec();
}

and in qml side you have:

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    id: window
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    //--------------------------------------------------------
    Component.onCompleted: {
       myobj.onSomeSignal.connect(signalHandling) 
    }
    //--------------------------------------------------------

    //--------------------------------------------------------
    function signalHandling(){
       console.log("Signal emitted from c++ side")
    }
    //--------------------------------------------------------
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文