【写在前面】
最近在写信息提交 ( 表单 ) 的窗口时发现一个奇怪的 BUG:
其代码如下:
import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Window 2.15 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") Button{ text: "open" onClicked: popup.open(); } Popup { id: popup width: 400 height: 200 anchors.centerIn: parent clip: true closePolicy: Popup.CloseOnPressOutside background: Rectangle { color: "#80800000" } contentItem: Flickable { id: flickable clip: true topMargin: 10 contentWidth: implicitWidth contentHeight: 500 ScrollBar.vertical: ScrollBar { width: 14 } /*onMovementStarted: { for (let key in contentItem.children) { let item = contentItem.children[key]; if (item.objectName === "__ComboBox__") item.popup.close(); } }*/ ComboBox { width: 160 height: 40 objectName: "__ComboBox__" model: ["aaaaaa", "bbbbbb", "cccccc", "dddddd"] } } } }
可以看到,当 ComboBox
嵌入 Popup
时,点开 ComboBox
,然后滚动内容超过其可见区域并不会关闭 ComboBox
弹窗,并且会超出其 父 Popup
范围。
【正文开始】
实际上,这是几乎存在在 Qt 所有版本 ( Qt5 ~ Qt6 )
的 BUG,猜测其主要原因为弹窗无法对内部嵌套弹窗进行裁剪,因为此弹窗 ( Popup )
并非真正的窗口 ( Window )
。
该 BUG 我已报告给官方:https://bugreports.qt.io/browse/QTBUG-130960?filter=-2
不过,在官方修复的版本出来之前,我实现的改动较小的修复办法为:
- Qt5 中为:
Flickable { ... onMovementStarted: { for (let key in contentItem.children) { let item = contentItem.children[key]; if (item.objectName === "__ComboBox__") item.popup.close(); } } ComboBox { ... objectName: "__ComboBox__" } }
- Qt6 中为:
Flickable { ... onMovementStarted: { for (let item of contentItem.children) { if (item.objectName === "__ComboBox__") item.popup.close(); } } ComboBox { ... objectName: "__ComboBox__" } }
只需要在当视图由于用户交互或生成的 flick()
而开始移动时,关闭掉 ComboBox
的弹窗即可。
修复后的效果如下:
【结语】
最后,要说明并非只有本文中的例子会有该 BUG,所有形如下面的代码都可能出现。
Popup { Popup { ... } }
而修复思路也大致相似。