【写在前面】
最近在写信息提交 ( 表单 ) 的窗口时发现一个奇怪的 BUG:
其代码如下:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")Button{text: "open"onClicked: popup.open();}Popup {id: popupwidth: 400height: 200anchors.centerIn: parentclip: trueclosePolicy: Popup.CloseOnPressOutsidebackground: Rectangle { color: "#80800000" }contentItem: Flickable {id: flickableclip: truetopMargin: 10contentWidth: implicitWidthcontentHeight: 500ScrollBar.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: 160height: 40objectName: "__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 {...}
}
而修复思路也大致相似。