【问题标题】:Difference between width, height and implicitWidth/Height and corresponding use-cases in QMLQML 中宽度、高度和隐式宽度/高度与相应用例之间的差异
【发布时间】:2018-02-07 08:45:29
【问题描述】:

QML 中的width/height 和implicitWidth/Height 有什么区别?什么时候应该设置隐式尺寸而不是常规尺寸?什么时候应该从组件/项目中询问隐式尺寸而不是常规尺寸?

【问题讨论】:

  • 好问题!我也为此苦苦挣扎了好久!
  • 太棒了!很多人在开始使用 QML 时都会遇到这个问题。

标签: qt qml


【解决方案1】:

通常,implicitHeight/Width 的使用仅在可重用组件中才有意义。

它给出了项目的自然大小的提示,而不强制执行此大小。

我们以Image 为例。图像的自然大小会将图像文件中的一个像素映射到屏幕上的一个像素。但是它允许我们拉伸它,所以大小不是强制的并且可以被覆盖。

假设现在,我们想要一个包含未知尺寸图片的画廊,我们不想扩大,只在必要时缩小它们。所以我们需要存储图像的自然大小。也就是说,隐式高度发挥作用。

Image {
    width: Math.max(150, implicitWidth)
    height: Math.max(150, implicitHeight)
}

在自定义组件中,您可以选择如何定义尺寸。

一种选择是,让所有维度都与组件root-node 相关,可能是这样的:

Item {
    id: root
    Rectangle {
        width: root.width * 0.2
        height: root.height * 0.2
        color: 'red'
    }
    Rectangle {
        x: 0.2 * root.width
        y: 0.2 * root.height
        width: root.width * 0.8
        height: root.height * 0.8
        color: 'green'
    }
}

在这种情况下,对象没有自然大小。对于您为组件设置的每种尺寸,一切都完美无缺。

另一方面,您可能有一个具有自然大小的对象 - 发生这种情况,例如如果你有绝对值

Item {
    id: root
    property alias model: repeater.model
    Repeater {
        id: repeater
        delegate: Rectangle {
            width: 100
            height: 100
            x: 102 * index
            y: 102 * index
        }
    }
}

在此示例中,您应该向用户提供有关自然尺寸的信息,其中内容不会突出项目。用户可能仍然决定设置较小的尺寸并处理突出,例如通过剪裁,但他需要有关自然尺寸的信息来做出决定。

在许多情况下,childrenRect.height/width 是 implcitHeight/Width 的一个很好的衡量标准,但也有一些例子,这不是一个好主意。 - 例如当item的内容有x: -500时。

一个真实的例子是Flickable,它专门设计用于包含比其自身大小更大的对象。让Flickable 的大小等于内容是不自然的。

在自定义组件中使用scale 时也要小心,因为childrenRect 不会知道缩放。

Item {
    id: root
    implicitWidth: child.width * child.scale
    implicitHeight: child.height * child.scale
    Rectangle {
        id: child
        width: 100
        height: 100
        scale: 3
        color: 'red'
    }
}

对于您的评论:我只是不明白为什么设置隐式宽度/高度而不是设置组件根尺寸的宽度/高度更好。

implicitWidht/Height 不是必需品 - QtQuick 可以没有它们。它们是为了方便而存在的,应该是约定的。


经验法则

当你想设置一个可复用组件的根节点的维度时,设置implicitWidth/Height。
在某些情况下,如果节点作为属性公开,则为非根节点设置它。
仅在有理由的情况下才这样做(许多官方组件都没有)。
使用组件时,设置width/height。

【讨论】:

  • 感谢 derM 和 Georg Schölly 的回答。我更喜欢这个答案,因为它有更深入的解释和“经验法则”+1。也感谢您对我的评论的回答。我在想类似的事情,这是一个很好的做法。现在接受这个答案,但我希望会有其他关于这个的帖子/cmets/讨论。
  • 非常好的完整答案。该标签在这个主题上缺乏一个好的答案。 :)
  • 我认为缺少一个重要的东西:在布局中使用项目时隐式大小的作用,这与 sizeHint 的 QWidgets/QLayout 行为接近。
  • @ymoreau:我还没有过多地使用 QtQuick.Layouts。我会调查它并在必要时更新答案。感谢您向我指出这一点。
  • @derM 关于Layout 类型的任何更新?阅读此文档,似乎在布局中使用 implicitX 而不是 x 也是有意义的:doc.qt.io/qt-5/…
