【寫在前面】
最近在寫資訊提交 ( 表單 ) 的視窗時發現一個奇怪的 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 {
...
}
}
而修復思路也大致相似。