From 47eefcd84d8e8db26af8ebba40408e45f93aba8b Mon Sep 17 00:00:00 2001 From: zhangkun Date: Thu, 15 Oct 2026 09:32:42 +0800 Subject: [PATCH] fix(qml): correct dropdown sizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Measure realized visible items and retain their maximum width. 2. Use visible row height and laid-out content to size the list. 3. Keep ComboBox delegate implicit width independent of popup width. Log: Correct dropdown width measurement and height sizing Influence: Improve dropdown sizing and item visibility. fix(qml): 修正下拉列表尺寸计算 1. 测量已创建的可见项并保留最大宽度。 2. 使用可见项行高和布局后的内容计算列表高度。 3. 移除组合框委托隐式宽度对弹窗宽度的依赖。 Log: 修正下拉列表宽度测量和高度计算 PMS: BUG-377521 Influence: 改善下拉列表尺寸和选项显示。 --- qt6/src/qml/ArrowListView.qml | 57 +++++++++++++++++++++++------------ qt6/src/qml/ComboBox.qml | 3 +- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/qt6/src/qml/ArrowListView.qml b/qt6/src/qml/ArrowListView.qml index eb7c880c..e3321ca8 100644 --- a/qt6/src/qml/ArrowListView.qml +++ b/qt6/src/qml/ArrowListView.qml @@ -15,15 +15,28 @@ FocusScope { property int itemHeight: DS.Style.arrowListView.itemHeight property alias view: itemsView - // Full height of the list, to size a popup before it is mapped. + // Height of a visible realized row, or the style height before one exists: + // row 0 can be a row hidden by a visible role, and its height is 0. + readonly property real _rowHeight: { + if (itemsView.contentHeight > 0) { + for (var i = 0; i < itemsView.count; ++i) { + const item = itemsView.itemAtIndex(i) + if (item && item.visible && item.height > 0) + return item.height + } + } + return itemHeight + } + + // Full height of the list, to size a popup before it is mapped readonly property real sizedHeight: { if (itemsView.count === 0) return 0 - const item = itemsView.itemAtIndex(0) - const measured = itemsView.contentHeight > 0 && item ? (item.height || item.implicitHeight) : 0 + if (itemsView.contentHeight > 0) + return implicitHeight const arrowStrips = itemsView.count > maxVisibleItems ? 2 * (DS.Style.arrowListView.stepButtonIconSize.height + contentLayout.spacing) : 0 - return Math.min(itemsView.count, maxVisibleItems) * (measured > 0 ? measured : itemHeight) + arrowStrips + return Math.min(itemsView.count, maxVisibleItems) * _rowHeight + arrowStrips } implicitWidth: Math.max(DS.Style.arrowListView.width, contentLayout.implicitWidth) @@ -44,21 +57,14 @@ FocusScope { ListView { id: itemsView + property real itemMaxWidth: 0 clip: true Layout.fillWidth: true Layout.fillHeight: true onHeightChanged: if (height > 0 && contentHeight === 0) forceLayout() - implicitHeight: itemsView.count > 0 ? Math.min(contentHeight, maxVisibleItems * contentHeight / itemsView.count) : 0 - implicitWidth:{ - var maxWidth = DS.Style.arrowListView.width - for (var i = 0; i < itemsView.count; ++i) { - var item = itemsView.itemAtIndex(i) - if (item && item.implicitWidth > maxWidth) - maxWidth = item.implicitWidth - } - return maxWidth - } - interactive: itemsView.count > maxVisibleItems + implicitHeight: itemsView.count > 0 ? Math.min(contentHeight, maxVisibleItems * control._rowHeight) : 0 + implicitWidth: itemMaxWidth + interactive: itemsView.contentHeight > itemsView.height ScrollIndicator.vertical: ScrollIndicator { } highlight: HighlightPanel { visible: false // TODO listview's highlight is confict with Item's highlight. @@ -76,16 +82,29 @@ FocusScope { highlightMoveDuration: -1 highlightMoveVelocity: 400 - onCountChanged: refreshContentItemWidth() + Connections { + target: itemsView.contentItem + function onChildrenChanged() { Qt.callLater(itemsView.refreshContentItemWidth) } + } + + onCountChanged: { + itemMaxWidth = 0 + refreshContentItemWidth() + } + onWidthChanged: refreshContentItemWidth() function refreshContentItemWidth() { + var maxWidth = itemMaxWidth for (var i = 0; i < itemsView.count; ++i) { var item = itemsView.itemAtIndex(i) - if (item) { - item.width = itemsView.width - } + if (!item || !item.visible) + continue + item.width = itemsView.width + if (item.implicitWidth > maxWidth) + maxWidth = item.implicitWidth } + itemMaxWidth = maxWidth } } diff --git a/qt6/src/qml/ComboBox.qml b/qt6/src/qml/ComboBox.qml index 9f3d5341..7d61c936 100644 --- a/qt6/src/qml/ComboBox.qml +++ b/qt6/src/qml/ComboBox.qml @@ -33,7 +33,6 @@ T.ComboBox { bottomPadding: control.flat ? 0 : padding delegate: MenuItem { - implicitWidth: Math.max(DS.Style.control.implicitWidth(control), popup.implicitWidth - DS.Style.popup.margin * 2) useIndicatorPadding: true text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : (model[control.textRole] === undefined ? modelData[control.textRole] : model[control.textRole])) : modelData icon.name: (control.iconNameRole && model[control.iconNameRole] !== undefined) ? model[control.iconNameRole] : null @@ -172,7 +171,7 @@ T.ComboBox { leftMargin: DS.Style.popup.margin rightMargin: DS.Style.popup.margin palette: control.palette - implicitWidth: control.flat ? Math.max(contentItem.implicitWidth, control.width) : control.width + implicitWidth: control.flat ? Math.max(contentItem.implicitWidth + leftPadding + rightPadding, control.width) : control.width // 60 is a temporary viewport so the list can realize one row and be measured. implicitHeight: (contentItem.sizedHeight > 0 ? contentItem.sizedHeight : 2 * DS.Style.arrowListView.itemHeight) + topPadding + bottomPadding