【问题标题】:Qt Qml connect to a signal of a QObject property of a Context PropertyQt Qml 连接到 Context Property 的 QObject 属性的信号
【发布时间】:2017-11-16 06:35:05
【问题描述】:

所以这似乎是一个奇怪的设置。为了简单起见,我有一个从 QObject 继承的 C++ 对象,称为“MasterGuiLogic”。它是使用指向另一个名为“MainEventBroker”的对象的指针创建的,您可能会猜到它处理我的所有应用程序事件。 MasterGuiLogic 对象在 qml 中注册为上下文属性,因此它的属性可以在我的 qml 中的任何位置使用。所以 main.cpp 看起来像这样:

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

    MasterEventBroker *MainEventBroker = new MasterEventBroker();
    MasterGuiLogic *MainGuiLogic = new MasterGuiLogic(*MainEventBroker);

    qmlRegisterUncreatableType<MasterGuiLogic>("GrblCom", 1, 0, "MasterGuiLogic", "");
    qmlRegisterUncreatableType<GuiLogic_SerialCom>("GrblCom", 1, 0, "GuiLogic_SerialCom", "");

    QQmlApplicationEngine engine;
    QQmlContext* context = engine.rootContext();

    context->setContextProperty("MasterGuiLogic", &(*MainGuiLogic));

    engine.load(QUrl(QLatin1String("qrc:/QmlGui/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

MasterGuiLogic 创建另一个名为 SerialCom 的类的实例,将其设置为 Q_PROPERTY,以便可以通过 MasterGuiLogic 属性在 qml 中访问它的属性和公共槽。

MasterGuiLogic.h:

class MasterGuiLogic : public QObject
{
    Q_OBJECT
    Q_PROPERTY(GuiLogic_SerialCom* serialCom READ serialCom CONSTANT)
public:
    MasterEventBroker *eventBroker;

    explicit MasterGuiLogic(MasterEventBroker &ev, QObject *parent = nullptr);


    GuiLogic_SerialCom* serialCom() const {
        return Gui_SerialCom;
    }

private:

    GuiLogic_SerialCom *Gui_SerialCom;

MasterGuiLogic.cpp:

MasterGuiLogic::MasterGuiLogic(MasterEventBroker &ev, QObject *parent) : QObject(parent)
{
    this->eventBroker = &ev;
    this->Gui_SerialCom = new GuiLogic_SerialCom(this);
}

SerialCom.h:

//Forward Declare our parent
class MasterGuiLogic;

class GuiLogic_SerialCom : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList portNames READ portNames NOTIFY portNamesChanged)
    Q_PROPERTY(bool connectedToPort READ connectedToPort NOTIFY connectedToPortChanged)
public:

    MasterGuiLogic *parent;
    explicit GuiLogic_SerialCom(MasterGuiLogic *parent = nullptr);

    std::map<QString, QSerialPortInfo> portsMap;


    QStringList portNames() {
        return _portNames;
    }

    bool connectedToPort() {
        return _connectedToPort;
    }

private:

    QStringList _portNames;
    bool _connectedToPort = false;


signals:

    void portNamesChanged(const QStringList &);
    void connectedToPortChanged(const bool &);

public slots:

    void connectToPort(const QString portName);
    void disconnectFromPort(const QString portName);

};

SerialCom.cpp:

GuiLogic_SerialCom::GuiLogic_SerialCom(MasterGuiLogic *parent) : QObject(qobject_cast<QObject *>(parent))
{
    this->parent = parent;


    QList<QSerialPortInfo> allPorts = QSerialPortInfo::availablePorts();

    for (int i = 0; i < allPorts.size(); ++i) {
        this->_portNames.append(allPorts.at(i).portName());
        this->portsMap[allPorts.at(i).portName()] = allPorts.at(i);
    }

    emit portNamesChanged(_portNames);

}

void GuiLogic_SerialCom::connectToPort(const QString portName) {
    //TODO: Connect To Port Logic Here;

    //Set Connected
    this->_connectedToPort = true;
    emit connectedToPortChanged(this->_connectedToPort);

    qDebug() << portName;
}

void GuiLogic_SerialCom::disconnectFromPort(const QString portName) {
    //TODO: DisConnect To Port Logic Here;

    //Set DisConnected
    this->_connectedToPort = false;
    emit connectedToPortChanged(this->_connectedToPort);

    qDebug() << portName;
}

因此,从 qml 读取这些属性中的任何一个都非常容易,甚至可以将信号从 qml 发送到 c++

例如,这很好用:

connectCom.onClicked: {
        if (MasterGuiLogic.serialCom.connectedToPort === false) {
            MasterGuiLogic.serialCom.connectToPort(comPort.currentText);
        } else {
            MasterGuiLogic.serialCom.disconnectFromPort(comPort.currentText);
        }
    }

问题是,我似乎找不到连接到 SerialCom 发出的信号的方法。我以为我可以做这样的事情:

Connections: {
        target: MasterGuiLogic.serialCom;
        onConnectedToPortChanged: {
            if (MasterGuiLogic.serialCom.connectedToPort === false) {
                connectCom.text = "Disconnect";
                comPort.enabled = false;
            } else {
                connectCom.text = "Connect";
                comPort.enabled = true;
            }
        }
    }

这应该监听 SerialCom 上的布尔属性来更改,但我收到以下错误:

QQmlApplicationEngine failed to load component
qrc:/QmlGui/main.qml:21 Type Page1 unavailable
qrc:/QmlGui/Page1.qml:49 Invalid attached object assignment

这只是意味着我无法使用上面的目标行“连接”。有没有其他方法可以连接到来自 ContextProperty 内 QObject 类型的 Q_PROPERTY 的信号?

【问题讨论】:

  • 什么是Page1?我没有看到有关错误连接的错误。为什么您认为错误输出与Connections 有关?

标签: c++ qt qml qt-signals qproperty


【解决方案1】:

首先&amp;(*MainGuiLogic) 应该是什么意思? 您正在取消引用并再次引用 MainGuiLogic?为什么?

context-&gt;setContextProperty("MasterGuiLogic", MainGuiLogic); 就够了。

但是将MasterGuiLogic 注册为Type 并添加名为MasterGuiLogicObject 可以在QML 世界中覆盖它们自己。

将其设置为 context-&gt;setContextProperty("MyGuiLogic", MainGuiLogic); 以消除此行为。

也不要在 C++ 和 QML 世界之间传递引用,例如:

void connectedToPortChanged(**const bool &amp;**);

只需使用原子类型和值(const bool); 并为其命名,以便能够在 QML 中将其用作 命名值

void connectedToPortChanged(bool connected)

这是一个与您的结构类似的示例,它有效。只需单击窗口并查看输出控制台。

test.h

#ifndef TEST_H
#define TEST_H

#include <QObject>

class GuiLogic_SerialCom : public QObject
{
    Q_OBJECT
public:
    GuiLogic_SerialCom(){}

signals:
    void connectedToPortChanged(bool connected);

public slots:
    void connectToPort(const QString & portName);
};

class MasterGuiLogic : public QObject
{
    Q_OBJECT
public:
    MasterGuiLogic();

    Q_PROPERTY(GuiLogic_SerialCom * serialCom READ serialCom CONSTANT)
    GuiLogic_SerialCom* serialCom() const {return test;}

    Q_INVOKABLE void generate_signal();

private:
    GuiLogic_SerialCom * test;
};

#endif // TEST_H

test.cpp

#include "test.h"
#include <QDebug>

MasterGuiLogic::MasterGuiLogic()
{
    this->test = new GuiLogic_SerialCom();
}

void MasterGuiLogic::generate_signal()
{
    qDebug() << __FUNCTION__ << "Calling serialcom to gen signal";
    this->test->connectToPort("88");
}


void GuiLogic_SerialCom::connectToPort(const QString &portName)
{
    qDebug() << __FUNCTION__ << "got signal" << portName;
    emit this->connectedToPortChanged(true);
}

ma​​in.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "test.h"

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

    qmlRegisterUncreatableType<MasterGuiLogic>("GrblCom", 1, 0, "MasterGuiLogic", "");
    qmlRegisterUncreatableType<GuiLogic_SerialCom>("GrblCom", 1, 0, "GuiLogic_SerialCom", "");

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty(QStringLiteral("Test"), new MasterGuiLogic());

    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

ma​​in.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

import GrblCom 1.0

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

    MouseArea
    {
        anchors.fill: parent
        onClicked:
        {
            Test.generate_signal();
        }
    }

    Connections
    {
        target: Test.serialCom
        onConnectedToPortChanged:
        {
            console.log("Got signal from SerialCom in QML. passed bool value is: " + connected);
        }
    }
}

【讨论】:

  • 是的,对于取消引用和再次引用感到抱歉。这是我正在排除故障的其他东西的剩余代码。在其他地方建议注册类型,我认为这没有任何意义。我会试试这个并返回结果。
【解决方案2】:

好的,我发现了问题...提供的答案虽然出于其他原因确实有帮助,但并不是正确的解决方案。在查看@Xplatforms 的代码后,我无法弄清楚我所做的和他所做的之间有什么区别......直到我在自己的代码中看到了这一点:

Connections: {
        target: MasterGuiLogic.serialCom;
        onConnectedToPortChanged: {
            ...
        }
    }

那里不应该有冒号(:)...

Connections {
        target: MasterGuiLogic.serialCom;
        onConnectedToPortChanged: {
            ...
        }
    }

千万不要在困倦的时候尝试编程......哈哈

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 1970-01-01
    相关资源
    最近更新 更多