c++ - 发射信号不更新 GUI 中的值

标签 c++ qt user-interface qml

我正在尝试制作一个非常基本的时间表应用程序,只是为了学习 Qt 的基础知识。我对此进行了相当多的研究,但似乎无法解决我的问题,当我更改主题的值时会发出信号,但发出的信号不会更新 GUI。它肯定会更改代码中的值,但 QML GUI 不会在运行时更新它。

我有一个名为 Day 的类,其中包含以下 Q_PROPERTY:

    Q_PROPERTY(Period *getPeriod READ getPeriod WRITE setPeriod NOTIFY periodChanged)
    Q_PROPERTY(QString getDay READ getDay WRITE setDay NOTIFY dayChanged)

和一个持有期间的成员

    Period *m_period = new Period[10]; //Of type Period (my other class) which holds my subject string

我还有日期和时间段的 getter 和 setter(如 Q_PROPERTY 中所示),这两个用于设置/获取主题:

    Q_INVOKABLE QString getSubject(int t){
    return m_period[t].getSub();
    };
    Q_INVOKABLE void setSubject(int t, QString subj){
    m_period[t].setSub(subj);
    emit periodChanged();
    };

具有以下信号:

    void periodChanged();
    void dayChanged();

我还有一个名为 Period 的类,具有以下 Q_PROPERTY:

    Q_PROPERTY(QString getSub READ getSub WRITE setSub NOTIFY subChanged)

和一个持有主题名称的成员:

    QString subject;

我的 Period 类包含在 day 中调用的函数以实际更改 QString 主题:

    QString getSub(){
    return subject;
    };
    void setSub(QString sub){
    subject = sub;
    emit subChanged();
    };

带有以下信号:

    void subChanged();

所以当在我的 QML 中使用 setSubject() 更改主题时,它不应该发出 periodChanged() 和 subChanged() 信号,这应该更新 GUI 吗?我以为可以,但似乎不起作用。

作为引用,这基本上是我在 QML 中实现它的方式:

    Label { text: monday.getSubject(2) } //How I display the Subject, the parameter being the period number

    Button{
        text: "Enter"
        onClicked:{
            monday.setSubject(2, "RANDOM_TEXT") //How I set the subject at run time, with the first argument being the period number and second the text I want to change it to
        }

主要文件和类文件如下:

主要.cpp

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

qmlRegisterType<Day>("Timetable", 1,0, "Day");
qmlRegisterType<Period>("Timetable", 1,0, "Period");

QQmlApplicationEngine engine;

Day monday;
engine.rootContext()->setContextProperty("monday", &monday);

engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQmlComponent component(&engine, QUrl::fromLocalFile("main.qml"));
component.create();

return app.exec();
}

日.h

class Day : public QObject
{
Q_OBJECT
Q_PROPERTY(Period *getPeriod READ getPeriod WRITE setPeriod NOTIFY periodChanged)


private:
        Period *m_period = new Period[10];

public:
    Day(QObject *parent = 0);
    ~Day();

    Period* getPeriod();
    Q_INVOKABLE void setPeriod(Period *p);

    Q_INVOKABLE QString getSubject(int t){
    return m_period[t].getSub();
    };
    Q_INVOKABLE void setSubject(int t, QString subj){
    m_period[t].setSub(subj);
    emit periodChanged();
    };

signals:
    void periodChanged();
};

句号.h

class Period: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString getSub READ getSub WRITE setSub NOTIFY subChanged)

private:
    QString subject;

public:
    Period(QObject *parent = 0);
    ~Period();

    QString getSub(){
    return subject;
    };
    void setSub(QString sub){
    subject = sub;
    emit subChanged();
    };

signals:
    void subChanged();
};

主.qml

ApplicationWindow {
    id: mainWindow
    visible: true
    title: "Timetable App"
    property int margin: 11
    width: mainLayout.implicitWidth + 2 * margin
    height: mainLayout.implicitHeight + 2 * margin
    minimumWidth: 800
    minimumHeight: 600

ColumnLayout {
    id: mainLayout
    anchors.fill: parent
    anchors.margins: margin

    GroupBox{

        id: timetable
        title: "Timetable"
        Layout.fillWidth: true
        Layout.fillHeight: true

        GridLayout {
            id: gridLayout
            rows: 11
            flow: GridLayout.TopToBottom
            anchors.fill: parent
            Layout.fillWidth: true
            Layout.fillHeight: true

            Label { }
            Label { text: "8:00" }
            Label { text: ...} // Added Labels for times from 8:00 to 17:00

            Label { text: "Monday" }
            Label { text: monday.getSubject(0) }
            Label { text: monday.getSubject(1) }
            Label { text: ...} // Added Labels to display subjects for monday at different times, also did the same for the rest of the week
        }
    }

    RowLayout{
         Button{
            text: "Enter"
            onClicked:{
                monday.setSubject(1, "RANDOM_TEXT") // Set the second period of monday to "RANDOM_TEXT"
                console.log(monday.getSubject(1)) // To check if actually set
            }
         }
    }
}
}

最佳答案

您的问题是您是通过 QML 中的方法调用而不是通过属性绑定(bind)来检索值。

像这样的 QML 代码应该更新

text: monday.getPeriod.getSub

显然调用属性“getSomething”有点奇怪。

现在,您的 m_period 建议单个 Day 对象将有多个 Period,这表明您可能需要一个列表属性而不是单个 Period 对象。有点像

Q_PROPERTY(QList<Period*> periods READ getPeriods NOTIFY periodsChanged);

像这样从 QML 中使用它

text: monday.periods[0].getSub

或者甚至使用例如一个中继器

Label { text: "Monday" }
Repeater {
    model: monday.periods

    Label {
        text: modelData.getSub
    }
}

与您的更新问题无关但也很重要: NOTIFY 信号触发绑定(bind)更新,因此您不希望不必要地发出它们。 IE。发出这些值的 setter 应该首先检查新值是否实际上与旧值不同,并且只有在它们不同时才发出。

关于c++ - 发射信号不更新 GUI 中的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40317449/

相关文章:

c++ - MFC-C代码合并问题

c++ - 实时音频,快速循环中的临时缓冲区,不同的方法

c++ - 使用 FireBreath 的 WMI 和 C++

c++ - 在内存池中查找下一个可用 block

c++ - 如何使用 Sigar 库在 C++ 中获取 CPU 使用率

qt - 在 Qt 中卸载插件

c++ - 改变QLabel文本的颜色?访问和修改.ui 文件的成员? [Qt]

c++ - 如何让信号和槽在 Qt 中工作?

C# GUI 和委托(delegate)用作抽象层

vba - 如何允许用户退出长时间运行的 VBA 任务?