首页 > 解决方案 > 使用 QML 构建基本的 Qt 界面

问题描述

我正在开发一个使用在 QML 中创建的用户界面的程序。它的核心程序有两个线程:运行 UI 的主线程和处理所有其余工作的第二个线程。所以程序有一个类用于与 UI 交互,第二个类是后端进程。问题在于将插槽/信号从 UI 类连接到第二个线程上的第二个类。

代码如下: main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "QmlInterface.h"
#include "MainClass.h"

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

    QGuiApplication app(argc, argv);

    qmlRegisterType<QmlInterface>("CppInterface",1,0,"CppInterface");

    /* Ui Stuff */
    QmlInterface qml;
    qml.SetupUI();

    /* Main class */
    MainClass work;
    QObject::connect(&qml, SIGNAL(onButtonClicked()), &work, SLOT(on_ButtonClicked()) );

    return app.exec();
}

Qml接口.h

#ifndef QMLINTERFACE_H
#define QMLINTERFACE_H

#include <QObject>
#include <QDebug>
#include <QQmlApplicationEngine>

class QmlInterface : public QObject
{
    Q_OBJECT
public:
    explicit QmlInterface();
    virtual ~QmlInterface();
    void SetupUI();

public slots:
    Q_INVOKABLE void buttonClicked();
signals:
    void onButtonClicked();
private:
    QQmlApplicationEngine *engine;
};

#endif // QMLINTERFACE_H

QmlInterface.cpp

#include "QmlInterface.h"

QmlInterface::QmlInterface()
{

}

QmlInterface::~QmlInterface()
{

}

void QmlInterface::SetupUI()
{
    engine = new QQmlApplicationEngine;
    engine->load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine->rootObjects().isEmpty())
    {
        qDebug() << "Failed to load UI";
    }
}

void QmlInterface::buttonClicked()
{
    qDebug() << "Button clicked! Signal to be emited!";
    emit onButtonClicked();
}

主类.h

#ifndef MAINCLASS_H
#define MAINCLASS_H

#include <QThread>
#include <QtDebug>

class MainClass : public QThread
{
    Q_OBJECT
public:
    MainClass();
    virtual ~MainClass() {}

public slots:
    void on_ButtonClicked();

private:
    void run();
};

#endif // MAINCLASS_H

主类.cpp

#include "MainClass.h"

MainClass::MainClass()
{

}

void MainClass::on_ButtonClicked()
{
    qDebug() << "Button click received in main class!";

}

void MainClass::run()
{
    while(1)
    {
        QThread::sleep(1);
    }
}

最后是 main.qml

import QtQuick 2.11
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Window 2.1

import CppInterface 1.0

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

    CppInterface
    {
        id: cpp
    }

    Button
    {
        text: "Click me"
        onPressed: {
            cpp.buttonClicked();
        }
    }

}

QML 和 QmlInterface 之间的连接工作正常!问题在于 QmlInterface 和 MainClass 之间的连接。

更具体地说,问题在于main.cpp中调用的connect()函数似乎无法将给定信号与来自 MainClass 的给定插槽链接:

QObject::connect(&qml, SIGNAL(onButtonClicked()), &work, SLOT(on_ButtonClicked()) );

标签: c++qtqml

解决方案


问题是您创建了 2 个实例QmlInterface

QmlInterface qml;
qml.SetupUI();

CppInterface
{
    id: cpp
}

并且您已经连接了第一个实例的信号,并且您正在使用第二个实例发出信号。

因此,不是创建 2 QmlInterface,而是创建一个,为方便起见,您无需在 QML 中创建对象,而仅使用以下命令导出在 C++ 中创建的对象setContextProperty()

// ...
#include <QQmlContext>
// ...
void QmlInterface::SetupUI()
{
    engine = new QQmlApplicationEngine;
    engine->load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine->rootObjects().isEmpty())
        qDebug() << "Failed to load UI";
    else
        // export
        engine->rootContext()->setContextProperty("cpp", this);
}

*.qml

import QtQuick 2.11
import QtQuick.Controls 2.1
import QtQuick.Window 2.1

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

    Button
    {
        text: "Click me"
        onPressed: cpp.buttonClicked();
    }
}

另一方面,不需要注册为类型,QmlInterface以便您可以将其删除:

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

    QGuiApplication app(argc, argv);

    /* Ui Stuff */
    QmlInterface qml;
    qml.SetupUI();

    /* Main class */
    MainClass work;
    QObject::connect(&qml, &QmlInterface::onButtonClicked, &work, &MainClass::on_ButtonClicked );

    return app.exec();
}

推荐阅读