无法找出将信号从 qml 绑定到 cpp 插槽的正确方法

Can't figure out the right way to bind signals from qml to cpp slots

我正在使用 QT 5.7。 我的 main.qml 文件的根元素是 'ApplicationWindow'(顺便说一句,尽管它们有效,但它总是强调可见、宽度和高度为无效属性。我想知道它的修复方法或正确的方法因为我不能在设计器中编辑它)。 这是它的代码:

ApplicationWindow {
visible: true
width: 640
height: 480
    Rectangle{
    signal mSend()
    anchors.fill: parent
        Button{
            id: bSend
                onClicked: {
                    parent.mSend()
                }
        }
    }
}

现在我正尝试以这种方式将 mSend 信号绑定到 CPP 插槽:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDebug>
#include <QObject>
#include <QQuickView>
#include <QQuickItem>

class Chat: public QObject{
    Q_OBJECT

    public Q_SLOTS:
    void sendMessage(){
        qDebug() << "CPP SLOT sendMessage called";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    QQuickView view(&engine, Q_NULLPTR);
    QObject *item = view.rootObject();
    Chat chat;
    if(item){
        qDebug() << "Item found";
        QObject::connect(item, SIGNAL(mSend()), &chat, SLOT(sendMessage()));
    }else{
        qDebug() << "item is null";
    }

    return app.exec();
}
#include "main.moc"

但结果是Item is null。我一直在关注这个 guide,但我无法在 QML 中修改 QMLApplicationEngine 和 ApplicationWindow。

TIA

注意:我正在使用 Q_SLOTS 因为我也在使用 Boost 来合并 Socket IO 库。

您应该将信号从矩形移动到根对象:

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4

ApplicationWindow {
  id: appWindow
  visible: true
  width: 640
  height: 480
  signal mSend()
  Rectangle{
    anchors.fill: parent
    Button{
      id: bSend
      onClicked: {
        appWindow.mSend()
      }
    }
  }
}

根对象可直接通过 QQmlApplicationEngine 获得

QGuiApplication app(argc, argv);

QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));

QObject *item = engine.rootObjects().first();
Chat chat;
if(item){
    qDebug() << "Item found";
    QObject::connect(item, SIGNAL(mSend()), &chat, SLOT(sendMessage()));
}else{
    qDebug() << "item is null";
}

return app.exec();

与其挖掘 QML 对象并从 C++ 中弄乱它们,我强烈建议将您的 Chat 对象公开给 QML。这就是 QML 和 C++ 集成设计的工作方式。您有多种选择。无论哪种方式,您都可以直接从 Button::onClicked 信号处理程序调用 Chat::sendMessage()

QML 类型

您可以使用 qmlRegisterType()Chat 注册为 QML 类型,这样您就可以在 QML 中创建实例。

  • main.cpp:

    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<Chat>("foo.bar", 1, 0, "Chat"); // <==
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    
        return app.exec();
    }
    
  • main.qml:

    import QtQuick 2.0
    import QtQuick.Controls 2.0
    import foo.bar 1.0
    
    ApplicationWindow {
        Chat {
          id: chat
        } 
    
        Button {
            onClicked: chat.sendMessage(...)
        }
    }
    

QML 单例类型

您可以使用 qmlRegisterSingletonType()Chat 注册为 QML 单例类型,这样您就可以方便地在 QML 中的任何地方访问同一个实例。

  • main.cpp

    static QObject *chatInstance(QQmlEngine *engine, QJSEngine *)
    {
        return new Chat(engine);
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        qmlRegisterSingletonType<Chat>("foo.bar", 1, 0, "Chat", chatInstance); // <==
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    
        return app.exec();
    }
    
  • main.qml

    import QtQuick 2.0
    import QtQuick.Controls 2.0
    import foo.bar 1.0
    
    ApplicationWindow {
        Button {
            onClicked: Chat.sendMessage(...)
        }
    }
    

上下文 属性

如果您必须在 C++ 中创建 Chat 实例,您可以使用 QQmlContext::setContextProperty() for the QML engine's root context 将其设置为上下文 属性。请注意,您必须在 属性 之前设置 加载引用上下文 属性.

的 QML
  • main.cpp

    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        Chat chat;
        engine.rootContext()->setContextProperty("chat", &chat); // <==
    
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    
        return app.exec();
    }
    
  • main.qml

    import QtQuick 2.0
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        Button {
            onClicked: chat.sendMessage(...)
        }
    }