绑定的 c++ 值在 QML 中未更新

Bound c++ value not updating in QML

本文关键字:更新 QML 值在 c++ 绑定      更新时间:2023-10-16

我在 c++ 中将.ini文件读取为整数,然后通过绑定在 QML 中使用它。在运行时,可以更改.ini文件中的值,这会导致 c++ 整数也随之更改。我发现尽管整数在 c++ 中确实发生了变化(通过 qDebug(( 验证(,但 QML 中的绑定值并没有改变,尽管发出了所需的 changed(( 信号。我的应用程序结构摘录如下所示:

主.cpp:

//Establish the QQmlApplication engine, set context properties for the two c++ files and load the QML file.
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("MainCpp"), new MainCpp());
engine.rootContext()->setContextProperty(QStringLiteral("Config"), new Config());
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

maincppp.h:

public:
    explicit MainCpp(QObject *parent = nullptr);
    Q_PROPERTY(int someValue READ someValue NOTIFY someValueChanged)
    int someValue(){return m_someValue;}
signals:
    void someValueChanged();
private:
    int    m_someValue;

配置.h:

public:
    explicit Config(QObject *parent = nullptr);
    Q_PROPERTY(int someOtherValue READ someOtherValue NOTIFY someOtheralueChanged)
    int someOtherValue(){return m_someOtherValue;}
signals:
    void someOtherValueChanged();
public:
    void loadSettings();
public:
    int      m_someOtherValue;
    QString  m_File;

配置.cpp:

Config::Config(QObject *parent) : QObject(parent)
{
    m_File = "/some/path/to/settings/file/config.ini";
    loadSettings();
}
void Config::loadSettings()
{
    QSettings settings(m_File, QSettings::IniFormat);
    settings.beginGroup("GROUP_NAME");
    m_someOtherValue = settings.value("someOtherValueConfig", "").toInt();
    settings.endGroup();
}

mainCPP.cpp:

MainCpp::MainCpp(QObject *parent = nullptr) : QObject(parent)
{
    Config configPointer;
    m_someValue = configPointer.someOtherValue();
    emit someValueChanged();
}

main.qml:

Window {
    width: 800
    height: 480
    Text {
        id: someText
        text: Config.someOtherValue //This does NOT update on changes to m_someOtherValue on the c++ side
        //text: MainCpp.someValue //This DOES update on change to m_someValue on the c++ side
    }
}

在 maincpp 中调用以下代码.cpp以更新.ini文件:

void MainCpp::update(int var)
{
    Config configPointer;
    QSettings settings("/some/path/to/settings/file/config.ini", QSettings::IniFormat);
    settings.setValue("GROUP_NAME/someOtherValueConfig", var);
    configPointer.m_someOtherValue = var;
    m_someValue = configPointer.someOtherValue;
    emit configPointer.someOtherValueChanged();
    emit someValueChanged();
}

我添加了"emit someOtherValueChanged(("信号无济于事。如前所述,我知道m_someOtherValue已经改变,因为我使用 qDebug(( 查询它。如果m_someValue发生变化,为什么QML不观察m_someOtherValue的变化?

导致该行为是因为您有 3 个 Config 对象:

  1. 主.cpp

engine.rootContext()->setContextProperty(QStringLiteral("Config"), new Config());
  1. MainCpp 构造函数:

MainCpp::MainCpp(QObject *parent = nullptr) : QObject(parent)
{
    Config configPointer; 
    [...]
  1. 更新方法:

void MainCpp::update(int var)
{
    Config configPointer;

也就是说,如果更改了其中一些对象,则不会更改其他对象,因为它们是不同的。

一个可能的解决方案是使 Config 成为单例,因此所有对象在整个应用程序中都是相同的。

配置.h

#ifndef CONFIG_H
#define CONFIG_H
#include <QObject>
#include <QSettings>
class Config : public QObject
{
    static Config* instance;
    Q_OBJECT
    Q_PROPERTY(int someOtherValue READ someOtherValue NOTIFY someOtherValueChanged)
    explicit Config(QObject *parent = nullptr);
public:
    static Config *getInstance();
    int someOtherValue(){return m_someOtherValue;}
    [...]
};
#endif // CONFIG_H

配置.cpp

#include "config.h"
Config* Config::instance = 0;
Config::Config(QObject *parent):QObject(parent){
    m_File = "/some/path/to/settings/file/config.ini";
    loadSettings();
}
Config *Config::getInstance(){
    if (instance == 0)
        instance = new Config;
    return instance;
}
void Config::loadSettings(){
    [...]
}

然后通过 getInstance ((:

主CPP.cpp

#include "maincpp.h"
MainCpp::MainCpp(QObject *parent):QObject(parent){
    Config *configPointer = Config::getInstance();
    m_someValue = configPointer->someOtherValue();
    emit someValueChanged();
}
void MainCpp::update(int var)
{
    Config *configPointer = Config::getInstance();
    QSettings settings("/some/path/to/settings/file/config.ini", QSettings::IniFormat);
    settings.setValue("GROUP_NAME/someOtherValueConfig", var);
    configPointer->m_someOtherValue = var;
    m_someValue = configPointer->someOtherValue();
    emit configPointer->someOtherValueChanged();
    emit someValueChanged();
}

要在QML中使用它,您必须在qmlRegisterSingletonType()的帮助下注册:

主.cpp

#include "maincpp.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
static QObject *singletonTypeProvider(QQmlEngine *, QJSEngine *)
{
    return Config::getInstance();
}
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);
    qmlRegisterSingletonType<Config>("Config", 1, 0, "Config", singletonTypeProvider);
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty(QStringLiteral("MainCpp"), new MainCpp());
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}

在 qml 中,您必须导入模块并使用对象:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import Config 1.0
Window {
    width: 800
    height: 480
    visible: true
    ColumnLayout{
        Text {
            id: someText
            text: Config.someOtherValue
        }
        Text {
            id: anotherText
            text: MainCpp.someValue
        }
        Slider {
            value: 0.5
            maximumValue: 100
            onValueChanged: MainCpp.update(value)
        }
    }
}

完整的示例可以在以下链接中找到。