为啥锚定到 ApplicationWindow 的项目的大小为零?

Posted

技术标签:

【中文标题】为啥锚定到 ApplicationWindow 的项目的大小为零?【英文标题】:Why do items anchored to the ApplicationWindow have a size of zero?为什么锚定到 ApplicationWindow 的项目的大小为零? 【发布时间】:2016-06-30 10:57:56 【问题描述】:

我需要一些像素完美的元素,以及其他应该可调整大小的元素,所以我尽量避免布局,只使用锚点。

如果我有一个固定大小的项目作为“主画布”,我可以通过锚定做任何必要的事情来实现我的目标。但是,它不适用于主窗口。如果我有一个锚定到主窗口的项目,它的大小报告为零

ApplicationWindow

    id: mainWindow
    width: 1024
    height: 768
    minimumWidth: 800
    minimumHeight: 480
    Component.onCompleted:  console.log("mainWindow width: " + width) 

    Item
    
        id: topLevelItem
        anchors.fill: parent
        Component.onCompleted:  console.log("topLevelItem width: " + width) 
    

有趣的是,topLevelItem 的宽度打印为0,而mainWindow 的宽度正确打印为1024

我添加了一些元素,现在变得很奇怪:

ApplicationWindow

    id: mainWindow
    width: 1024
    height: 768
    minimumWidth: 800
    minimumHeight: 480
    Component.onCompleted:  console.log("mainWindow width: " + width) 

    Item
    
        id: topLevelItem
        anchors.fill: parent
        Component.onCompleted:  console.log("topLevelItem width: " + width) 

        Rectangle
        
            id: red
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.left: parent.left

            width: 100
            color: "#FF0000"

            Component.onCompleted:  console.log("red width: " + width) 
        


        Rectangle
        
            id: green

            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.left: red.right
            anchors.right: blue.left

            color: "#00FF00"

            Component.onCompleted:  console.log("green width: " + width) 
        

        Rectangle
        
            id: blue

            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.right: parent.right

            width: 50
            color: "#0000FF"

            Component.onCompleted:  console.log("blue width: " + width) 
        

    


一切都按原样显示。左边有一个 100 px 的垂直红条,右边有一个 50 px 的垂直蓝条,其余的用绿色填充。

令人惊讶的是,尺寸不对:

qml: topLevelItem width: 0
qml: blue width: 50
qml: green width: -150
qml: red width: 100
qml: mainWindow width: 1024

mainWindow 外,所有内容的高度都报告为零。

我需要访问尺寸,尤其是中间区域的尺寸,因为它必须根据可用空间影响将放置什么样的其他元素。

这种奇怪行为的原因是什么,我做错了什么吗?如何正确获取中间矩形的大小?

【问题讨论】:

【参考方案1】:

QML 是一种声明性语言,这意味着如果您尝试过分依赖某些事物的评估顺序,您可能会发现自己与它作斗争。如果您在更改时打印出topLevelItemwidth,您会发现它最终是正确的:

import QtQuick 2.7
import QtQuick.Controls 1.0

ApplicationWindow 
    id: mainWindow
    width: 1024
    height: 768
    minimumWidth: 800
    minimumHeight: 480
    visible: true

    Component.onCompleted: console.log("mainWindow width: " + width)

    Item 
        id: topLevelItem
        anchors.fill: parent
        onWidthChanged: print("topLevelItem width: " + width)
        Component.onCompleted: console.log("topLevelItem width: " + width)
    

输出:

qml: topLevelItem width: 0
qml: mainWindow width: 1024
qml: topLevelItem width: 1024

我不确定到底发生了什么,但很可能是窗口首先获得了它的大小,然后告诉contentItem 它可以开始布置它的项目并给它们大小。这是异步发生的,也是在某些情况下不应依赖命令式代码的原因之一。

还值得指出的是,在使用布局时,您可以同时拥有像素完美的项目和可调整大小的项目;使用例如Layout.minimumWidthLayout.maximumWidth 强制使用某些尺寸。

【讨论】:

我知道没有严格的评估顺序会尊重声明的顺序,但我认为 onCompleted 只有在项目完全呈现后才会被调用。看来这是我的错误。

以上是关于为啥锚定到 ApplicationWindow 的项目的大小为零?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UIAlertController 操作表锚定到特定单元格 UICollectionView?

导航栏可以锚定到特定位置吗?

如何将视图锚定到 android 软键盘

如何将 Reality Composer (RealityKit) 场景锚定到检测到的图像

将项目锚定到屏幕中心并带有一些偏移

锚定到应用栏的 FAB 不会在向上滚动时隐藏