RowLayout пример fillWidth:true
Home Qt Qt QML nested Layouts, Layout.fillWidth: true не работает, и как быть с Layout.alignment

Qt QML nested Layouts, Layout.fillWidth: true не работает, и как быть с Layout.alignment

by Pavelk
RowLayout c работающим fillWidth:true

Постоянно сталкиваюсь, что многие не учитывают некоторые нюансы работы Layout, а именно когда дело касается вложенных, например RowLayout в ColumnLayout, тогда если выставить у RowLayout свойство Layout.fillWidth: true , то оно ведёт себя странно (на первый взгляд), а именно как будто бы не работает и вложенный RowLayout не принимает всю доступную ширину ColumnLayout.

Если коротко, решение:

Layout.maximumWidth: Number.POSITIVE_INFINITY

А теперь подробнее почему.
Напишу пример для наглядности, где нам нужно будет прямоугольники выровнять по левому, центру и правому краю.

import QtQuick
import QtQuick.Layouts

Window {
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")
  color: "#292929"

  Rectangle {
    color: "#5f5f5f"
    width: parent.width*0.5
    height: parent.height
    anchors.horizontalCenter: parent.horizontalCenter

    ColumnLayout {
      id: mainLayout
      anchors.fill: parent

      RowLayout {
        id: nestedRowLayout
        Layout.fillWidth: true

        Rectangle {
          id: rectLeft
          color: "red"
          implicitWidth: 80
          implicitHeight: 80
          Layout.alignment: Qt.AlignLeft

          Text {
            text: "Left"
            anchors.centerIn: parent
          }
        }

        Rectangle {
          id: rectMiddle
          color: "red"
          implicitWidth: 80
          implicitHeight: 80
          Layout.alignment: Qt.AlignHCenter

          Text {
            text: "Center"
            anchors.centerIn: parent
          }
        }

        Rectangle {
          id: rectRight
          color: "red"
          implicitWidth: 80
          implicitHeight: 80
          Layout.alignment: Qt.AlignRight

          Text {
            text: "Right"
            anchors.centerIn: parent
          }
        }
      }
    }
  }
}

Результат выглядит так:

RowLayout пример странного поведения

Всё внимание на id: nestedRowLayout, казалось бы стоит Layout.fillWidth: true и если следовать логике, которая прописана в документации на Layout.fillWidth: true, то RowLayout должна была заполнить всю ширину, но этого не происходит.

На этом моменте многие сразу между прямоугольниками начинают вставлять «распорки» (они же «spacer» и т.п.) и городить прочий огород.

Пример распорки:

Item {   Layout.fillWidth: true; implicitHeight: 1; }

Выглядит это костыльно (по моему), при этом создаёт лишнюю нагрузку при перерасчёте позиций во внутренностях Layout.

Погуглив, к удивлению обнаружил, что большинство ответов на подобные темы «qml nested layouts» как раз сводятся к советам использовать распорки, либо оборачивать RowLayout в Item… да же на официальном Qt форуме =(

При этом, кажется, в документации то же ничего не говорится про такую особенность у Layout, но там речь идёт именно про наследников Item, а не Layout.

НО нас интересует в первую очередь раздел «Size constraints«, из него становится ясно, что нужно разметке знать и Layout.maximumWidth элементов, читаем самую суть:

Layout.maximumWidth

Если элемент является макетом, неявная максимальная ширина будет максимальной шириной, которую может иметь макет без превышения максимальной ширины любого из его элементов. Неявная максимальная ширина для любого другого элемента — Number.POSITIVE_INFINITY.

Итого получается, что когда RowLayout вложен в ColumnLayout (или любой другой) и у него не задан явно размер (или anchors), то RowLaout пытается быть максимальной шириной вложенных в него Rectangle, а не шириной доступной в ColumnLayout, а он в свою очередь видит, что у RowLayout максимальная ширина в 250 пикселей (3 прямоугольника по 80 пикселей и добавить 2 промежутка по 5 пикселей). Из этого получается, что нам всего лишь нужно задать для RowLayout бесконечную максимальную ширину, а именно делается это с помощью

RowLayout {
  id: nestedRowLayout
  Layout.fillWidth: true
  Layout.maximumWidth: Number.POSITIVE_INFINITY
  ....

Вот и получится в итоге, как и задумывалось, без лишних костылей в виде распорок и т.д.

RowLayout пример правильного поведения

Тут наверное возникнет вопрос — а нафига тогда у RowLayout вообще Layout.fillWidth: true если он «не работает» и вместо него нужно Layout.maximumWidth?

На самом деле такая трактовка не совсем правильна и вовсе не «вместо», а в дополнении.
А именно, при true размер размер RowLayout будет высчитываться в зависимости от Layout.minimumWidth и Layout.maximumWidth, при этом пропорционально соседям, а при false зафиксирован на Layout.preferredWidth.
Кстати, по умолчанию у Layout всегда fillWidth: true и fillHeight: true и прописывать явно не обязательно.

Вот как-то так =)

Leave a Comment

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

You may also like