問題描述
我有一個用 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"
這篇關于如何在 QML 中使用模型?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!