属性 绑定未按预期与 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

但结果是一样的

因此,我的问题是:

  1. 如何从 ListView/ListModel 向 ChartItem 传递值?作为第一步,我想使用 ChartItem 作为 CandlestickItem 的容器重现工作示例,然后根据需要在 ChartItem 中添加更多元素
  2. 通过 属性 绑定传递模型似乎不起作用,但从模型传递每个相关值也不起作用。是否可以传递整个对象?例如,我可以像这样将整个视图作为 属性 传递:property ListView view 然后引用其字段:view.model.ts 吗?我已经试过了,但没有成功
  3. 此处出现的问题是否可能与 lifetimes/times 创建委托和视图有关?如果是这样,我应该如何构建代码以避免此类问题?

感谢您的阅读和帮助。

事实证明,这个问题比我想象的要简单。

  1. 解决属性 名称冲突。用 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
        ...
    }
  1. 是也不是。是的,如果它是一个对象。适用于 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 有特殊含义,不应该这样使用,但希望被证明是错误的。

  1. 没有