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

【写在前面】

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

其代码如下:

qml 复制代码
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 中为:
qml 复制代码
Flickable {
    ...
    onMovementStarted: {
        for (let key in contentItem.children) {
            let item = contentItem.children[key];
            if (item.objectName === "__ComboBox__")
                item.popup.close();
        }
    }

    ComboBox {
        ...
        objectName: "__ComboBox__"
    }
}
  • Qt6 中为:
qml 复制代码
Flickable {
    ...
    onMovementStarted: {
        for (let item of contentItem.children) {
            if (item.objectName === "__ComboBox__")
                item.popup.close();
        }
    }

    ComboBox {
        ...
        objectName: "__ComboBox__"
    }
}

只需要在当视图由于用户交互或生成的 flick() 而开始移动时,关闭掉 ComboBox 的弹窗即可。

修复后的效果如下:


【结语】

最后,要说明并非只有本文中的例子会有该 BUG,所有形如下面的代码都可能出现。

qml 复制代码
Popup {
    Popup {
        ...
    }
}

而修复思路也大致相似。

相关推荐
liwenzhuola9 分钟前
解决 Ubuntu 上 Qt Creator 项目编译失败的问题
数据库·qt·ubuntu
娇娇yyyyyy1 小时前
QT编程(18): Qt QItemSelectionModel介绍
开发语言·qt
sthnyph1 小时前
QT开发:事件循环与处理机制的概念和流程概括性总结
开发语言·qt
机器视觉知识推荐、就业指导5 小时前
LVGL真能动摇Qt的地位吗?
开发语言·qt·系统架构
羊小猪~~10 小时前
【QT】--QWIdget与QDialog
开发语言·数据库·c++·后端·qt·求职招聘
Blasit12 小时前
Qt 程序打包,运行提示找不到或无法加载平台插件 qwindows.dll
开发语言·windows·qt
C++ 老炮儿的技术栈12 小时前
c++常见配置文件格式 JSON、INI、XML、YAML 它们如何解析
xml·开发语言·c++·windows·qt·json
镜中月ss12 小时前
QT中的资源树
开发语言·qt·qml
Laurence12 小时前
GitHub 1.2 万星 Qt 项目 VNote 源码解读(一):核心类与主流程
qt·github·源码·代码·介绍·解读·vnote
Hello.Reader1 天前
从零开始安装 Qt完整新手教程(1)
开发语言·qt