属性 绑定未按预期与 ListView + Delegate(嵌套项目)一起工作
Property bindings not working as expected with ListView + Delegate (nested items)
我正在用 QML 编写一个简单的烛台图表程序。数据被建模为列表。无论时间戳差异如何(即 x 轴上没有间隙),元素都会一个接一个地绘制。这是故意的。
这个简单的模型按预期使用以下示例代码工作:
import QtQuick 2.0
Item {
// dimensions arbitrary
height: 1000
width: 400
property int bar_spacing: 1
// example dimensions of the y axis, axis omitted for simplicity
// used to position candlesticks vertically
property real y_axis_px_per_unit: 720/360
property real y_axis_max: 660
property int bar_min_width: 10
Component {
id: candlestickItem
Candlestick {
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
px_per_unit: y_axis_px_per_unit
axis_max: y_axis_max
min_width: bar_min_width
// each candlestick scaled to fill listview, min_width is
// the scaling limit (if the candle_width calculation
// results in smaller candles than min_width, then
// min_width is used and listview has a horizontal scrollbar)
candle_width: {
// Total width - spaces between elements - left margin
(candles_view.implicitWidth - candles_view.count * candles_view.spacing - candles_view.spacing) / candles_view.count
}
}
}
ListView {
id: candles_view
model: ticks
delegate: candlestickItem
implicitHeight: parent.height
implicitWidth: parent.width
anchors.fill: parent
anchors.leftMargin: bar_spacing
clip: true
orientation: ListView.Horizontal
layoutDirection: "LeftToRight"
spacing: bar_spacing
}
ListModel {
id: ticks
ListElement { ts: '2020-01-01 00:00:00'; open: 608.4900; high: 615.0000; low: 515.0000; close: 519.0000; }
ListElement { ts: '2020-01-02 00:00:00'; open: 631.2650; high: 653.6500; low: 553.0000; close: 631.2732; }
ListElement { ts: '2020-01-03 00:00:00'; open: 562.0000; high: 608.0000; low: 508.0000; close: 534.0000; }
ListElement { ts: '2020-01-04 00:00:00'; open: 506.5000; high: 505.0100; low: 405.0000; close: 453.0001; }
ListElement { ts: '2020-01-05 00:00:00'; open: 472.0000; high: 484.0000; low: 384.0000; close: 407.5601; }
ListElement { ts: '2020-01-06 00:00:00'; open: 403.0000; high: 404.8600; low: 304.0000; close: 373.0000; }
ListElement { ts: '2020-01-07 00:00:00'; open: 365.0000; high: 451.9900; low: 351.0000; close: 394.0000; }
ListElement { ts: '2020-01-08 00:00:00'; open: 447.9500; high: 477.0000; low: 377.0000; close: 423.7800; }
}
}
生成一个非常基本但正确的图表:
我想通过将烛台放在另一个项目中来扩展它,一个“容器”(不是 QML 意义上的),它也可以包含其他项目,例如在蜡烛上绘制的线条、直方图等。但是,当我创建一个新的 QML 项目时,图表不再起作用:
import QtQuick 2.0
Item {
height: 1000
width: 400
property int bar_spacing: 1
property real y_axis_px_per_unit: 720/360
property real y_axis_max: 660
property int bar_min_width: 10
Component {
id: chartItemDelegate
ChartItem {
model: model
count: candles_view.count
spacing: bar_spacing
view_width: candles_view.implicitWidth
y_axis_max: y_axis_max
y_axis_px_per_unit: y_axis_px_per_unit
bar_min_width: bar_min_width
}
}
ListView {
id: candles_view
model: ticks
delegate: chartItemDelegate
implicitHeight: parent.height
implicitWidth: parent.width
anchors.fill: parent
anchors.leftMargin: bar_spacing
clip: true
orientation: ListView.Horizontal
layoutDirection: "LeftToRight"
spacing: bar_spacing
}
ListModel {
id: ticks
ListElement { ts: '2020-01-01 00:00:00'; open: 608.4900; high: 615.0000; low: 515.0000; close: 519.0000; }
ListElement { ts: '2020-01-02 00:00:00'; open: 631.2650; high: 653.6500; low: 553.0000; close: 631.2732; }
ListElement { ts: '2020-01-03 00:00:00'; open: 562.0000; high: 608.0000; low: 508.0000; close: 534.0000; }
ListElement { ts: '2020-01-04 00:00:00'; open: 506.5000; high: 505.0100; low: 405.0000; close: 453.0001; }
ListElement { ts: '2020-01-05 00:00:00'; open: 472.0000; high: 484.0000; low: 384.0000; close: 407.5601; }
ListElement { ts: '2020-01-06 00:00:00'; open: 403.0000; high: 404.8600; low: 304.0000; close: 373.0000; }
ListElement { ts: '2020-01-07 00:00:00'; open: 365.0000; high: 451.9900; low: 351.0000; close: 394.0000; }
ListElement { ts: '2020-01-08 00:00:00'; open: 447.9500; high: 477.0000; low: 377.0000; close: 423.7800; }
}
}
ChartItem.qml
import QtQuick 2.0
Item {
property ListModel model
property real y_axis_px_per_unit
property real y_axis_max
property int bar_min_width
property int view_width
property int spacing
property int count
id: chart_item
implicitWidth: candlestick.implicitWidth
implicitHeight: candlestick.implicitHeight
Candlestick {
id: candlestick
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
px_per_unit: y_axis_px_per_unit
axis_max: y_axis_max
min_width: bar_min_width
candle_width: {
// Total width - spaces between elements - left margin
(view_width - count * spacing - spacing) / count
}
}
}
结果是 window 带有 1 个像素高的黄线,这意味着用于定位柱的模型和轴尺寸都没有传递到烛台项目:
我试过在 QtCreator 中调试它,但不明白为什么它不起作用。我还尝试像最初使用烛台一样从模型中传递每个值:
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
但结果是一样的
因此,我的问题是:
- 如何从 ListView/ListModel 向 ChartItem 传递值?作为第一步,我想使用 ChartItem 作为 CandlestickItem 的容器重现工作示例,然后根据需要在 ChartItem 中添加更多元素
- 通过 属性 绑定传递模型似乎不起作用,但从模型传递每个相关值也不起作用。是否可以传递整个对象?例如,我可以像这样将整个视图作为 属性 传递:
property ListView view
然后引用其字段:view.model.ts
吗?我已经试过了,但没有成功
- 此处出现的问题是否可能与 lifetimes/times 创建委托和视图有关?如果是这样,我应该如何构建代码以避免此类问题?
感谢您的阅读和帮助。
事实证明,这个问题比我想象的要简单。
- 解决属性 名称冲突。用
model
和 Item 的 id 限定每个绑定的 rhs 值,或者完全使用不同的 属性 名称。我更喜欢更明确:
ChartItem {
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
view: candles_view
y_axis_max: y_axis_max
y_axis_px_per_unit: y_axis_px_per_unit
bar_min_width: bar_min_width
}
ChartItem.qml
Candlestick {
id: candlestick
ts: chart_item.ts
open: chart_item.open
high: chart_item.high
low: chart_item.low
close: chart_item.close
...
}
- 是也不是。是的,如果它是一个对象。适用于
view
,因为它是一个对象。
定义属性:
property ListView view
创建项目时绑定一个值:
view: candles_view
在项目中使用:
candle_width:
{
// Total width - spaces between elements - left margin
(view.implicitWidth - view.count * view.spacing - view.spacing) / view.count
}
它不适用于 model
。我的理解是 model 有特殊含义,不应该这样使用,但希望被证明是错误的。
- 没有
我正在用 QML 编写一个简单的烛台图表程序。数据被建模为列表。无论时间戳差异如何(即 x 轴上没有间隙),元素都会一个接一个地绘制。这是故意的。 这个简单的模型按预期使用以下示例代码工作:
import QtQuick 2.0
Item {
// dimensions arbitrary
height: 1000
width: 400
property int bar_spacing: 1
// example dimensions of the y axis, axis omitted for simplicity
// used to position candlesticks vertically
property real y_axis_px_per_unit: 720/360
property real y_axis_max: 660
property int bar_min_width: 10
Component {
id: candlestickItem
Candlestick {
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
px_per_unit: y_axis_px_per_unit
axis_max: y_axis_max
min_width: bar_min_width
// each candlestick scaled to fill listview, min_width is
// the scaling limit (if the candle_width calculation
// results in smaller candles than min_width, then
// min_width is used and listview has a horizontal scrollbar)
candle_width: {
// Total width - spaces between elements - left margin
(candles_view.implicitWidth - candles_view.count * candles_view.spacing - candles_view.spacing) / candles_view.count
}
}
}
ListView {
id: candles_view
model: ticks
delegate: candlestickItem
implicitHeight: parent.height
implicitWidth: parent.width
anchors.fill: parent
anchors.leftMargin: bar_spacing
clip: true
orientation: ListView.Horizontal
layoutDirection: "LeftToRight"
spacing: bar_spacing
}
ListModel {
id: ticks
ListElement { ts: '2020-01-01 00:00:00'; open: 608.4900; high: 615.0000; low: 515.0000; close: 519.0000; }
ListElement { ts: '2020-01-02 00:00:00'; open: 631.2650; high: 653.6500; low: 553.0000; close: 631.2732; }
ListElement { ts: '2020-01-03 00:00:00'; open: 562.0000; high: 608.0000; low: 508.0000; close: 534.0000; }
ListElement { ts: '2020-01-04 00:00:00'; open: 506.5000; high: 505.0100; low: 405.0000; close: 453.0001; }
ListElement { ts: '2020-01-05 00:00:00'; open: 472.0000; high: 484.0000; low: 384.0000; close: 407.5601; }
ListElement { ts: '2020-01-06 00:00:00'; open: 403.0000; high: 404.8600; low: 304.0000; close: 373.0000; }
ListElement { ts: '2020-01-07 00:00:00'; open: 365.0000; high: 451.9900; low: 351.0000; close: 394.0000; }
ListElement { ts: '2020-01-08 00:00:00'; open: 447.9500; high: 477.0000; low: 377.0000; close: 423.7800; }
}
}
生成一个非常基本但正确的图表:
我想通过将烛台放在另一个项目中来扩展它,一个“容器”(不是 QML 意义上的),它也可以包含其他项目,例如在蜡烛上绘制的线条、直方图等。但是,当我创建一个新的 QML 项目时,图表不再起作用:
import QtQuick 2.0
Item {
height: 1000
width: 400
property int bar_spacing: 1
property real y_axis_px_per_unit: 720/360
property real y_axis_max: 660
property int bar_min_width: 10
Component {
id: chartItemDelegate
ChartItem {
model: model
count: candles_view.count
spacing: bar_spacing
view_width: candles_view.implicitWidth
y_axis_max: y_axis_max
y_axis_px_per_unit: y_axis_px_per_unit
bar_min_width: bar_min_width
}
}
ListView {
id: candles_view
model: ticks
delegate: chartItemDelegate
implicitHeight: parent.height
implicitWidth: parent.width
anchors.fill: parent
anchors.leftMargin: bar_spacing
clip: true
orientation: ListView.Horizontal
layoutDirection: "LeftToRight"
spacing: bar_spacing
}
ListModel {
id: ticks
ListElement { ts: '2020-01-01 00:00:00'; open: 608.4900; high: 615.0000; low: 515.0000; close: 519.0000; }
ListElement { ts: '2020-01-02 00:00:00'; open: 631.2650; high: 653.6500; low: 553.0000; close: 631.2732; }
ListElement { ts: '2020-01-03 00:00:00'; open: 562.0000; high: 608.0000; low: 508.0000; close: 534.0000; }
ListElement { ts: '2020-01-04 00:00:00'; open: 506.5000; high: 505.0100; low: 405.0000; close: 453.0001; }
ListElement { ts: '2020-01-05 00:00:00'; open: 472.0000; high: 484.0000; low: 384.0000; close: 407.5601; }
ListElement { ts: '2020-01-06 00:00:00'; open: 403.0000; high: 404.8600; low: 304.0000; close: 373.0000; }
ListElement { ts: '2020-01-07 00:00:00'; open: 365.0000; high: 451.9900; low: 351.0000; close: 394.0000; }
ListElement { ts: '2020-01-08 00:00:00'; open: 447.9500; high: 477.0000; low: 377.0000; close: 423.7800; }
}
}
ChartItem.qml
import QtQuick 2.0
Item {
property ListModel model
property real y_axis_px_per_unit
property real y_axis_max
property int bar_min_width
property int view_width
property int spacing
property int count
id: chart_item
implicitWidth: candlestick.implicitWidth
implicitHeight: candlestick.implicitHeight
Candlestick {
id: candlestick
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
px_per_unit: y_axis_px_per_unit
axis_max: y_axis_max
min_width: bar_min_width
candle_width: {
// Total width - spaces between elements - left margin
(view_width - count * spacing - spacing) / count
}
}
}
结果是 window 带有 1 个像素高的黄线,这意味着用于定位柱的模型和轴尺寸都没有传递到烛台项目:
我试过在 QtCreator 中调试它,但不明白为什么它不起作用。我还尝试像最初使用烛台一样从模型中传递每个值:
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
但结果是一样的
因此,我的问题是:
- 如何从 ListView/ListModel 向 ChartItem 传递值?作为第一步,我想使用 ChartItem 作为 CandlestickItem 的容器重现工作示例,然后根据需要在 ChartItem 中添加更多元素
- 通过 属性 绑定传递模型似乎不起作用,但从模型传递每个相关值也不起作用。是否可以传递整个对象?例如,我可以像这样将整个视图作为 属性 传递:
property ListView view
然后引用其字段:view.model.ts
吗?我已经试过了,但没有成功 - 此处出现的问题是否可能与 lifetimes/times 创建委托和视图有关?如果是这样,我应该如何构建代码以避免此类问题?
感谢您的阅读和帮助。
事实证明,这个问题比我想象的要简单。
- 解决属性 名称冲突。用
model
和 Item 的 id 限定每个绑定的 rhs 值,或者完全使用不同的 属性 名称。我更喜欢更明确:
ChartItem {
ts: model.ts
open: model.open
high: model.high
low: model.low
close: model.close
view: candles_view
y_axis_max: y_axis_max
y_axis_px_per_unit: y_axis_px_per_unit
bar_min_width: bar_min_width
}
ChartItem.qml
Candlestick {
id: candlestick
ts: chart_item.ts
open: chart_item.open
high: chart_item.high
low: chart_item.low
close: chart_item.close
...
}
- 是也不是。是的,如果它是一个对象。适用于
view
,因为它是一个对象。
定义属性:
property ListView view
创建项目时绑定一个值:
view: candles_view
在项目中使用:
candle_width:
{
// Total width - spaces between elements - left margin
(view.implicitWidth - view.count * view.spacing - view.spacing) / view.count
}
它不适用于 model
。我的理解是 model 有特殊含义,不应该这样使用,但希望被证明是错误的。
- 没有