【问题标题】:Can't figure out the right way to bind signals from qml to cpp slots无法找出将信号从 qml 绑定到 cpp 插槽的正确方法
【发布时间】:2016-07-17 16:47:13
【问题描述】:

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

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 库。

【问题讨论】:

    标签: c++ qt qml signals-slots


    【解决方案1】:

    我强烈建议您将 Chat 对象暴露给 QML,而不是从 C++ 中挖掘出 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 实例,您可以使用 QML 引擎的 root context 使用 QQmlContext::setContextProperty() 将其设置为上下文属性。请注意,您必须在加载引用上下文属性的 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(...)
          }
      }
      

    【讨论】:

    • 我真的很喜欢寄存器类型和单例类型的方法。我一直是单身人士的粉丝。感谢您在我的问题中提供了如此大的帮助!很高兴得到与 QT 本身合作的人的回答:)
    • 你能指导我这部分吗? 'ApplicationWindow'(顺便说一句,即使它们有效,也总是将可见、宽度和高度下划线作为无效属性。我想知道它的修复方法或正确的方法,因为我无法在设计器中编辑它)跨度>
    • 这已在 Qt 5.7.1 中得到修复。临时解决方法是在控件导入之前添加import QtQuick.Window 2.2。很抱歉给您带来不便。
    【解决方案2】:

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

    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();
    

    【讨论】:

    • 太棒了!解决麻烦,谢谢!你能看看我在大括号中发布的关于 ApplicationWindow 的其他疑问吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    • 2013-10-08
    • 1970-01-01
    相关资源
    最近更新 更多