如何在QML的RowLayout中动态获取组件尺寸?
QML RowLayout内组件启动时宽度为0的问题解决
问题描述
尝试获取RowLayout内组件的宽度时,Component.onCompleted中得到的宽度为0,但调整窗口尺寸时能正常获取正确宽度,应用输出如下:
qml: onCompleted: rectangle width is 0 qml: onWidthChanged: rectangle width is 300 qml: onWidthChanged: rectangle width is 301 qml: onWidthChanged: rectangle width is 302 qml: onWidthChanged: rectangle width is 305 qml: onWidthChanged: rectangle width is 306 qml: onWidthChanged: rectangle width is 307
相关代码:
App.qml
import QtQuick 6.2 Window { width: 600 height: 400 visible: true Screen01 { id: mainScreen anchors.fill: parent } onWidthChanged: { console.log("onWidthChanged: rectangle width is " + mainScreen.rectangle2.width) } Component.onCompleted: { console.log("onCompleted: rectangle width is " + mainScreen.rectangle2.width) } }
Screen01.ui.qml
import QtQuick 6.2 import QtQuick.Layouts Rectangle { id: rectangle property alias rectangle2: rectangle2 RowLayout { id: rowLayout anchors.fill: parent spacing: 0 Rectangle { id: rectangle1 Layout.fillWidth: true Layout.fillHeight: true color: "red" } Rectangle { id: rectangle2 Layout.fillWidth: true Layout.fillHeight: true color: "yellow" } } }
原因分析
Component.onCompleted的触发时机是组件对象创建完毕,但此时Qt Quick的布局计算还没完成。RowLayout要等父组件的尺寸确定后,才会根据Layout.fillWidth这类属性计算子组件的实际宽高,所以在Component.onCompleted时,子组件的宽度还没被布局引擎赋值,自然显示为0。
而窗口尺寸调整时,布局引擎会重新计算所有布局内组件的尺寸,这时rectangle2的宽度已经被正确计算,所以能获取到有效值。
解决方法
下面几种方式可以在应用启动后可靠获取布局内组件的正确尺寸:
监听目标组件的
widthChanged信号:直接在rectangle2上监听宽度变化,第一次有效宽度赋值时就会触发,还能过滤掉初始的0值:
修改Screen01.ui.qml中的rectangle2:Rectangle { id: rectangle2 Layout.fillWidth: true Layout.fillHeight: true color: "yellow" onWidthChanged: { if (width > 0) { console.log("rectangle2 width is " + width) // 若只需要获取一次,可在这里断开信号 // widthChanged.disconnect(this.onWidthChanged) } } }用
Qt.callLater延迟执行:把获取尺寸的逻辑推迟到下一个事件循环,此时布局计算已完成:
修改App.qml的Component.onCompleted:Component.onCompleted: { Qt.callLater(function() { console.log("delayed: rectangle width is " + mainScreen.rectangle2.width) }) }监听布局的
layoutCompleted信号:Qt Quick Layouts自带layoutCompleted信号,布局完成计算后会触发,直接在RowLayout上监听即可:
修改Screen01.ui.qml的RowLayout:RowLayout { id: rowLayout anchors.fill: parent spacing: 0 onLayoutCompleted: { console.log("layout done: rectangle2 width is " + rectangle2.width) } // 子组件代码保持不变 }
内容的提问来源于stack exchange,提问作者e.n.shirokov
相关产品推荐
相关产品推荐

