以编程方式重新配置 QML 控件
Reconfiguring QML controls programatically
所以,我正在开发一个 Qt Quick (QML) 应用程序,我有这个特殊的任务:
该应用程序将处理不同类型的设备,并非所有设备都具有相同的特性。例如,由于这些是 SDR 设备,一个可以需要一个增益滑块,而另一个有 3 个独立的。
后端将读取设备并知道此信息:有多少个阶段以及它们的范围是多少。所以我需要根据需要查看 create/destroy/readjust 滑块。
实现这种想法的最干净的方法是什么?直接从 C++ 访问 QML 元素似乎非常令人沮丧。
一般来说,配置总是有一些确定的特征,必须有:
- 每个项目或对象都可以访问
- 广播更改事件
- 独立于消费者
- 默认值
...
根据我们的个人经验,我们总是创建一个 C++ 单例对象并创建配置值 属性(Q属性) 并将它们作为上下文 属性 发送到 QML 引擎(QQmlContext::setContext属性())。
所有 QML 项目都是自己绑定的 属性。当必须更改配置值时,所有项目都可以知道此更改,然后自己进行更新。
这里没有太多信息,所以我的回答主要是未经测试的伪代码。
阅读您的评论后更新的答案:
我会有一个 DeviceManager
来存储插入的每个设备的列表。DeviceModel
会监听该列表中的变化,并公开一个 device
角色(你也可以为设备的每个 属性 分配一个角色)。创建一个 DeviceUI.qml
代表每个设备的公共部分,并在其中有一个像 @eyllanesc 提到的 Repeater
来枚举由 DeviceGainModel
代表的每个“增益”类型:
// DeviceUi.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 2.15
GroupBox {
id: root
title: device.displayName
required property var device
ColumnLayout {
anchors.fill: parent
Repeater {
model: DeviceGainModel {
device: root.device
}
delegate: RowLayout {
Label {
text: model.gainDisplayName
}
Slider {
value: model.gain
onMoved: model.gain = value
}
}
}
}
}
// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 2.15
import MyApp 1.0
ApplicationWindow {
id: window
width: 640
height: 480
visible: true
required property DeviceManager deviceManager
ColumnLayout {
Repeater {
model: DeviceModel {
deviceManager: window.deviceManager
}
delegate: DeviceUi {
// Set via model roles.
required property var device
}
}
}
}
这样,您的域逻辑对 UI 一无所知(即不从 C++ 访问 QML)。
所以,我正在开发一个 Qt Quick (QML) 应用程序,我有这个特殊的任务:
该应用程序将处理不同类型的设备,并非所有设备都具有相同的特性。例如,由于这些是 SDR 设备,一个可以需要一个增益滑块,而另一个有 3 个独立的。
后端将读取设备并知道此信息:有多少个阶段以及它们的范围是多少。所以我需要根据需要查看 create/destroy/readjust 滑块。
实现这种想法的最干净的方法是什么?直接从 C++ 访问 QML 元素似乎非常令人沮丧。
一般来说,配置总是有一些确定的特征,必须有:
- 每个项目或对象都可以访问
- 广播更改事件
- 独立于消费者
- 默认值 ...
根据我们的个人经验,我们总是创建一个 C++ 单例对象并创建配置值 属性(Q属性) 并将它们作为上下文 属性 发送到 QML 引擎(QQmlContext::setContext属性())。 所有 QML 项目都是自己绑定的 属性。当必须更改配置值时,所有项目都可以知道此更改,然后自己进行更新。
这里没有太多信息,所以我的回答主要是未经测试的伪代码。
阅读您的评论后更新的答案:
我会有一个 DeviceManager
来存储插入的每个设备的列表。DeviceModel
会监听该列表中的变化,并公开一个 device
角色(你也可以为设备的每个 属性 分配一个角色)。创建一个 DeviceUI.qml
代表每个设备的公共部分,并在其中有一个像 @eyllanesc 提到的 Repeater
来枚举由 DeviceGainModel
代表的每个“增益”类型:
// DeviceUi.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 2.15
GroupBox {
id: root
title: device.displayName
required property var device
ColumnLayout {
anchors.fill: parent
Repeater {
model: DeviceGainModel {
device: root.device
}
delegate: RowLayout {
Label {
text: model.gainDisplayName
}
Slider {
value: model.gain
onMoved: model.gain = value
}
}
}
}
}
// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 2.15
import MyApp 1.0
ApplicationWindow {
id: window
width: 640
height: 480
visible: true
required property DeviceManager deviceManager
ColumnLayout {
Repeater {
model: DeviceModel {
deviceManager: window.deviceManager
}
delegate: DeviceUi {
// Set via model roles.
required property var device
}
}
}
}
这样,您的域逻辑对 UI 一无所知(即不从 C++ 访问 QML)。