通过另一个转发器中的复选框控制转发器中的项目 "enabled" 属性
Controling an Item "enabled" property in a repeater from a checkbox in another repeater
这听起来很容易,但它并没有像我预期的那样工作。
我有一个带复选框的中继器,垂直放置。
然后我有一个组合框网格。
我希望在选中相应的复选框时禁用组合框。
这是代码的摘录:
Repeater {
id: idChkUseChordNotes
model: _max_patterns
SmallCheckBox {
onClicked: {
console.log("Clicked at " + index + "!! ==> " + idChkUseChordNotes.itemAt(index).checked);
// attempt to force a refresh of the idStepNotes repeater => No effect
//resetP=false;
//resetP=true;
}
}
}
Repeater {
id: idStepNotes
model: getPatterns(resetP)
StackLayout {
width: parent.width
currentIndex: modeIndex()
property int stepIndex: index % _max_steps
property int patternIndex: Math.floor(index / _max_steps)
Label {
text: "dummy"
}
ComboBox {
id: lstGStep
property var step: patterns[patternIndex * _max_steps + stepIndex]
editable: false
enabled: !idChkUseChordNotes.itemAt(patternIndex).checked
model: _ddGridNotes
currentIndex: find(step.degree, Qt.MatchExactly)
onCurrentIndexChanged: {
step.degree = model[currentIndex];
// debug
console.log(idChkUseChordNotes.itemAt(patternIndex).checked); // <-- working fine
}
}
}
}
虽然组合框可以访问正确的复选框(请参阅“onCurrentIndexChanged”中的“调试”),但选中和关闭复选框不会影响组合框 属性。
我知道 QML 在 属性 绑定级别上有一些限制。我不知道这是否是这里的问题。
重要提示:我仅限于这些版本:QtQuick 2.9 和 QtQuick.Controls 2.2
您应该会看到一堆这样的警告:TypeError: Cannot read property 'checked' of null
。令人惊讶的是(根据您的评论)您没有。在绑定被评估时,复选框还没有被实例化。解决这个问题需要各种 Component.onCompleted
处理程序中的程序代码,正如您已经在评论中指出的那样。但是,这不是 QML 的预期使用方式。
与其根据 UI 元素相互作用来考虑问题,不如考虑更 data-centric 的方法。复选框和组合框实际上只是同一组数据的不同视图或方面。每个数据点都有一个布尔方面(或 Qt 术语中的 属性)“使用和弦音符”和另一个方面(“程度”?)具有另一种含义。复选框是布尔方面的视觉和可交互表示,组合框对另一个方面做同样的事情,但使用第一个来决定交互性。
在代码中表示这种结构的 Qt/QML 方法是通过视图、绑定和模型。我已经模拟了一个示例,说明如何使用您的代码段作为起点。请注意这里没有声明性代码(按钮的 onClicked 处理程序除外,但那只是为了说明目的)。
有几点需要注意:
- 为了简单起见,这里的模型是一个QML
ListModel
。在 real-world 应用程序中,这很可能是用 C++ 实现的。
- 复选框和组合框都使用 two-way 绑定来确保它们的状态始终与模型 up-to-date 一致,即使模型由于其他原因发生更改也是如此。第三列中的按钮说明了这一点。如果不需要这个,
Binding
对象可以用简单的绑定表达式替换:checked: useChordNotes
.
- combobox上的
currentIndex
绑定使用了这里作为模型的JS数组的indexOf
方法。在您的代码中,必须将其替换为适用于 _ddGridNotes
具有的任何类型的内容。 ComboBox.find()
在这里不起作用,因为初始化顺序。在 Binding
构造后第一次被评估的那一刻,组合框尚未实例化其项目,因此对于任何对 find
的调用总是返回 -1。这与您原来的问题类似。
代码
import QtQuick 2.9
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.2
import QtQuick.Window 2.9
Window {
width: 640
height: 480
visible: true
ListModel {
id: patterns
ListElement {
useChordNotes: false
gridNote: "1"
}
ListElement {
useChordNotes: true
gridNote: "3"
}
ListElement {
useChordNotes: false
gridNote: "2"
}
}
RowLayout {
anchors.fill: parent
ColumnLayout {
Repeater {
id: idChkUseChordNotes
model: patterns
CheckBox {
// Use a two-way binding here, in case something else in the program changes the model (e.g. loading a file)
// #1: change model value on user interaction
onCheckedChanged: useChordNotes = checked
// #2: update value on model change from another source
Binding on checked {
value: useChordNotes
}
}
}
}
ColumnLayout {
Repeater {
id: idStepNotes
model: patterns
ComboBox {
id: lstGStep
enabled: !useChordNotes
model: ["1", "2", "3"]
onActivated: gridNote = currentValue
Binding on currentIndex {
// Replace this to something that works with whatever type lstGStep.model might be
value: lstGStep.model.indexOf(gridNote)
}
}
}
}
ColumnLayout {
Repeater {
model: patterns
Button {
text: "useChordNotes: " + (useChordNotes ? "true" : "false") + "; gridNote: " + gridNote
onClicked: {
gridNote = "3";
useChordNotes = !useChordNotes;
}
}
}
}
}
}
这听起来很容易,但它并没有像我预期的那样工作。
我有一个带复选框的中继器,垂直放置。 然后我有一个组合框网格。 我希望在选中相应的复选框时禁用组合框。
这是代码的摘录:
Repeater {
id: idChkUseChordNotes
model: _max_patterns
SmallCheckBox {
onClicked: {
console.log("Clicked at " + index + "!! ==> " + idChkUseChordNotes.itemAt(index).checked);
// attempt to force a refresh of the idStepNotes repeater => No effect
//resetP=false;
//resetP=true;
}
}
}
Repeater {
id: idStepNotes
model: getPatterns(resetP)
StackLayout {
width: parent.width
currentIndex: modeIndex()
property int stepIndex: index % _max_steps
property int patternIndex: Math.floor(index / _max_steps)
Label {
text: "dummy"
}
ComboBox {
id: lstGStep
property var step: patterns[patternIndex * _max_steps + stepIndex]
editable: false
enabled: !idChkUseChordNotes.itemAt(patternIndex).checked
model: _ddGridNotes
currentIndex: find(step.degree, Qt.MatchExactly)
onCurrentIndexChanged: {
step.degree = model[currentIndex];
// debug
console.log(idChkUseChordNotes.itemAt(patternIndex).checked); // <-- working fine
}
}
}
}
虽然组合框可以访问正确的复选框(请参阅“onCurrentIndexChanged”中的“调试”),但选中和关闭复选框不会影响组合框 属性。
我知道 QML 在 属性 绑定级别上有一些限制。我不知道这是否是这里的问题。
重要提示:我仅限于这些版本:QtQuick 2.9 和 QtQuick.Controls 2.2
您应该会看到一堆这样的警告:TypeError: Cannot read property 'checked' of null
。令人惊讶的是(根据您的评论)您没有。在绑定被评估时,复选框还没有被实例化。解决这个问题需要各种 Component.onCompleted
处理程序中的程序代码,正如您已经在评论中指出的那样。但是,这不是 QML 的预期使用方式。
与其根据 UI 元素相互作用来考虑问题,不如考虑更 data-centric 的方法。复选框和组合框实际上只是同一组数据的不同视图或方面。每个数据点都有一个布尔方面(或 Qt 术语中的 属性)“使用和弦音符”和另一个方面(“程度”?)具有另一种含义。复选框是布尔方面的视觉和可交互表示,组合框对另一个方面做同样的事情,但使用第一个来决定交互性。
在代码中表示这种结构的 Qt/QML 方法是通过视图、绑定和模型。我已经模拟了一个示例,说明如何使用您的代码段作为起点。请注意这里没有声明性代码(按钮的 onClicked 处理程序除外,但那只是为了说明目的)。
有几点需要注意:
- 为了简单起见,这里的模型是一个QML
ListModel
。在 real-world 应用程序中,这很可能是用 C++ 实现的。 - 复选框和组合框都使用 two-way 绑定来确保它们的状态始终与模型 up-to-date 一致,即使模型由于其他原因发生更改也是如此。第三列中的按钮说明了这一点。如果不需要这个,
Binding
对象可以用简单的绑定表达式替换:checked: useChordNotes
. - combobox上的
currentIndex
绑定使用了这里作为模型的JS数组的indexOf
方法。在您的代码中,必须将其替换为适用于_ddGridNotes
具有的任何类型的内容。ComboBox.find()
在这里不起作用,因为初始化顺序。在Binding
构造后第一次被评估的那一刻,组合框尚未实例化其项目,因此对于任何对find
的调用总是返回 -1。这与您原来的问题类似。
代码
import QtQuick 2.9
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.2
import QtQuick.Window 2.9
Window {
width: 640
height: 480
visible: true
ListModel {
id: patterns
ListElement {
useChordNotes: false
gridNote: "1"
}
ListElement {
useChordNotes: true
gridNote: "3"
}
ListElement {
useChordNotes: false
gridNote: "2"
}
}
RowLayout {
anchors.fill: parent
ColumnLayout {
Repeater {
id: idChkUseChordNotes
model: patterns
CheckBox {
// Use a two-way binding here, in case something else in the program changes the model (e.g. loading a file)
// #1: change model value on user interaction
onCheckedChanged: useChordNotes = checked
// #2: update value on model change from another source
Binding on checked {
value: useChordNotes
}
}
}
}
ColumnLayout {
Repeater {
id: idStepNotes
model: patterns
ComboBox {
id: lstGStep
enabled: !useChordNotes
model: ["1", "2", "3"]
onActivated: gridNote = currentValue
Binding on currentIndex {
// Replace this to something that works with whatever type lstGStep.model might be
value: lstGStep.model.indexOf(gridNote)
}
}
}
}
ColumnLayout {
Repeater {
model: patterns
Button {
text: "useChordNotes: " + (useChordNotes ? "true" : "false") + "; gridNote: " + gridNote
onClicked: {
gridNote = "3";
useChordNotes = !useChordNotes;
}
}
}
}
}
}