如何在 QML 中使用模型?
我有一个用 qml 和 C++ 编写的 GUI.有 2 个组合框(qt control 5.1).每当第一个组合框的值发生更改时,第二个组合框都必须在运行时更新.
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.
maincontext->setContextProperty("typemodel", QVariant::fromValue(m_typemodel));
maincontext->setContextProperty("unitmodel", QVariant::fromValue(m_unitmodel));
这些是我从 C++ 提供给 qml 的 2 个模型.
These are 2 models that I give to qml from c++.
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)).但它似乎没有更新组合框的模型.
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.
如何在运行时更新 qml 的模型?
How can I update qml's model on runtime?
推荐答案
为了开始解决您的问题,我们需要了解 unitGenerator
方法的作用.如果您使用自定义模型,几乎可以肯定您没有正确实现通知.目前我敢打赌,您不会发出模型重置的信号.
To even begin to address your issue, we'd need to see what the unitGenerator
method 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.
下面是一个完整的代码示例,展示了如何将 QStringListModel
绑定到可编辑的 ListView
和 ComboBox
es.第二个 ComboBox
的模型是根据第一个模型的选择重新生成的.这大概是您想要的功能.
Below is a complete code example that shows how you can tie a QStringListModel
to an editable ListView
and to ComboBox
es. The second ComboBox
's model is regenerated based on the selection from the first one. This presumably approximates your desired functionality.
注意 QStringListModel
对角色的具体处理.该模型对待显示和编辑角色几乎相同:它们都映射到列表中的字符串值.然而,当您更新特定角色的数据时,dataChanged
信号仅携带您已更改的角色.这可用于中断可能存在于模型编辑器项 (TextInput) 中的绑定循环.当您使用自定义模型时,您可能需要实现类似的功能.
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 dataChanged
signal carries only the 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.
display
角色用于将组合框绑定到模型.edit
角色用于预填充编辑器对象.编辑器的 onTextChanged
信号处理程序正在更新 display
角色,这不会导致其自身的绑定循环.如果处理程序正在更新 edit
角色,则会通过 text
属性导致绑定循环.
The display
role is used to bind the combo boxes to the model. The edit
role is used to pre-populate the editor objects. The editor's onTextChanged
signal handler is updating the display
role, and this doesn't cause a binding loop to itself. If the handler was updating the edit
role, it would cause a binding loop via the text
property.
QML 中有各种各样的模型".在内部,QML 将在模型中包装几乎任何东西".任何内部不是 QObject 但仍然可以是模型的东西(比如 QVariant
),不会通知任何人任何事情.
There are various kinds of "models" in QML. Internally, QML will wrap almost "anything" in a model. Anything that is internally not a QObject yet can still be a model (say a QVariant
), won't be notifying anyone about anything.
例如,基于 QVariant
的模型"包装了 int
不会发出通知,因为 QVariant
不是 >QObject
可以发出变化信号.
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.
同样,如果您的模型"绑定到从 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.
不知道您的模型类型是什么,就无法判断.
Without knowing what your model types are, it's impossible to tell.
ma??in.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"
}
}
}
ma??in.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"
相关文章