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

而修复思路也大致相似。

相关推荐
Sunlight_7778 小时前
第六章 QT基础:9、Qt中数据库的操作
数据库·qt·oracle
向日葵xyz9 小时前
Qt5与现代OpenGL学习(二)画一个彩色三角形
开发语言·qt·学习
AAA废品回收站陈师傅10 小时前
60常用控件_QSpinBox的使用
qt
姆路13 小时前
Qt官方案例知识点总结(拖放操作——Drag And Drop Robot )
c++·qt
Cuit小唐13 小时前
Qt二维码demo
开发语言·qt·命令模式
天堂的恶魔94613 小时前
QT —— 信号和槽(带参数的信号和槽函数)
开发语言·qt
enyp8013 小时前
Qt connect第五个参数
开发语言·qt
郑文博Coding16 小时前
Qt QWebEngine应用和网页的交互
开发语言·qt·交互
enyp8017 小时前
Qt多线程TCP服务器实现指南
服务器·qt·tcp/ip
码力码力我爱你18 小时前
QT Quick 3D 渲染之场景构建(一)
开发语言·qt·3d