jjzjj

c++ - 将它们传递给 cpp 后如何与 qml 项目值进行交互?

coder 2024-02-24 原文

我正在尝试将 qml 中的项目值获取到我的 cpp 代码中,从那里我想将这些值添加到 CAN 消息中并通过 CAN 总线发送它们.

到目前为止,我可以成功地将许多qml 项的值和状态获取到我的cpp 中。此外,我可以使用静态值将 CAN 消息传输到 CAN 总线。但是,其中一些值不应是静态的,而应使用 qml 中的项目值动态更新。

这是backend.h:

#ifndef BACKEND_H
#define BACKEND_H

#include <QObject>
#include <QCanBusDevice>

class BackEnd : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int elemVal READ getElemVal WRITE setElemVal NOTIFY elemValChanged)

public:
    explicit BackEnd(QObject *parent = nullptr);
    //elemVal
    int getElemVal();
    void setElemVal(const int &elemVal);
    int m_elemVal;

    //can
    void run();
    void oneShotConnectCan();
    QCanBusDevice *m_canDevice = nullptr;

signals:
    void elemValChanged();

public slots:
    void sendCanFrame();
};

#endif // BACKEND_H

这是backend.cpp:

BackEnd::BackEnd(QObject *parent) : QObject(parent)
{

}

//elemVal get set
int BackEnd::getElemVal()
{
    return m_elemVal;
}

void BackEnd::setElemVal(const int &elemVal)
{
    if(elemVal == m_elemVal)
        return;

    m_elemVal = elemVal;
    emit elemValChanged();
    qDebug() << "elemVal is: " << m_elemVal;
}
//end of elemVal get set

... 
CAN Bus initialization
...

void BackEnd::sendCanFrame()
{
    quint32 frameid = 131;
    QByteArray payload;
    payload[0] = 0x04;
    payload[1] = 0x03;
    payload[2] = m_elemVal;

    QCanBusFrame testFrame(frameid, payload);
    testFrame.setFrameType(QCanBusFrame::DataFrame);

    m_canDevice->writeFrame(testFrame);
    if (m_canDevice->writeFrame(testFrame)) {
    qDebug() << "test frame: " << testFrame.toString();
    }
    else {
        qFatal("Write failed");
    }
}

这是main.cpp:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");

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

    BackEnd m_can;
    m_can.oneShotConnectCan(); //creating CAN device
    m_can.run(); //sending the CAN message

    return app.exec();
}

这是main.qml 文件:

Window {
    id: window
    objectName: "window"
    visible: true
    visibility: Window.FullScreen

    onWindowStateChanged: {
        console.log( "onWindowStateChanged (Window), state: " + windowState );
    }

    BackEnd{
        id: backend
    }

    Dial {
        id: dial
        x: 181
        y: 38
        stepSize: 1
        to: 255
        value: backend.elemVal
        onValueChanged: backend.elemVal = value
    }
}

qDebug的实际输出是这样的:

elemVal is:  0
test frame :  "     083   [3]  04 03 05"
test frame :  "     083   [3]  04 03 05"
elemVal is:  1
elemVal is:  2
elemVal is:  3
test frame :  "     083   [3]  04 03 05"
elemVal is:  4
elemVal is:  5
elemVal is:  6
test frame :  "     083   [3]  04 03 05"

我的期望是:

elemVal is:  0
test frame :  "     083   [3]  04 03 00"
test frame :  "     083   [3]  04 03 00"
elemVal is:  1
elemVal is:  2
elemVal is:  3
test frame :  "     083   [3]  04 03 03"
elemVal is:  4
elemVal is:  5
elemVal is:  6
test frame :  "     083   [3]  04 03 06"

消息的第三个字节,在实际输出中为 05,应该随 m_elemVal 变量动态变化,该变量连接到 qml 中。虽然我可以读取和写入 m_elemVal 的值,但我无法将其写入我的 CAN 报文。

抱歉,如果帖子太长,请尽可能具体。

感谢任何帮助...

最佳答案

您在 QML 中创建的后端对象

BackEnd {
    id: backend
}

与C++创建的不同:

BackEnd m_can;

有几种可能的解决方案:

1。通过setContextProperty()导出一个Backend对象

与其他建议解决方案相比的优势在于,现在可以从任何 QML 访问后端对象,例如 console.log()

#include <QQmlContext>
// ...
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    BackEnd m_can;
    m_can.oneShotConnectCan(); //creating CAN device
    m_can.run(); //sending the CAN message

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("backend", &m_can);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

*.qml

Window {
    id: window
    objectName: "window"
    visible: true
    visibility: Window.FullScreen

    onWindowStateChanged: {
        console.log( "onWindowStateChanged (Window), state: " + windowState );
    }

    Dial {
        id: dial
        x: 181
        y: 38
        stepSize: 1
        to: 255
        onValueChanged: backend.elemVal = value
    }
}

与其他答案相比的一个优势是不使用会产生问题的旧连接样式,因为它的验证是在运行时而不是编译时完成的。另外,代码依赖于QML结构。

我还假设您想在 elemVal 更改时发送一个帧,因此理想的是在 elemValChanged 和 sendCanFrame() 之间的信号之间建立连接:

BackEnd::BackEnd(QObject *parent) : QObject(parent)
{
    connect(this, &Backend::elemValChanged, this, &Backend::sendCanFrame);
}

2。创建 QML 类型

有时需要在创建对象后启动某些资源,在这种情况下,您可以使用 QML 中的 Component.onCompleted 或使用 QQmlParserStatus,在这种情况下,我将使用第二种方法。

*.h

class BackEnd : public QObject, public QQmlParserStatus
{
    Q_OBJECT
    Q_INTERFACES(QQmlParserStatus)
    Q_PROPERTY(int elemVal READ getElemVal WRITE setElemVal NOTIFY elemValChanged)
public:
    explicit BackEnd(QObject *parent = nullptr);
    void classBegin();
    void componentComplete();
    //elemVal
    int getElemVal();
    void setElemVal(const int &elemVal);
signals:
    void elemValChanged();

public slots:
    void sendCanFrame();
private:
    //can
    void run();
    void oneShotConnectCan();
    QCanBusDevice *m_canDevice = nullptr;
    int m_elemVal;
};

*.cpp

BackEnd::BackEnd(QObject *parent) : QObject(parent)
{
    connect(this, &Backend::elemValChanged, this, &Backend::sendCanFrame);
}

void BackEnd::classBegin(){}
void BackEnd::componentComplete()
{
    oneShotConnectCan(); //creating CAN device
    run()
}

//elemVal get set
int BackEnd::getElemVal()
{
    return m_elemVal;
}

void BackEnd::setElemVal(const int &elemVal)
{
    if(elemVal == m_elemVal)
        return;

    m_elemVal = elemVal;
    emit elemValChanged();
    qDebug() << "elemVal is: " << m_elemVal;
}
//end of elemVal get set

// ... 
// CAN Bus initialization
// ...

void BackEnd::sendCanFrame()
{
    quint32 frameid = 131;
    QByteArray payload;
    payload[0] = 0x04;
    payload[1] = 0x03;
    payload[2] = m_elemVal;

    QCanBusFrame testFrame(frameid, payload);
    testFrame.setFrameType(QCanBusFrame::DataFrame);

    m_canDevice->writeFrame(testFrame);
    if (m_canDevice->writeFrame(testFrame)) {
    qDebug() << "test frame: " << testFrame.toString();
    }
    else {
        qFatal("Write failed");
    }
}

main.cpp

static void registerTypes()
{
    qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");
}

Q_COREAPP_STARTUP_FUNCTION(registerTypes)

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

*.qml

Window {
    id: window
    objectName: "window"
    visible: true
    visibility: Window.FullScreen

    onWindowStateChanged: {
        console.log( "onWindowStateChanged (Window), state: " + windowState );
    }

    BackEnd{
        id: backend
        elemVal : dial.value
    }

    Dial {
        id: dial
        x: 181
        y: 38
        stepSize: 1
        to: 255
        Component.onCompleted: value = backend.elemVal
    }
}

关于c++ - 将它们传递给 cpp 后如何与 qml 项目值进行交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55952105/

有关c++ - 将它们传递给 cpp 后如何与 qml 项目值进行交互?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  4. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  7. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  10. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

随机推荐