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 {
        ...
    }
}

而修复思路也大致相似。

相关推荐
feiyangqingyun1 小时前
Qt实时绘制飞行轨迹/移动轨迹实时显示/带旋转角度/平滑移动/效果一级棒/地面站软件开发/无人机管理平台
qt·无人机·集群地面站
十五年专注C++开发4 小时前
Qt-VLC: 一个集成VLC的开源跨平台媒体播放库
开发语言·qt·媒体·libvlc·vlc-qt
Aevget7 小时前
QtitanNavigation助力能源数字化转型:打造清晰可控的系统导航体验
c++·qt·嵌入式·能源·界面控件·ui开发
寻找华年的锦瑟10 小时前
Qt Quick Application&&Qt Quick Application (compat)
开发语言·qt
上去我就QWER13 小时前
Qt中如何获取系统版本信息
开发语言·qt
十五年专注C++开发1 天前
Qt-Nice-Frameless-Window: 一个跨平台无边框窗口(Frameless Window)解决方案
开发语言·c++·qt
江公望1 天前
装了新的QtCreator17,没有用Qt5.12自带的QtCreator4,导致QtCreator17无法找到Qt5.12帮助文档
qt·qml
ctgu901 天前
PyQt5(八):ui设置为可以手动随意拉伸功能
开发语言·qt·ui
进击的大海贼1 天前
QT/C++ 消息定时管理器
开发语言·c++·qt
Lj2_jOker1 天前
QT 给Qimage数据赋值,显示异常,像素对齐的坑
开发语言·前端·qt