使用QML

时间:2018-11-18 07:01:33

标签: c++ qt qml

我正在开发一个使用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();
}

QmlInterface.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();
}

MainClass.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

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

1 个答案:

答案 0 :(得分:2)

问题是您创建了两个QmlInterface的实例:

QmlInterface qml;
qml.SetupUI();

CppInterface
{
    id: cpp
}

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

因此,不是创建2个QmlInterface而是创建一个,为了方便起见,您没有在QML中创建对象,而仅使用setContextProperty()导出了在C ++中创建的对象:

// ...
#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();
}