如何抓住QML Component完全布局的那一刻?

时间:2014-08-18 13:48:51

标签: qt qml

我在QML ApplicationWindow中有一个应该填充的GridView 与一些项目。

我用JS功能" placeItems"放置我的项目。 但问题是,当调用ApplicationWindow的Component.onCreated信号时,GridView尚未布局。 例如,GridView在ApplicationWindow的Component.onCreated中的x坐标等于-425。 如果我稍后再调用相同的函数 - 一切正常并且GridView 有正确的坐标(= 75)。

我来回检查Qt参考,并且找不到可能有用的其他信号(例如onLayouted或onLayoutComplete)。 问题是何时调用" placeItems"所以ApplicationWindow中的GridView 已经有正确的坐标?

UPDATE1: 要观察不良行为,请在应用程序启动后单击File-> Start。它会将物品放在正确的位置。

import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.1

ApplicationWindow {
    id: mainWindow

    width:1000
    height: 900
    color : "white"
    visible: true
    flags: Qt.Window

    function max (a,b) { return a>b ? a : b; }
    function min (a,b) { return a<b ? a : b; }

    property int sizeMin: width < height ? width : height

    property int dimField: sizeMin - 50
    property int dimCellSpacing: 3
    property int dimCell: (dimField / 5 ) - 1 - dimCellSpacing

    GridView {
        id: field
        anchors.centerIn: parent
        model: 20

        width: dimField
        height: dimField

        cellWidth: dimCell
        cellHeight: dimCell

        delegate: cell

        property var items: []

        function centerCell(column,row) {
            return {x: field.x + (column + 0.5) * cellWidth,
                y: field.y + (row + 0.5) * cellHeight}
        }

        function placeItem(name, col, row) {
            var c = centerCell(col,row)
            items[name].centerX = c.x
            items[name].centerY = c.y
        }

        function placeItems() {
            placeItem ("a", 3, 3)
            //placeItem ("b", 4, 4)
        }

    }

    Component.onCompleted: field.placeItems()

    Component {
        id: cell

        Rectangle {
            id: rectCell

            width: dimCell
            height: dimCell
            color: "lightgray"

            border.width: 3
            border.color: "brown"
        }
    }

    Rectangle
    {
        id: rectItemA

        property int dimItem: 100
        property int centerX: 0
        property int centerY: 0
        property int margin: 5
        property var cell: field.items["a"] = this
        border.color: "black"
        border.width: 3

        width: dimItem
        height: dimItem

        x: centerX - width/2
        y: centerY - height/2

        color: "red"
        opacity: 0.5
    }

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("Start")
                onTriggered: field.placeItems();
            }
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

    function placeItem(name, col, row) {
        items[name].anchors.horizontalCenter = field.left;
        items[name].anchors.verticalCenter = field.top;
        items[name].anchors.horizontalCenterOffset = (col + 0.5) * cellWidth;
        items[name].anchors.verticalCenterOffset = (row + 0.5) * cellHeight;
    }

关键是将元素锚定在网格视图中,然后根据您的计算移动它。

顺便说一句,你知道QML内置了函数Math.min / Math.max吗?

修改

或者更好的是,为什么不直接在rectItemA中定义绑定?

答案 1 :(得分:0)

为什么不延迟placeItems功能,因此它会以微小的延迟运行,以便在运行&#34;静态&#34;组件都已完成。

Timer {
        interval: 250 // might want to tune that
        repeat: false
        onTriggered: placeItems()
    }

在一个完美的世界中,Component.onCompleted将完美地嵌套,根项目将是最后一个要发射的项目。但遗憾的是Qt并不保证订单,事实上当我做了一个快速测试时,父项目在子项目之前发出(或至少响应)onCompleted

如果您不想使用计时器污染您的QML文件,您实际上可以实例化一个&#34;帮助对象&#34;从动态JS函数中,将其设置为完成其工​​作,然后在完成后自行删除。类似于&#34;重复帮手&#34;我在这个答案中概述了:Better way to reparent visual items in QML而是在计时器超时而不是在JS函数中删除它本身,这样就不会给它时间触发。

答案 2 :(得分:0)

另一种不那么具有正确行为的hackish方式(不要使用带有布局的Timer,真的,这是一个坏主意):

您将Rectangle定义为以属于GridView的项目实例为中心的项目。所以,我使用了一些你的方式(在gridview中的r行和c列中获取项目),然后我将Rectangle重新显示为此项目。要使其居中,只需将其锚定到新绑定的父级的中心。

import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.1

ApplicationWindow {
    id: mainWindow

    width:1000
    height: 900
    color : "white"
    visible: true
    flags: Qt.Window

    property int sizeMin: Math.min(width, height)

    property int dimField: sizeMin - 50
    property int dimCellSpacing: 3
    property int dimCell: (dimField / 5 ) - 1 - dimCellSpacing

    GridView {
        id: field
        anchors.centerIn: parent
        model: 20

        width: dimField
        height: dimField

        cellWidth: dimCell
        cellHeight: dimCell

        delegate: cell

        function cellAt(row, col) {
            return itemAt(row * (dimCell + dimCellSpacing), col * (dimCell + dimCellSpacing));
        }
    }

    Component {
        id: cell

        Rectangle {
            id: rectCell

            width: dimCell
            height: dimCell
            color: "lightgray"

            border.width: 3
            border.color: "brown"
        }
    }

    Rectangle
    {
        id: rectItemA

        property int dimItem: 100
        property int margin: 5
        border.color: "black"
        border.width: 3

        width: dimItem
        height: dimItem

        anchors.centerIn: parent

        color: "red"
        opacity: 0.5
    }

    Component.onCompleted: {
        rectItemA.parent = field.cellAt(3, 3);
    }

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }
}