不幸的是,这是 Qt 中的一个错误。目前,该文档具有误导性,并且无法Dialog
根据内容正确调整自身大小。考虑这个工作示例,我基于:DefaultFontDialog
AbstractDialog {
title: "Hello"
id: root
// standardButtons: StandardButton.Ok | StandardButton.Cancel
modality: Qt.NonModal
Rectangle {
id: content
implicitWidth: mainLayout.implicitWidth + outerSpacing * 2
implicitHeight: mainLayout.implicitHeight + outerSpacing * 2
property real spacing: 6
property real outerSpacing: 12
color: "white"
GridLayout {
id: mainLayout
anchors { fill: parent; margins: content.outerSpacing }
rowSpacing: content.spacing
columnSpacing: content.spacing
columns: 5
Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" }
Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" }
Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" }
Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" } Text { text: "Hello" }
}
}
}
这完全符合预期,尽管您当然没有得到按钮。
如果您只是将其更改为 aDialog
并取消注释standardButtons
,那么它将停止工作 - 您可以调整对话框的大小以剪辑其内容(至少在宽度方面),并且内容不会扩展到对话框大小。
当我们查看Dialog
(in qtquickcontrols/src/dialogs/DefaultDialogWrapper.qml
) 的源代码时,最小宽度不起作用的原因就很清楚了:
AbstractDialog {
id: root
default property alias data: defaultContentItem.data
onVisibilityChanged: if (visible && contentItem) contentItem.forceActiveFocus()
Rectangle {
id: content
property real spacing: 6
property real outerSpacing: 12
property real buttonsRowImplicitWidth: minimumWidth
property bool buttonsInSingleRow: defaultContentItem.width >= buttonsRowImplicitWidth
property real minimumHeight: implicitHeight
property real minimumWidth: Screen.pixelDensity * 50
implicitHeight: defaultContentItem.implicitHeight + spacing + outerSpacing * 2 + buttonsRight.implicitHeight
implicitWidth: Math.min(root.__maximumDimension, Math.max(
defaultContentItem.implicitWidth, buttonsRowImplicitWidth, Screen.pixelDensity * 50) + outerSpacing * 2);
minimumWidth
被硬编码为Screen.pixelDensity * 50
!! 从来没有任何希望它会匹配对话内容。minimumHeight
确实工作得更好(虽然不完美,但我相信因为没有考虑间距)。
我不确定为什么 defaultContentItem 不能正确展开,但无论如何。看起来目前唯一的解决方案是使用AbstractDialog
和实现按钮和accepted()
/ rejected()
/等。给自己发信号。有点痛。
编辑/解决方案
我做了一些进一步的调查。
defaultContentItem 不展开的原因是它的底部锚未绑定到按钮行的顶部:
Item {
id: defaultContentItem
anchors {
left: parent.left
right: parent.right
top: parent.top
margins: content.outerSpacing
}
implicitHeight: childrenRect.height
}
最小尺寸不适用于基于锚的布局。他们使用基于 GridLayout 的布局。
不幸的是,childrenRect 没有隐式宽度/高度,所以我们实际上必须让子项进入 ColumnLayout 而不是ColumnLayout。
...
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
// A Dialog that resizes properly. The defualt dialog doesn't work very well for this purpose.
AbstractDialog {
id: root
default property alias data: defaultContentItem.data
onVisibilityChanged: if (visible && contentItem) contentItem.forceActiveFocus()
Rectangle {
id: content
property real spacing: 6
property real outerSpacing: 12
property real buttonsRowImplicitWidth: minimumWidth
property bool buttonsInSingleRow: defaultContentItem.width >= buttonsRowImplicitWidth
property real minimumHeight: implicitHeight
property real minimumWidth: implicitWidth // Don't hard-code this.
implicitWidth: Math.min(root.__maximumDimension, Math.max(Screen.pixelDensity * 10, mainLayout.implicitWidth + outerSpacing * 2))
implicitHeight: Math.min(root.__maximumDimension, Math.max(Screen.pixelDensity * 10, mainLayout.implicitHeight + outerSpacing * 2))
color: palette.window
Keys.onPressed: {
event.accepted = true
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
reject()
break
case Qt.Key_Enter:
case Qt.Key_Return:
accept()
break
default:
event.accepted = false
}
}
SystemPalette { id: palette }
// We use layouts rather than anchors because there are no minimum widths/heights
// with the anchor system.
ColumnLayout {
id: mainLayout
anchors { fill: parent; margins: content.outerSpacing }
spacing: content.spacing
// We have to embed another item so that children don't go after the buttons.
ColumnLayout {
id: defaultContentItem
Layout.fillWidth: true
Layout.fillHeight: true
}
Flow {
Layout.fillWidth: true
id: buttonsLeft
spacing: content.spacing
Repeater {
id: buttonsLeftRepeater
Button {
text: (buttonsLeftRepeater.model && buttonsLeftRepeater.model[index] ? buttonsLeftRepeater.model[index].text : index)
onClicked: root.click(buttonsLeftRepeater.model[index].standardButton)
}
}
Button {
id: moreButton
text: qsTr("Show Details...")
visible: false
}
}
Flow {
Layout.fillWidth: true
id: buttonsRight
spacing: content.spacing
layoutDirection: Qt.RightToLeft
Repeater {
id: buttonsRightRepeater
// TODO maybe: insert gaps if the button requires it (destructive buttons only)
Button {
text: (buttonsRightRepeater.model && buttonsRightRepeater.model[index] ? buttonsRightRepeater.model[index].text : index)
onClicked: root.click(buttonsRightRepeater.model[index].standardButton)
}
}
}
}
}
function setupButtons() {
buttonsLeftRepeater.model = root.__standardButtonsLeftModel()
buttonsRightRepeater.model = root.__standardButtonsRightModel()
if (!buttonsRightRepeater.model || buttonsRightRepeater.model.length < 2)
return;
var calcWidth = 0;
function calculateForButton(i, b) {
var buttonWidth = b.implicitWidth;
if (buttonWidth > 0) {
if (i > 0)
buttonWidth += content.spacing
calcWidth += buttonWidth
}
}
for (var i = 0; i < buttonsRight.visibleChildren.length; ++i)
calculateForButton(i, buttonsRight.visibleChildren[i])
content.minimumWidth = calcWidth + content.outerSpacing * 2
for (i = 0; i < buttonsLeft.visibleChildren.length; ++i)
calculateForButton(i, buttonsLeft.visibleChildren[i])
content.buttonsRowImplicitWidth = calcWidth + content.spacing
}
onStandardButtonsChanged: setupButtons()
Component.onCompleted: setupButtons()
}
您必须使用与普通Dialog
. 想象一下它是一个ColumnLayout
(这与原始问题略有不同):
ColumnLayoutDialog {
id: dialog1
standardButtons: StandardButton.Ok | StandardButton.Cancel
Text {
text: "Hello world? "
}
Text {
text: "Hello world!"
}
// Spacer.
Item {
Layout.fillHeight: true;
}
Text {
text: "Goodbye world? "
}
Text {
text: "Goodbye world!"
}
}
顺便说一句,如果需要,您可以将其更改ColumnLayout
为 aGridLayout
并公开该columns
属性。这可能更有意义。
一个小问题
事实证明 aQWindow
的最小宽度和高度仅确保对话框不会主动调整大小以小于其内容。它不能确保对话框永远不会小于其内容,因为在创建对话框后内容可能会增长(例如,添加了额外的项目)。为了解决这个问题,我将此功能添加到我的ColumnLayoutDialog
:
// The minimumWidth/Height values of content are accessed by the C++ class, but they
// only ensure that the window isn't resized to be smaller than its content. They
// don't ensure that if the content grows the window grows with it.
function ensureMinimumSize()
{
if (root.width < content.minimumWidth)
root.width = content.minimumWidth;
if (root.height < content.minimumHeight)
root.height = content.minimumHeight;
}
当您更改对话框内容时,必须手动调用它。或者要自动执行此操作,您可以将其添加到content
矩形:
onMinimumHeightChanged: {
if (root.height < content.minimumHeight)
root.height = content.minimumHeight;
}
onMinimumWidthChanged: {
if (root.width < content.minimumWidth)
root.width = content.minimumWidth;
}