簡體   English   中英

如何在QML中使用模型?

[英]How to Use Models with QML?

我有一個用qml和c ++編寫的GUI。 有2個組合框(qt控件5.1)。 每當第一個組合框的值更改時,第二個組合框就必須在運行時進行更新。

maincontext->setContextProperty("typemodel", QVariant::fromValue(m_typemodel));

maincontext->setContextProperty("unitmodel", QVariant::fromValue(m_unitmodel));

這些是我從c ++給qml的2個模型。

ComboBox {
    id: typebox

    anchors.left: text1.right
    anchors.leftMargin: 5
    signal changed(string newtext)

    width: 70
    height: 23
    anchors.top: parent.top
    anchors.topMargin: 37
    model: typemodel

    onCurrentTextChanged: {

        mainwin.unitGenerator(typebox.currentText);

    }

這是第一個組合框。 如您所見,第二個組合框的c ++模型在每次更改第一個組合框的值時都會更新(mainwin.unitGenerator(typebox.currentText))。 但是它似乎並沒有更新組合框的模型。

如何在運行時更新qml的模型?

為了甚至可以解決您的問題,我們需要查看unitGenerator方法的作用。 如果您使用的是自定義模型,則幾乎可以肯定您沒有正確實現通知。 目前,我的賭注是您未表示要重置模型。

下面是一個完整的代碼示例,該示例顯示如何將QStringListModel綁定到可編輯的ListViewComboBox 根據第一個ComboBox的選擇,重新生成第二個ComboBox的模型。 據推測這近似於您所需的功能。

注意QStringListModel完成的角色處理。 該模型對待顯示和編輯角色幾乎相同:它們都映射到列表中的字符串值。 但是,當您更新特定角色的數據時, dataChanged信號攜帶您已更改的角色。 這可用於打破模型編輯器項(TextInput)中可能存在的綁定循環。 使用自定義模型時,可能需要實現類似的功能。

display角色用於將組合框綁定到模型。 edit角色用於預填充編輯器對象。 編輯器的onTextChanged信號處理程序正在更新display角色,並且這不會導致自身的綁定循環。 如果處理程序正在更新edit角色,則將通過text屬性引起綁定循環。

關於QML中的模型

QML中有各種各樣的“模型”。 在內部,QML會將模型中的幾乎“任何內容”包裝起來。 內部上不是QObject的任何事物仍然可以是模型(例如QVariant ),不會將任何事情通知任何人。

例如,基於QVariant包裝了int的“模型”將不會發出通知,因為QVariant不是可以表示更改的QObject

同樣,如果您的“模型”與從QObject派生的類的屬性值綁定在一起,但是您未能emit屬性更改通知信號,那么它也將不起作用。

如果不知道您的模型類型是什么,就無法分辨。

main.qml

import QtQuick 2.0
import QtQuick.Controls 1.0

ApplicationWindow {
    width: 300; height: 300
    ListView {
        id: view
        width: parent.width
        anchors.top: parent.top
        anchors.bottom: column.top
        model: model1
        spacing: 2
        delegate: Component {
            Rectangle {
                width: view.width
                implicitHeight: edit.implicitHeight + 10
                color: "transparent"
                border.color: "red"
                border.width: 2
                radius: 5
                TextInput {
                    id: edit
                    anchors.margins: 1.5 * parent.border.width
                    anchors.fill: parent
                    text: edit // "edit" role of the model, to break the binding loop
                    onTextChanged: model.display = text
                }
            }
        }
    }
    Column {
        id: column;
        anchors.bottom: parent.bottom
        Text { text: "Type";  }
        ComboBox {
            id: box1
            model: model1
            textRole: "display"
            onCurrentTextChanged: generator.generate(currentText)
        }
        Text { text: "Unit"; }
        ComboBox {
            id: box2
            model: model2
            textRole: "display"
        }
    }
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QStringListModel>
#include <QQmlContext>

class Generator : public QObject
{
    Q_OBJECT
    QStringListModel * m_model;
public:
    Generator(QStringListModel * model) : m_model(model) {}
    Q_INVOKABLE void generate(const QVariant & val) {
        QStringList list;
        for (int i = 1; i <= 3; ++i) {
            list << QString("%1:%2").arg(val.toString()).arg(i);
        }
        m_model->setStringList(list);
    }
};

int main(int argc, char *argv[])
{
    QStringListModel model1, model2;
    Generator generator(&model2);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    QStringList list;
    list << "one" << "two" << "three" << "four";
    model1.setStringList(list);

    engine.rootContext()->setContextProperty("model1", &model1);
    engine.rootContext()->setContextProperty("model2", &model2);
    engine.rootContext()->setContextProperty("generator", &generator);

    engine.load(QUrl("qrc:/main.qml"));
    QObject *topLevel = engine.rootObjects().value(0);
    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
    window->show();
    return app.exec();
}

#include "main.moc"

實際上,這更多是對@KubaOber答案的回答/評論。

我發現如果綁定到正確的事件,實際上沒有必要使用多個角色來做任何特殊的技巧:

onAccepted: model.edit = text

可以正常工作,並且不會創建任何更新循環(因為僅在“人工” /輸入修改時調用它)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM