简体   繁体   English

如何在QML中使用模型?

[英]How to Use Models with QML?

I have a GUI written in qml and c++. 我有一个用qml和c ++编写的GUI。 There are 2 comboboxes (qt control 5.1). 有2个组合框(qt控件5.1)。 Second combobox has to update at runtime whenever the value of the first one is changed. 每当第一个组合框的值更改时,第二个组合框就必须在运行时进行更新。

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

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

These are 2 models that I give to qml from c++. 这些是我从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);

    }

This is the first combobox. 这是第一个组合框。 As you see, the c++ model of second combobox is updated every time the value of the first is changed (mainwin.unitGenerator(typebox.currentText)). 如您所见,第二个组合框的c ++模型在每次更改第一个组合框的值时都会更新(mainwin.unitGenerator(typebox.currentText))。 But it does not seem to update the combobox's model. 但是它似乎并没有更新组合框的模型。

How can I update qml's model on runtime? 如何在运行时更新qml的模型?

To even begin to address your issue, we'd need to see what the unitGenerator method does. 为了甚至可以解决您的问题,我们需要查看unitGenerator方法的作用。 If you're using a custom model, it's almost certain that you're not correctly implementing the notifications. 如果您使用的是自定义模型,则几乎可以肯定您没有正确实现通知。 My bet at the moment would be that you're not signaling the model reset. 目前,我的赌注是您未表示要重置模型。

Below is a complete code example that shows how you can tie a QStringListModel to an editable ListView and to ComboBox es. 下面是一个完整的代码示例,该示例显示如何将QStringListModel绑定到可编辑的ListViewComboBox The second ComboBox 's model is regenerated based on the selection from the first one. 根据第一个ComboBox的选择,重新生成第二个ComboBox的模型。 This presumably approximates your desired functionality. 据推测这近似于您所需的功能。

Note the specific handling of roles done by the QStringListModel . 注意QStringListModel完成的角色处理。 The model treats the display and edit roles almost the same: they both are mapped to the string value in the list. 该模型对待显示和编辑角色几乎相同:它们都映射到列表中的字符串值。 Yet when you update a particular role's data, the dataChanged signal carries only the role that you've changed. 但是,当您更新特定角色的数据时, dataChanged信号携带您已更改的角色。 This can be used to break a binding loop that might be otherwise present in the model editor item (TextInput). 这可用于打破模型编辑器项(TextInput)中可能存在的绑定循环。 When you use a custom model, you may need to implement similar functionality. 使用自定义模型时,可能需要实现类似的功能。

The display role is used to bind the combo boxes to the model. display角色用于将组合框绑定到模型。 The edit role is used to pre-populate the editor objects. edit角色用于预填充编辑器对象。 The editor's onTextChanged signal handler is updating the display role, and this doesn't cause a binding loop to itself. 编辑器的onTextChanged信号处理程序正在更新display角色,并且这不会导致自身的绑定循环。 If the handler was updating the edit role, it would cause a binding loop via the text property. 如果处理程序正在更新edit角色,则将通过text属性引起绑定循环。

On Models in QML 关于QML中的模型

There are various kinds of "models" in QML. QML中有各种各样的“模型”。 Internally, QML will wrap almost "anything" in a model. 在内部,QML会将模型中的几乎“任何内容”包装起来。 Anything that is internally not a QObject yet can still be a model (say a QVariant ), won't be notifying anyone about anything. 内部上不是QObject的任何事物仍然可以是模型(例如QVariant ),不会将任何事情通知任何人。

For example, a "model" based on QVariant that wraps an int will not issue notifications, because QVariant is not a QObject that could signal changes. 例如,基于QVariant包装了int的“模型”将不会发出通知,因为QVariant不是可以表示更改的QObject

Similarly, if your "model" is tied to a property value of a class derived from QObject , but you fail to emit the property change notification signal, it also won't work. 同样,如果您的“模型”与从QObject派生的类的属性值绑定在一起,但是您未能emit属性更改通知信号,那么它也将不起作用。

Without knowing what your model types are, it's impossible to tell. 如果不知道您的模型类型是什么,就无法分辨。

main.qml 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 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"

This is actually more of an answer/comment to the answer of @KubaOber. 实际上,这更多是对@KubaOber答案的回答/评论。

I found that it is actually not necessary to do any special tricks using multiple roles if you bind to the correct event: 我发现如果绑定到正确的事件,实际上没有必要使用多个角色来做任何特殊的技巧:

onAccepted: model.edit = text

works just fine and does not create any update loop (as it is only called on "human"/input modification). 可以正常工作,并且不会创建任何更新循环(因为仅在“人工” /输入修改时调用它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM