如何将模型与 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
绑定到可编辑ListView
和ComboBox
es。第二个ComboBox
模型是根据第一个模型的选择再生的。这大概接近于您想要的功能。
请注意QStringListModel
完成的角色的具体处理。该模型对显示和编辑角色的处理几乎相同:它们都映射到列表中的字符串值。然而,当您更新特定角色的数据时,dataChanged
信号仅携带您已更改的角色。这可用于中断模型编辑器项 (TextInput) 中可能存在的绑定循环。使用自定义模型时,可能需要实现类似的功能。
display
角色用于将组合框绑定到模型。edit
角色用于预填充编辑器对象。编辑器的onTextChanged
信号处理程序正在更新display
角色,这不会导致自身的绑定循环。如果处理程序正在更新edit
角色,则会通过 text
属性导致绑定循环。
关于 QML 中的模型
QML中有各种各样的"模型"。在内部,QML将几乎"任何东西"包装在一个模型中。任何内部不是QObject的东西仍然可以是一个模型(比如QVariant
),不会通知任何人任何事情。
例如,基于包装int
的QVariant
的"模型"不会发出通知,因为QVariant
不是可能发出更改信号的QObject
。
同样,如果你的"模型"绑定到从QObject
派生的类的属性值,但你未能emit
属性更改通知信号,它也不会工作。
如果不知道您的模型类型是什么,就无法分辨。
主.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"
}
}
}
主.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
工作正常,不会创建任何更新循环(因为它仅在"人工"/输入修改时调用)。
- 从C++实例化QML
- 使用CMake创建QML插件
- 如何将enable-if与模板参数和参数包一起使用
- 如何将PERF_AMPLE_READ与mmap一起使用
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- QT通过C++添加映射QML项目
- 如何在没有信号的情况下从C++执行QML插槽
- 如何将C++中的库和头与MinGW一起使用
- QML按钮点击功能执行顺序
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 为什么我不能将 rand() 与数组的大小一起使用?
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- QML:修改在不同QML文件(而非main.QML)中定义的子对象的属性
- 建议在运行时将带有类实例的列表从c++导入qml
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 将fold表达式与std::一起用于两个元组
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- QML:如何将动态创建的组件与自定义的内部对象一起使用
- 任何将非QObject类与QML一起使用的机会
- 如何将模型与 QML 一起使用