如何在QML中设计多级流体布局

Isa*_*aac 12 layout qt fluid-layout qml

我在QML中设计了一个布局,以了解有关其功能的更多信息,并在设计此类布局时对"最佳实践"有一些疑问.这里是:

在此输入图像描述

它本质上是一个由三个RowLayout组成的ColumnLayout,每个RowLayout都有一些Rectangle s.应计算每个Row和Rectangle的大小,例如:

  • 第一行:高度= 40%,宽度= 100%
    • 红色矩形填充整个区域
  • 第二行:高度= 20%,宽度= 100%
    • 深绿色矩形:高度= 100%,宽度= 20%,
    • 浅绿色矩形:高度= 100%,宽度= 80%
  • 第三排:高度= 40%,宽度= 100%
    • 深蓝色矩形:高度= 100%,宽度= 40%,
    • 蓝色矩形:高度= 100%,宽度= 20%
    • 浅蓝色矩形:高度= 100%,宽度= 40%

我想出的QML正在发挥作用,如下所示.我有一些问题:

  1. 我使用Layout.preferredHeight:x*parent.height模式设置了宽度和高度百分比.其他选项导致一些问题(例如preferredHeight导致绑定循环警告).我的方法是正确有效的吗?
  2. 作为一个黑客,我为第2行和第3行的第一个元素设置了Layout.fillWidth:true,这对我来说没有意义,但确实有效.如果我将它们的宽度设置为百分比(例如Layout.preferredWidth:0.2*parent.width),它们的行将折叠为宽度0.这是预期的行为吗?有没有更好的解决方法?
  3. 你有关于布局的任何建议吗?我在正确的道路上吗?

这是我的布局QML代码:

ApplicationWindow {
    x: 500
    y: 100
    width: 250
    height: 150
    visible: true

    ColumnLayout {
        anchors.fill: parent
        spacing: 0
        RowLayout {
            spacing: 0
            Layout.preferredHeight: 0.4*parent.height
            Layout.fillHeight: false
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "red"
            }
        }
        RowLayout {
            spacing: 0
            Layout.preferredHeight: 0.2*parent.height
            Layout.fillHeight: false
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "darkGreen"
            }
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 0.8*parent.width
                color: "lightGreen"
            }
        }
        RowLayout {
            spacing: 0
            Layout.preferredHeight: 0.4*parent.height
            Layout.fillHeight: false
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "darkBlue"
            }
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 0.2*parent.width
                color: "blue"
            }
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 0.4*parent.width
                color: "lightBlue"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:

我的方法似乎比我预期的更加苛刻:

  1. Text元素作为子元素放在此布局中会引发绑定循环警告,如:

QML QQuickLayoutAttached:检测到属性"preferredWidth"的绑定循环

如果在Rectangle内部包装Text,则警告消失.

  1. 间距:0似乎发挥了重要的作用.省略它会导致绑定循环警告.

虽然我在QML中采用流体布局设计的方法有效,但它有一些严重的问题,可能不属于"最佳实践".

Mar*_* Ch 6

禁止(也是不必要的)尝试从布局内的项目中引用父级的宽度和高度。

fillWidth(或fillHeight)设置为时true,则将按其指定的preferredWidth(或preferredHeight)比例分配项目空间。

因此,创建布局的正确方法如下。我修改外观只是为了显示间距,Text也可以根据需要自由设置。没有绑定循环。

在此处输入图片说明 在此处输入图片说明

ApplicationWindow {
    x: 500
    y: 100
    width: 250
    height: 150
    visible: true

    ColumnLayout {
        anchors.fill: parent
        spacing: 5
        RowLayout {
            spacing: 5
            Layout.preferredHeight: 40
            Layout.fillHeight: true
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "red"
            }
        }
        RowLayout {
            spacing: 5
            Layout.preferredHeight: 20
            Layout.fillHeight: true
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 20
                Layout.fillWidth: true
                color: "darkGreen"
            }
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 80
                Layout.fillWidth: true
                color: "lightGreen"
            }
        }
        RowLayout {
            spacing: 5
            Layout.preferredHeight: 40
            Layout.fillHeight: true
            Text {
                Layout.fillHeight: true
                Layout.preferredWidth: 40
                Layout.fillWidth: true
                color: "darkBlue"
                text: "hello world!"
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 20
                Layout.fillWidth: true
                color: "blue"
            }
            Rectangle {
                Layout.fillHeight: true
                Layout.preferredWidth: 40
                Layout.fillWidth: true
                color: "lightBlue"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Blu*_*gma 5

QtQuick.Layout 没有对经典锚定系统提供任何真正的改进。我会建议避免它们。您可以使用锚点对布局进行更多控制。

这是没有 QtQuick.Layout 的完全相同的设计:

ApplicationWindow {
    x: 500
    y: 100
    width: 250
    height: 150
    visible: true

    Column {
        anchors.fill: parent

        Row {
            anchors.left: parent.left
            anchors.right: parent.right
            height: 0.4 * parent.height

            Rectangle {
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: parent.width
                color: "red"
            }
        }

        Row {
            anchors.left: parent.left
            anchors.right: parent.right
            height: 0.2 * parent.height

            Rectangle {
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: 0.2 * parent.width
                color: "darkGreen"
            }

            Rectangle {
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: 0.8 * parent.width
                color: "lightGreen"
            }
        }

        Row {
            anchors.left: parent.left
            anchors.right: parent.right
            height: 0.4 * parent.height

            Rectangle {
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: 0.4 * parent.width
                color: "darkBlue"
            }
            Rectangle {
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: 0.2 * parent.width
                color: "blue"
            }
            Rectangle {
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: 0.4 * parent.width
                color: "lightBlue"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我从未遇到过没有 QtQuick.Layout 就无法实现的设计。


Fou*_*Two 5

虽然其他两个答案都显示了有效的解决方案,但我相信所要提出的问题和两个解决方案都以某种方式错过了使用布局的意义。

基本上,布局是将具有隐式大小(implicitHeight / implicitWidth)的项目组合在一起的。Layout.preferredWidth / Layout.preferredHeight在某些罕见情况下用于覆盖这些内容,请参见下文。Qt附带的“ Qt快速布局-基本示例”根本不使用Layout.preferredWidth / Layout.preferredHeight(!),并且外观非常好,而不会用锚点或Layout属性污染整个qml文件。要做到这一点需要一些学习,但是一旦习惯了,布局是一种使用更少的代码更直接地定义用户界面的方法。

一开始最让我感到困惑的是以下几件事:

  • RowLayout / ColumnLayout / GridLayout的Layout.fillWidth / Layout.fillHeight设置为true,因此当将它们放置在Item / Rectangle附近时,Items / Rectangles突然消失,因为它们没有设置这些值(即,它们具有Layout。 fillWidth / Layout.fillHeight设置为false)。
  • 项目/矩形的隐式高度/隐式宽度为0,这意味着它们与Layouts并不能很好地并排使用。最好的办法是从包含的子项目中派生implicitWidth / implicitHeight,就​​像默认情况下,RowLayout / ColumnLayout本身为其子项目所做的那样。
  • Layout.preferredWidth / Layout.preferredHeight可用于克服已定义且无法设置的隐式大小。一个这样的地方直接在布局项中,另一个是例如Text项,它也不允许您覆盖隐式大小。

考虑到这些要点,我将以以下方式编写示例。我删除了不必要的项目,以更好地说明何时需要Layout.fillwidth / Layout.fillheight,以及我认为何时最好使用隐式宽度。

import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
    width: 250
    height: 150

    ColumnLayout {
        spacing: 0
        anchors.fill: parent
        Rectangle {
            implicitHeight: 40
            Layout.fillHeight: true
            Layout.fillWidth: true
            color: "red"
        }
        RowLayout {
            spacing: 0
            Layout.preferredHeight: 20
            Rectangle {
                implicitWidth: 20
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "darkGreen"
            }
            Rectangle {
                implicitWidth: 80
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "lightGreen"
            }
        }
        RowLayout {
            spacing: 0
            Layout.preferredHeight: 40
            Rectangle {
                implicitWidth: 40
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "darkBlue"
            }
            Rectangle {
                implicitWidth: 20
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "blue"
            }
            Rectangle {
                implicitWidth: 40
                Layout.fillHeight: true
                Layout.fillWidth: true
                color: "lightBlue"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)