diannao 发表于 2025-2-7 03:27:42

Qml 中的那些坑(七)---ComboBox嵌入Popup时,滚动内容超过其可见区域不会关闭ComboBox弹窗

【写在前面】

最近在写信息提交 ( 表单 ) 的窗口时发现一个奇怪的 BUG:

其代码如下:
import QtQuick 2.15import QtQuick.Controls 2.15import QtQuick.Window 2.15Window {    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;                  if (item.objectName === "__ComboBox__")                        item.popup.close();                }            }*/            ComboBox {                width: 160                height: 40                objectName: "__ComboBox__"                model: ["aaaaaa", "bbbbbb", "cccccc", "dddddd"]            }      }    }}可以看到,当 ComboBox 嵌入 Popup 时,点开 ComboBox,然后滚动内容超过其可见区域并不会关闭 ComboBox 弹窗,并且会超出其 父 Popup 范围。
<hr>【正文开始】

实际上,这是几乎存在在 Qt 所有版本 ( Qt5 ~ Qt6 ) 的 BUG,猜测其主要原因为弹窗无法对内部嵌套弹窗进行裁剪,因为此弹窗 ( Popup ) 并非真正的窗口 ( Window )。
该 BUG 我已报告给官方:https://bugreports.qt.io/browse/QTBUG-130960
不过,在官方修复的版本出来之前,我实现的改动较小的修复办法为:

[*]Qt5 中为:
Flickable {    ...    onMovementStarted: {      for (let key in contentItem.children) {            let item = contentItem.children;            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 的弹窗即可。
修复后的效果如下:

<hr>【结语】

最后,要说明并非只有本文中的例子会有该 BUG,所有形如下面的代码都可能出现。
Popup {    Popup {      ...    }}而修复思路也大致相似。
页: [1]
查看完整版本: Qml 中的那些坑(七)---ComboBox嵌入Popup时,滚动内容超过其可见区域不会关闭ComboBox弹窗