C++ 如何在 QML 中使用模型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18616497/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:04:26  来源:igfitidea点击:

How to Use Models with QML?

c++qtcomboboxqml

提问by khajvah

I have a GUI written in qml and c++. There are 2 comboboxes (qt control 5.1). Second combobox has to update at runtime whenever the value of the first one is changed.

我有一个用 qml 和 C++ 编写的 GUI。有 2 个组合框(qt control 5.1)。每当第一个组合框的值发生更改时,第二个组合框都必须在运行时更新。

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)). But it does not seem to update the combobox's model.

这是第一个组合框。如您所见,每次更改第一个组合框的值时,第二个组合框的 c++ 模型都会更新(mainwin.unitGenerator(typebox.currentText))。但它似乎没有更新组合框的模型。

How can I update qml's model on runtime?

如何在运行时更新 qml 的模型?

回答by Reinstate Monica

To even begin to address your issue, we'd need to see what the unitGeneratormethod does. 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.

为了开始解决您的问题,我们需要了解该unitGenerator方法的作用。如果您使用自定义模型,几乎可以肯定您没有正确实现通知。我现在打赌你没有发出模型重置的信号。

Below is a complete code example that shows how you can tie a QStringListModelto an editable ListViewand to ComboBoxes. The second ComboBox's model is regenerated based on the selection from the first one. This presumably approximates your desired functionality.

下面是一个完整的代码示例,展示了如何将 aQStringListModel与可编辑ListViewComboBoxes 联系起来。第二个ComboBox模型是根据第一个模型的选择重新生成的。这大概接近您想要的功能。

Note the specific handling of roles done by the 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 dataChangedsignal carries onlythe role that you've changed. This can be used to break a binding loop that might be otherwise present in the model editor item (TextInput). When you use a custom model, you may need to implement similar functionality.

请注意由QStringListModel. 该模型对待显示和编辑角色几乎相同:它们都映射到列表中的字符串值。然而,当您更新特定角色的数据时,dataChanged信号携带您已更改的角色。这可用于中断可能存在于模型编辑器项 (TextInput) 中的绑定循环。当您使用自定义模型时,您可能需要实现类似的功能。

The displayrole is used to bind the combo boxes to the model. The editrole is used to pre-populate the editor objects. The editor's onTextChangedsignal handler is updating the displayrole, and this doesn't cause a binding loop to itself. If the handler was updating the editrole, it would cause a binding loop via the textproperty.

display角色用于将组合框绑定到模型。该edit角色用于预填充编辑器对象。编辑器的onTextChanged信号处理程序正在更新display角色,这不会导致其自身的绑定循环。如果处理程序正在更新edit角色,则会通过text属性导致绑定循环。

On Models in QML

关于 QML 中的模型

There are various kinds of "models" in QML. Internally, QML will wrap almost "anything" in a model. Anything that is internally not a QObjectyet can still be a model (say a QVariant), won't be notifying anyone about anything.

QML 中有各种“模型”。在内部,QML 将在模型中包装几乎“任何东西”。任何内部不是 QObject 的东西仍然可以是模型(比如 a QVariant),不会通知任何人任何事情。

For example, a "model" based on QVariantthat wraps an intwill not issue notifications, because QVariantis not a QObjectthat could signal changes.

例如,基于QVariant包装 an的“模型”int不会发出通知,因为QVariant它不会QObject发出更改信号。

Similarly, if your "model" is tied to a property value of a class derived from QObject, but you fail to emitthe 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

主文件

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"

回答by Simon Schmei?er

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).

工作得很好并且不会创建任何更新循环(因为它只被称为“人工”/输入修改)。