首页 文章

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

提问于
浏览
8

我在QML中设计了一个布局,以便更多地了解它的功能,并对设计这种布局的“最佳实践”提出一些问题 . 这里是:

enter image description here

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

  • 第一行:高度= 40%,宽度= 100%

  • 红色矩形填充整个区域

  • 第二行:高度= 20%,宽度= 100%

  • 深绿色矩形:高度= 100%,宽度= 20%,

  • 浅绿色矩形:高度= 100%,宽度= 80%

  • 第三行:高度= 40%,宽度= 100%

  • 深蓝色矩形:高度= 100%,宽度= 40%,

  • 蓝色矩形:高度= 100%,宽度= 20%

  • 浅蓝色矩形:高度= 100%,宽度= 40%

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

  • 我使用 Layout.preferredHeight: x*parent.height 模式设置了宽度和高度百分比 . 其他选项导致一些问题(例如preferredHeight导致绑定循环警告) . 我的方法是否正确有效?

  • 作为一个黑客,我为行#2和行#3的第一个元素设置 Layout.fillWidth: true ,这对我没有意义,但确实有效 . 如果我将宽度设置为百分比(例如 Layout.preferredWidth: 0.2*parent.width ),则其行将折叠为宽度0.这是预期的行为吗?有没有更好的解决方法?

  • 您对布局有什么建议吗?我在正确的道路上吗?

这是我的布局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"
            }
        }
    }
}

Update:

我的方法似乎比我预期的更黑客:

  • 在此布局中将 Text 元素作为子元素引发绑定循环警告,如:

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

如果 Rectangle 内的换行文本警告消失 .

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

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

3 回答

  • 3

    虽然其他两个答案都显示了有效的解决方案,但我相信这个问题和两个解决方案都错过了使用布局的重点 .

    基本上,使用布局将具有隐式大小的项(implicitHeight / implicitWidth)组合在一起 . Layout.preferredWidth / Layout.preferredHeight用于在极少数情况下覆盖这些内容,请参阅下文 . Qt附带的“Qt快速布局 - 基本示例”根本不使用Layout.preferredWidth / Layout.preferredHeight(!)并且看起来很漂亮,不会使用锚点或布局属性污染整个qml文件 . 需要一些学习才能自己做到这一点,但是一旦你习惯了它,Layouts就是一种用更少的代码更直接地定义用户界面的方法 .

    最让我困惑的是以下几点:

    • RowLayout / ColumnLayout / GridLayout将Layout.fillWidth / Layout.fillHeight设置为true,因此当将它们放在Item / Rectangle附近时,Items / Rectangles会突然消失,因为它们没有设置这些值(即它们有布局.fillWidth / Layout.fillHeight设置为false) .

    • Items / Rectangles的implicitHeight / implicitWidth为0,这意味着它们与Layouts并不真正并行 . 最好的办法是从包含的子项中派生implicitWidth / implicitHeight,就像RowLayout / ColumnLayout本身默认为其子项一样 .

    • Layout.preferredWidth / Layout.preferredHeight可用于克服已定义且无法设置的隐式大小 . 一个这样的地方直接在布局项目中,另一个例如是一个Text项,它也不允许您覆盖隐式大小 .

    考虑到这些要点,我将以下列方式编写示例 . 我删除了不必要的项目以更好地说明何时需要Layout.fillwidth / Layout.fillheight,以及何时最好在我看来使用implicitWidth .

    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"
                }
            }
        }
    }
    
  • 0

    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"
                }
            }
        }
    }
    

    到目前为止,我从未遇到任何没有QtQuick.Layout无法做到的设计 .

  • 4

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

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

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

    enter image description here

    enter image description here

    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"
                }
            }
        }
    }
    

相关问题