5

我有这个代码:

import QtQuick 2.3
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2

Dialog {
    standardButtons: StandardButton.Ok | StandardButton.Cancel

    width: layout.implicitWidth
    height: layout.implicitHeight

    RowLayout {
        id: layout
        anchors.fill: parent

        Item {
            width: 10
            height: 1
        }

        GridLayout {
            columns: 2
            rowSpacing: 10

            Layout.fillHeight: true
            Layout.fillWidth: true

            Text {
                text: "Hello world? "
            }
            Text {
                text: "Hello world!"
            }

            Text {
                text: "Goodbye world? "
            }
            Text {
                text: "Goodbye world!"
            }

        }

        Item {
            width: 10
            height: 1
        }
    }
}

当你运行它时,它看起来像这样,并且对话框可以调整为任何大小。如您所见,RowLayout实际上并没有填充其父级。

该死 请

如何使对话框无法调整到布局的最小尺寸以下,并且布局填充对话框?

4

2 回答 2

6

不幸的是,这是 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()/等。给自己发信号。有点痛。

编辑/解决方案

我做了一些进一步的调查。

  1. defaultContentItem 不展开的原因是它的底部锚未绑定到按钮行的顶部:

    Item {
        id: defaultContentItem
        anchors {
            left: parent.left
            right: parent.right
            top: parent.top
            margins: content.outerSpacing
        }
        implicitHeight: childrenRect.height
    }
    
  2. 最小尺寸不适用于基于锚的布局。他们使用基于 GridLayout 的布局。

  3. 不幸的是,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;
    }
于 2015-06-10T11:13:26.570 回答
1

这是 QT 5.6.0 之前的一个错误。很可能是错误号 49058。问题中的代码在 QT 5.6.1 和 5.7.0 中按预期工作。

旧版本的部分解决方法是删除这些行

width: layout.implicitWidth
height: layout.implicitHeight

并更换

anchors.fill: parent

anchors.right: parent.right
anchors.left: parent.left

然后对话框遵循最小高度并且内容水平扩展。

这里也是一个完整的解决方法,但是它依赖于 Dialog 未记录的实现细节,所以应该谨慎使用。它适用于 5.5.1、5.6.0、5.6.1 和 5.7.0。另请注意,第二个 Item 更改为红色 Rectangle 以使行为更加明显。

import QtQuick 2.3
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2

Dialog {
    visible: true
    standardButtons: StandardButton.Ok | StandardButton.Cancel

    RowLayout {
        id: layout

        // In the horizontal direction, expansion and shrinking can be achieved with anchors.
        anchors.left: parent.left
        anchors.right: parent.right

        // Used only for guessing the height of the Dialog's standard buttons.
        Button {
            id: hiddenButton
            visible: false
        }

        // Repeats until the relevant parts of the dialog (parent of the parent of the RowLayout)
        // are complete, then overwrites the minimum width and implicit height and stops repeating.
        Timer {
            id: timer
            interval: 50; running: true; repeat: true;
            onTriggered: {
                if(layout.parent.parent) {
                    var lp = layout.parent
                    var lpp = layout.parent.parent
                    lpp.minimumWidth = layout.implicitWidth + 2 * lpp.outerSpacing
                    layout.buttonHeight = 2 * lpp.outerSpacing + hiddenButton.implicitHeight + lpp.spacing
                    lp.implicitHeight = layout.implicitHeight + 2 * lpp.outerSpacing
                    running = false
                }
            }
        }

        // The guessed space needed for the Dialog's buttons.
        property int buttonHeight: 80

        // Expand and shrink vertically when the dialog is resized.
        height: parent.parent ? Math.max(parent.parent.height-buttonHeight, implicitHeight) : implicitHeight

        Item {
            width: 10
            height: 1
        }

        GridLayout {
            columns: 2
            rowSpacing: 10

            Layout.fillHeight: true
            Layout.fillWidth: true

            Text {
                text: "Hello world? "
            }
            Text {
                text: "Hello world!"
            }

            Text {
                text: "Goodbye world? "
            }
            Text {
                text: "Goodbye world!"
            }

        }

        Rectangle {
            Layout.fillHeight: true
            color: 'red'
            width: 10
        }
    }
}
于 2016-12-02T12:12:42.967 回答