【解决方案2】:

我没有确切的答案,但我可以告诉你我发现了什么。一、from the documentation:

implicitWidth : 真实

如果没有宽度或高度,则定义项目的自然宽度或高度 已指定。

大多数项目的默认隐式大小是 0x0,但是有些项目 具有不能被覆盖的固有隐式大小,因为 例如,Image 和 Text。

但是less informative for width:

宽度

定义项目的位置和大小。

width 和 height 反映了场景中项目的实际大小。隐式大小是项目本身的某种固有属性。1

我按如下方式使用它们:当我创建一个可以调整大小的新项目时,我在对象2内部设置了一个隐式大小。在使用对象时,我经常从外部显式设置实际大小。

可以通过设置高度和宽度来覆盖对象的隐式大小。

一个例子:TextWithBackground.qml

Item {
    implicitWidth: text.implicitWidth
    implicitHeight: text.implicitHeight
    // the rectangle will expand to the real size of the item
    Rectangle { anchors.fill: parent; color: "yellow" }
    Text { id: text; text: "Lorem ipsum dolor..." }
}

一个例子:MyWindow.qml

Item {
    width: 400
    height: 300
    TextWithBackground {
         // half of the scene, but never smaller than its implicitWidth
         width: Math.max(parent.width / 2, implicitWidth)
         // the height of the element is equal to implicitHeight
         // because height is not explicitly set
    }
}

1) 对于某些元素,例如 Text,隐式高度取决于(非隐式)宽度。
2)隐式大小通常取决于其子项的隐式大小。

【讨论】:

  • 简而言之:隐式大小是对象想要占用的空间,大小是它实际占用的空间。
  • 请注意,对于Text,implicitWidth 是没有换行时文本将占据的宽度。 contentWidth 是Item 的实际宽度,如果有环绕(如果没有环绕,它等于implicitWidth)。
  • 我想我也是这么理解的。因此,简而言之,使用隐式尺寸来“预设”组件的尺寸,并在您想要“覆盖”它时使用常规尺寸。如果未设置常规宽度/高度,则隐式尺寸有点像后备值。我在这里说得通吗?
  • 根据我的经验,我得出的结论是,如果要引用子大小,则应使用隐式大小,如果要引用父大小,则应使用显式大小。创建新组件时,不要硬编码大小,而是使用隐式大小。我试图用一个例子来说明它,但暂时放弃了,因为很难找到一个有意义的例子:)
  • 我只是不明白为什么设置implicitWidth/Height而不是设置组件根维度的width/height更好。如果我没有在我创建给定组件的位置指定一个,那么设置常规宽度/高度的工作方式与回退相同。
【解决方案3】:

根据内容计算项目的大小时,应该使用隐式大小。虽然在父项上设置 width 或 height 可能会影响其子项的大小,但当您设置隐式大小时,它绝不应该是这种情况。

经验法则

隐式大小只能“冒泡”,即儿童永远不应该 查找其父项的隐式大小以计算自己的 隐式大小,父母都不应该尝试强制其隐式大小 孩子们。

如果您尝试在类似于布局的组件上设置width,它最初会根据其子项的width(而不是implicitWidth)计算其宽度,并且该子项受父母,你最终会得到一个绑定循环。

这就是该属性存在的原因 - 在根据其内容计算项目大小时打破循环依赖关系。

【讨论】:

  • 如果你想创建一个可调整大小的 RowLayout 来填充它的父级怎么办?你不应该明确设置父母的大小,然后让布局的元素相对于他们的父母(布局)调整大小吗?
  • @pooya13 是的,您可以明确设置父级的大小。然后父级可以显式地设置其子级的大小。问题是RowLayout 应该如何表现,如果你不设置它的大小。如果您不设置RowLayout 的大小,则既不使用其附加属性RowLayout 将使用隐式大小的孩子来计算自己的大小。
猜你喜欢
  • 2016-07-14
  • 2016-05-15
  • 2020-07-24
  • 1970-01-01
  • 2014-03-15
  • 2013-07-02
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
相关资源
最近更新 更多