diff --git a/examples/quick/controls/basiclayouts/main.qml b/examples/quick/controls/basiclayouts/main.qml index 74ccb49112a7c1fcd4e816e43e8b24a090b5be2a..e43f0a4a4a494e4115b5e9822ae359654eef3c0e 100644 --- a/examples/quick/controls/basiclayouts/main.qml +++ b/examples/quick/controls/basiclayouts/main.qml @@ -61,8 +61,6 @@ ApplicationWindow { GroupBox { id: rowBox title: "Row layout" - contentWidth: rowLayout.implicitWidth - contentHeight: rowLayout.implicitHeight Layout.fillWidth: true RowLayout { @@ -81,8 +79,6 @@ ApplicationWindow { GroupBox { id: gridBox title: "Grid layout" - contentWidth: gridLayout.implicitWidth - contentHeight: gridLayout.implicitHeight Layout.fillWidth: true GridLayout { diff --git a/examples/quick/controls/gallery/content/Controls.qml b/examples/quick/controls/gallery/content/Controls.qml index 93b933d780b5713f22eba950ba36381aa1b82293..310eee5956725bf5886a07ce8da6a4adfc86618a 100644 --- a/examples/quick/controls/gallery/content/Controls.qml +++ b/examples/quick/controls/gallery/content/Controls.qml @@ -154,8 +154,8 @@ Item { id: group2 title:"Tab Position" width: area.width - ExclusiveGroup { id: tabPositionGroup } Row { + ExclusiveGroup { id: tabPositionGroup } RadioButton { id: r1 text: "Top" diff --git a/src/controls/GroupBox.qml b/src/controls/GroupBox.qml index 61406fff0f66dbb7d8f8ddc1e8fbde4198945bee..6342d2789066f4ecb1fb84e53ad9ba41e6a37d84 100644 --- a/src/controls/GroupBox.qml +++ b/src/controls/GroupBox.qml @@ -58,13 +58,18 @@ import QtQuick.Layouts 1.0 You can minimize the space consumption of a group box by enabling the flat property. In most styles, enabling this property results in the removal of the left, right and bottom edges of the frame. - GroupBox doesn't automatically lay out the child controls (which are often \l{CheckBox}{CheckBoxes} or \l{RadioButton}{RadioButtons} but can be any controls). - The following example shows how we can set up a GroupBox with a column: + To add content to a group box, you can reparent it to its contentItem property. + + The implicit size of the GroupBox is calculated based on the size of its content. If you want to anchor + items inside the group box, you must specify an explicit width and height on the GroupBox itself. + + The following example shows how we use a GroupBox with a column: \qml GroupBox { title: qsTr("Package selection") Column { + spacing: 2 CheckBox { text: qsTr("Update system") } @@ -78,9 +83,8 @@ import QtQuick.Layouts 1.0 } \endqml - \note The default size of the GroupBox is calculated based on the size of its children. If you need to use anchors - inside a GroupBox, it is recommended to specify a width and height to the GroupBox or to add an intermediate Item - inside the GroupBox. + \sa CheckBox, RadioButton, Layout + */ Item { @@ -129,27 +133,34 @@ Item { */ property alias checked: check.checked - /*! - This property holds the width of the content. - */ - property real contentWidth: content.childrenRect.width + + /*! \internal */ + default property alias __content: container.data /*! - This property holds the height of the content. + \qmlproperty Item GroupBox::contentItem + + This property holds the content Item of the group box. + + Items declared as children of a GroupBox are automatically parented to the GroupBox's contentItem. + Items created dynamically need to be explicitly parented to the contentItem: + + \note The implicit size of the GroupBox is calculated based on the size of its content. If you want to anchor + items inside the group box, you must specify an explicit width and height on the GroupBox itself. */ - property real contentHeight: content.childrenRect.height + readonly property alias contentItem: container /*! \internal */ property Component style: Qt.createComponent(Settings.theme() + "/GroupBoxStyle.qml", groupbox) /*! \internal */ - default property alias data: content.data + property alias __checkbox: check /*! \internal */ - property alias __checkbox: check + property alias __style: styleLoader.item - implicitWidth: Math.max(200, (loader.item ? loader.item.implicitWidth: 0) ) - implicitHeight: (loader.item ? loader.item.implicitHeight : 0) + implicitWidth: (!anchors.fill ? container.calcWidth() : 0) + loader.leftMargin + loader.rightMargin + implicitHeight: (!anchors.fill ? container.calcHeight() : 0) + loader.topMargin + loader.bottomMargin Layout.minimumWidth: implicitWidth Layout.minimumHeight: implicitHeight @@ -159,44 +170,49 @@ Item { activeFocusOnTab: false - Loader { - id: loader - anchors.fill: parent - property int topMargin: (title.length > 0 || checkable ? 16 : 0) + content.margin - property int bottomMargin: 4 - property int leftMargin: 4 - property int rightMargin: 4 - sourceComponent: styleLoader.item ? styleLoader.item.panel : null - onLoaded: item.z = -1 + + data: [ Loader { - id: styleLoader - property alias __control: groupbox - sourceComponent: groupbox.style - } - } - - CheckBox { - id: check - checked: true - text: groupbox.title - visible: checkable - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: loader.topMargin - style: CheckBoxStyle { panel: Item{} } - } - - Item { - id:content - z: 1 - focus: true - property int margin: styleLoader.item ? styleLoader.item.margin : 0 - anchors.topMargin: loader.topMargin - anchors.leftMargin: margin - anchors.rightMargin: margin - anchors.bottomMargin: margin - anchors.fill: parent - enabled: (!groupbox.checkable || groupbox.checked) - } + id: loader + anchors.fill: parent + property int topMargin: __style ? __style.padding.top : 0 + property int bottomMargin: __style ? __style.padding.bottom : 0 + property int leftMargin: __style ? __style.padding.left : 0 + property int rightMargin: __style ? __style.padding.right : 0 + sourceComponent: styleLoader.item ? styleLoader.item.panel : null + onLoaded: item.z = -1 + Loader { + id: styleLoader + property alias __control: groupbox + sourceComponent: groupbox.style + } + }, + CheckBox { + id: check + checked: true + text: groupbox.title + visible: checkable + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: loader.topMargin + activeFocusOnTab: groupbox.checkable + style: CheckBoxStyle { panel: Item{} } + }, + Item { + id: container + z: 1 + focus: true + anchors.fill: parent + + anchors.topMargin: loader.topMargin + anchors.leftMargin: loader.leftMargin + anchors.rightMargin: loader.rightMargin + anchors.bottomMargin: loader.bottomMargin + enabled: (!groupbox.checkable || groupbox.checked) + + property Item layoutItem: container.children.length === 1 ? container.children[0] : null + function calcWidth () { return (layoutItem ? (layoutItem.implicitWidth || layoutItem.width) : container.childrenRect.width) } + function calcHeight () { return (layoutItem ? (layoutItem.implicitHeight || layoutItem.height) : container.childrenRect.height) } + }] } diff --git a/src/styles/Desktop/GroupBoxStyle.qml b/src/styles/Desktop/GroupBoxStyle.qml index 40c5ce58a97f9adec07a1869df56154984244820..d22341c52545f66230cc546affb1d31ffbe2a204 100644 --- a/src/styles/Desktop/GroupBoxStyle.qml +++ b/src/styles/Desktop/GroupBoxStyle.qml @@ -43,17 +43,32 @@ import QtQuick.Controls.Private 1.0 Style { - property int margin: 8 readonly property GroupBox control: __control + + property var __style: StyleItem { id: style } + property int titleHeight: 18 + + Component.onCompleted: { + var stylename = __style.style + if (stylename.indexOf("windows") > -1) + titleHeight = 9 + } + + property Margins padding: Margins { + top: (control.title.length > 0 || control.checkable ? titleHeight : 0) + 6 + left: 8 + right: 8 + bottom: 6 + } + property Component panel: StyleItem { + anchors.fill: parent id: styleitem elementType: "groupbox" text: control.title on: control.checked hasFocus: control.activeFocus - activeControl: checkable ? "checkbox" : "" - properties: { "checkable" : checkable , "sunken" : !flat} - contentWidth: control.contentWidth + 2 * margin - contentHeight: control.contentHeight + 2 * margin + activeControl: control.checkable ? "checkbox" : "" + properties: { "checkable" : control.checkable , "sunken" : !control.flat} } } diff --git a/src/styles/GroupBoxStyle.qml b/src/styles/GroupBoxStyle.qml index f5f2c9f49c40542d0b21cab9d5a2932e427b53be..d8538b95a14d9557b773c020bb31dde356c2073a 100644 --- a/src/styles/GroupBoxStyle.qml +++ b/src/styles/GroupBoxStyle.qml @@ -52,33 +52,94 @@ Style { /*! The \l GroupBox attached to this style. */ readonly property GroupBox control: __control - /*! The margin. */ - property int margin: 9 + /*! The margin from the content item to the groupbox. */ + property Margins padding: Margins { + top: (control.title.length > 0 || control.checkable ? 16 : 0) + 10 + left: 8 + right: 8 + bottom: 6 + } /*! The title text color. */ property color textColor: __syspal.text + /*! The check box. */ + property Component checkbox: Item { + implicitWidth: 18 + implicitHeight: 18 + BorderImage { + anchors.fill: parent + source: "images/editbox.png" + border.top: 6 + border.bottom: 6 + border.left: 6 + border.right: 6 + } + Rectangle { + height: 16 + width: 16 + antialiasing: true + visible: control.checked + color: "#666" + radius: 1 + anchors.margins: 4 + anchors.fill: parent + anchors.topMargin: 3 + anchors.bottomMargin: 5 + border.color: "#222" + opacity: control.enabled ? 1 : 0.5 + Rectangle { + anchors.fill: parent + anchors.margins: 1 + color: "transparent" + border.color: "#33ffffff" + } + } + BorderImage { + anchors.fill: parent + anchors.margins: -1 + anchors.topMargin: -2 + anchors.rightMargin: 0 + anchors.bottomMargin: 1 + source: "images/focusframe.png" + visible: control.activeFocus + border.left: 4 + border.right: 4 + border.top: 4 + border.bottom: 4 + } + } + /*! The groupbox frame. */ - property Component panel: - Item { - implicitWidth: control.contentWidth + 2 * margin - implicitHeight: control.contentHeight + 2 * margin + 11 + property Component panel: Item { + anchors.fill: parent + Loader { + id: checkboxloader + anchors.left: parent.left + sourceComponent: control.checkable ? checkbox : null + anchors.verticalCenter: label.verticalCenter + width: item ? item.implicitWidth : 0 + } + Text { + id: label anchors.top: parent.top - anchors.left: parent.left + anchors.left: checkboxloader.right anchors.margins: 4 text: control.title color: textColor renderType: Text.NativeRendering } + BorderImage { anchors.fill: parent - anchors.topMargin: 20 + anchors.topMargin: padding.top - 7 source: "images/groupbox.png" - border.left: 8 - border.right: 8 - border.top: 8 - border.bottom: 8 + border.left: 4 + border.right: 4 + border.top: 4 + border.bottom: 4 + visible: !control.flat } } } diff --git a/tests/auto/controls/data/tst_groupbox.qml b/tests/auto/controls/data/tst_groupbox.qml index 5599ca5f3a4d4920fdfc8204c0fb7030466aa9fc..6753868c27a14849b37202feacead9f97ec96806 100644 --- a/tests/auto/controls/data/tst_groupbox.qml +++ b/tests/auto/controls/data/tst_groupbox.qml @@ -84,6 +84,34 @@ TestCase { groupBox.destroy() } + function test_contentItem() { + verify (groupBox.contentItem !== null) + verify (groupBox.contentItem.anchors !== undefined) + } + + function test_dynamicSize() { + + var groupbox = Qt.createQmlObject('import QtQuick.Controls 1.0; import QtQuick.Controls.Styles.Private 1.0 ; GroupBox {style:GroupBoxStyle{}}', container, '') + compare(groupbox.width, 16) + compare(groupbox.height, 16) + + var content = Qt.createQmlObject('import QtQuick 2.1; Rectangle {implicitWidth:100 ; implicitHeight:30}', container, '') + content.parent = groupbox.contentItem + compare(groupbox.implicitWidth, 116) + compare(groupbox.implicitHeight, 46) + content.parent = null + content.destroy() + + content = Qt.createQmlObject('import QtQuick 2.1; Rectangle {width:20 ; height:20}', container, '') + content.parent = groupbox.contentItem + compare(groupbox.implicitWidth, 36) + compare(groupbox.implicitHeight, 36) + content.parent = null + content.destroy() + + groupbox.destroy() + } + function test_checkable() { compare(groupBox.checkable, false) compare(groupBox.child1.enabled, true)