一个 Qml MenuBar 的问题

2023-05-16

基本情况

使用 QQuick.Control 中的 MenuBar 实现主菜单栏。菜单栏包括 File、Edit、View、Help 菜单项。点击菜单项,会弹出对应的菜单。

ApplicationWindow {
    id: window
    width: 320
    height: 260
    visible: true

    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")
            Action { text: qsTr("&New...") }
            Action { text: qsTr("&Open...") }
            Action { text: qsTr("&Save") }
            Action { text: qsTr("Save &As...") }
            MenuSeparator { }
            Action { text: qsTr("&Quit") }
        }
        Menu {
            title: qsTr("&Edit")
            Action { text: qsTr("Cu&t") }
            Action { text: qsTr("&Copy") }
            Action { text: qsTr("&Paste") }
        }
        Menu {
            title: qsTr("&Help")
            Action { text: qsTr("&About") }
        }
    }
}

流程1:点击菜单栏上的菜单项,该菜单项被激活(弹出),再次点击该菜单项,菜单项退出激活状态。

流程2:如果在激活状态,移动鼠标到另一个菜单项,自动激活(不需要点击)另一个菜单项,当前激活的菜单项退出激活状态。

以上都符合预期,但是问题来了。

问题现象

流程3:在弹出的菜单上,点击某一个项目,弹出菜单消失,但是对应的菜单项并没有退出激活状态。

尝试解决

首先想到的方法,就是针对性处理。在弹出菜单消失时,触发菜单项状态切换。

        delegate: MenuBarItem {
            id: menuBarItem

            property bool opened: menu.opened
            onOpenedChanged: {
                if (!opened && highlighted) {
                    highlighted = false
                    triggered()
                }
            }
        }

实测流程3是OK了,但是流程1有问题了。在激活状态,再次点击菜单项,没有退出激活状态。

代码分析

看来只能分析源代码了。相同的思路,其实源代码里面已经实现了。

注意下面代码的 aboutToHide 一行,在弹出菜单将要消失时,是有处理的。

void QQuickMenuBar::itemAdded(int index, QQuickItem *item)
{
    Q_D(QQuickMenuBar);
    QQuickContainer::itemAdded(index, item);
    if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
        QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(this);
        QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
        QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
        if (QQuickMenu *menu = menuBarItem->menu())
            QObjectPrivate::connect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
    }
    d->updateImplicitContentSize();
    emit menusChanged();
}

菜单栏里面维护了激活状态(即 popupMode 为 true),菜单消失时,退出激活状态。

void QQuickMenuBarPrivate::onMenuAboutToHide()
{
    if (triggering || !currentItem || (currentItem->isHovered() && currentItem->isEnabled()) || !currentItem->isHighlighted())
        return;
    popupMode = false;
    activateItem(nullptr);
}

那为什么没有生效呢?通过调试,发现上面的代码 menu 是空指针,所以没有与 aboutToHide 信号连接。调用栈如下:

1   QQuickMenuBar::itemAdded              qquickmenubar.cpp       534  0x7ffc9884f04f 
2   QQuickContainerPrivate::insertItem    qquickcontainer.cpp     250  0x7ffc98814a3b 
3   QQuickContainer::insertItem           qquickcontainer.cpp     532  0x7ffc98813378 
4   QQuickContainer::addItem              qquickcontainer.cpp     507  0x7ffc9881327c 
5   QQuickContainer::itemChange           qquickcontainer.cpp     865  0x7ffc98813da0 
6   QQuickItemPrivate::itemChange         qquickitem.cpp          6231 0x7ffc7b509ed7 
7   QQuickItemPrivate::addChild           qquickitem.cpp          2976 0x7ffc7b505cf3 
8   QQuickItem::setParentItem             qquickitem.cpp          2765 0x7ffc7b4f699c 
9   QQuickMenuBarPrivate::beginCreateItem qquickmenubar.cpp       100  0x7ffc9884f6d8 
10  QQuickMenuBarPrivate::createItem      qquickmenubar.cpp       115  0x7ffc9884f768 
11  QQuickMenuBar::addMenu                qquickmenubar.cpp       341  0x7ffc9884e9cc 
12  QQuickMenuBar::qt_static_metacall     moc_qquickmenubar_p.cpp 131  0x7ffc9884e30d 
13  QQuickMenuBar::qt_metacall            moc_qquickmenubar_p.cpp 230  0x7ffc9884e0f9 
14  QMetaObject::metacall                 qmetaobject.cpp         310  0x7ffc5d08dcb4 
15  QQmlObjectOrGadget::metacall          qqmlpropertycache.cpp   1772 0x7ffc7140ed1b 
16  CallMethod                            qv4qobjectwrapper.cpp   1297 0x7ffc711c923e 
17  CallPrecise                           qv4qobjectwrapper.cpp   1557 0x7ffc711c9f56 
18  QV4::QObjectMethod::callInternal      qv4qobjectwrapper.cpp   2118 0x7ffc711c63da 
19  QV4::QObjectMethod::virtualCall       qv4qobjectwrapper.cpp   2056 0x7ffc711c5eeb 
20  QV4::FunctionObject::call             qv4functionobject_p.h   203  0x7ffc70f8a031 
... <更多>                                                                              

为什么 menu 是空的呢,原来 itemAdded 调用得比较早,这个时候还没有 setMenu。下面的代码(Qt 5.12.4) beginCreateItem 会调用 setParentItem,此时就触发了 itemAdded。

QQuickItem *QQuickMenuBarPrivate::createItem(QQuickMenu *menu)
{
    QQuickItem *item = beginCreateItem();
    if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item))
        menuBarItem->setMenu(menu);
    completeCreateItem();
    return item;
}

 后来看到一个比较新的 Qt5 代码,这个问题就是修复了的。他将 setMenu 放在了更前面。

QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu)
{
    ......
    if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item))
        menuBarItem->setMenu(menu);
    item->setParentItem(q);
    QQml_setParent_noEvent(item, q);
    return item;
}

解决方案

如果不升级 Qt,有没有办法解决这个问题呢?

其实只要将 MenuItem 重新添加到 MenuBar 中就行了,这个时候 menu 就不是空的了。

看代码:

    MenuBar {
        id: menuBar

        delegate: MenuBarItem {
            id: menuBarItem

            onMenuChanged: {
                // MenuBar has BUG on addMenu, it can't detach menu on MenuBarItem which is set later
                //  Re-add the item to fix the BUG
                menuBar.addItem(menuBar.takeItem(menuBar.count - 1))
            }
        }
    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个 Qml MenuBar 的问题 的相关文章

  • 如何将 C++ 属性绑定到 QML 属性?

    所以我知道如何将 QML 属性绑定到 C 属性 因此当 C 调用通知信号时 QML 会更新视图 当用户使用 UI 更改某些内容时 有什么方法可以更新 C 属性吗 例如 我有一个组合框 我希望当用户更改组合框的值时更新一些 C 属性 编辑 我
  • 删除 QML 网格的子项

    我想循环遍历 QML 网格的子级并使用 Javascript 销毁它们中的每一个 Grid id contentGrid spacing 10 ImageItem imageSource file foo jpeg destroy this
  • 更改 OS X 菜单栏中 Tkinter 应用程序的标题

    当您在 Python 中使用 Tkinter 创建带有 GUI 的应用程序时 应用程序的名称在 OS X 的菜单栏中显示为 Python 如何才能让它显示为其他内容 我的答案是基于埋在中间的一个一些论坛 http compgroups ne
  • QML 中日期和时间的正则表达式(DD/MM/YYYY hh:mm:ss)

    在QML2中我没有找到任何Calender控件 我已经实现了一个以日期和时间作为输入的控件 并且我使用正则表达式进行验证 该验证与日期 包括闰年和其他验证 相匹配 主要问题是空格 退格键也应该被视为有效 例如 s s s s s s s s
  • 在移动设备上部署 C++ QML 插件的正确方法是什么?

    我经常使用 Box2D QML 插件 看起来效果非常好 但是 我想在 Android SGS2 上部署我的示例应用程序 但我似乎无法让它工作 无论我尝试在 AVD 上还是在设备上运行它 它都不起作用 androiddeployqt 成功完成
  • 在 Qt 中自定义 AppMenu

    我正在为 MacOS 开发 Qt 应用程序 如何向 menuApp 添加项目 我的意思是出现在苹果图标右侧菜单栏上的条目 我想知道如何在 Qt 中实现这一点 而不是 Objective C 我正在使用 Qt 5 9 这是QWidget应用程
  • 更新 QML 中 var 属性的绑定

    如果你看一下这一页 http doc qt io qt 5 qml var html它指出 当对象更改时 与 var 属性的绑定不会自动更新 Item property var car new Object wheels 4 Text te
  • Qt - 模块“QtQuick.Controls”未安装

    我尝试部署一个在 PC 上运行良好的 QT 应用程序 该应用程序部署在基于 ASEM 的 yocto 安装映像中 版本为 morty 我收到错误消息 qml 加载组件时出错 qrc GUI InputDialog qml 3模块 QtQui
  • 对于属性上的 NOTIFY 信号,如果我给它一个参数,会有什么区别?

    假设我有一个如下所示的类 class Something QObject Q PROPERTY int something READ getSomething NOTIFY somethingChanged signals void som
  • 在 Qt Quick 中从 ListView 制作自定义 TableView 的规范方法

    制作桌子的最佳方法是什么ListView 假设给定一个二维字符串数组并且delegate因为所有列都是Labels 仅使用 QML 时如何以及何时计算每列的最大项目宽度 各内容Label不是恒定的 即implicitWidth在生命周期中是
  • 如何为动态创建的 QML 元素添加事件处理程序?

    我根据以下内容动态添加了一些 qml 组件到我的 gui 中这篇博文 http kunalmaemo blogspot kr 2011 04 creating qml element dynamically on html 如何为这些新创建
  • 带有 QML 的 FbxGeometryLoader

    我想将 fbx 文件导入到我的Scene3D https doc qt io qt 5 11 qml qtdatavisualization scene3d html 通过QMesh https doc qt io qt 5 11 qt3d
  • 计算在鼠标光标位置放大的视图偏移

    我有一个 画布 用户可以在上面绘制像素等 它运行良好 但我的缩放功能当前使用相同的原点 无论鼠标的位置如何 我想实现类似 Google 地图缩放行为的功能 也就是说 缩放的原点应始终是鼠标光标的位置 我目前拥有的 https i stack
  • iOS 和 Android 中的照片库

    我正在开发一个用于移动设备运行的应用程序iOS and Android我在访问时遇到一些困难image gallery的设备与Qml 我需要在一个中列出图片库中的图像GridView 我尝试使用返回图片文件夹QStandardPaths但它
  • QML - 不支持命令式代码

    有人可以评论这个事实吗QML 任何命令式JavaScript代码不会被执行 除非它是额外组件 http blog qt digia com blog 2011 05 05 qt quick designer in qt creator 2
  • 如何使应用程序的触摸栏在 macOS 上始终可见?

    我正在做macOS 菜单栏应用程序 https vidr io显示全屏覆盖 用户可以通过菜单栏中的滑块控制该叠加层的不透明度 我希望将这些控件移至触摸栏 因为该应用程序用于屏幕录制 并且会记录主屏幕上的干扰 我的应用程序中的滑块应该像默认情
  • QML 不显示 svg 图像

    我编写了一个简单的 QML ui 它使用一些 svg 图像 当我在桌面上执行该应用程序时 一切都很好 显示了 UI 以及上面的 svg 图像 当我尝试在嵌入式设备 运行嵌入式 Windows 上执行应用程序时 会出现问题 在这种情况下 会显
  • Q_PROPERTY NOTIFY 信号及其参数

    我有写 propertyChanged 的习惯signals 带参数 这样接收端就不需要调用Q PROPERTY s READ明确地发挥作用 我这样做是出于清晰的考虑 并且假设在 QML 数据绑定情况下 不需要对 getter 进行 昂贵
  • 部署 Qt Quick 演示应用程序 Minehunt 时出现全白屏幕

    为了测试部署过程 我尝试部署附带的演示应用程序 Minehunt 我能够让它运行 没有崩溃或错误 但屏幕是全白的 我相信这通常意味着我缺少插件 Dependency walker 报告没有问题 我什至尝试包含 Qt MingW 插件目录中的
  • 使用 KDE Kirigami 时未找到 QML 模块

    所以我决定在我的应用程序中使用 KDE Kirigami UI 框架 所以我按照说明进行操作here https api kde org frameworks kirigami html index html 我将存储库克隆到我的应用程序目

随机推荐

  • 营运型手游开发、测试、正式的三阶段开发架构

    在手机游戏的畅销排行榜上 xff0c 可以看到大多数的游戏都是营运型的游戏 所谓的营运型游戏 xff0c 指的是游戏的开发并不是上架后就结束 xff0c 而是需要持续的配合游戏营运的需求 xff0c 进行游戏的更新 内容调整以及后续内容的开
  • 【github】【action】如何给软件包添加CI集成

    github action 如何给软件包添加CI集成 简介 github有自己的CI集成工具 action 很少有小伙伴关注到 xff0c 如果你有自己的软件包 xff0c 想要对其进行维护的话 xff0c 添加CI集成能够方便你快速验证你
  • Access 标准表达式中数据类型不匹配

    Access 标准表达式中数据类型不匹配 Access标准表达式中数据类型不匹配 今天在做一个小程序时 要求用到Access数据库 在调试运行一个SELECT语句时 老是提示标准表达式中数据类型不匹配 弄了好久 原来发现是数据类型不匹配的问
  • c#中new一个对象以后,是否需要手动释放?

    c 中new一个对象以后 xff0c 是否需要手动释放 xff1f 2012 04 28 23 43 wshbfzdzb 分类 xff1a C NET 浏览723次 c 43 43 中 class1 a 61 new class1 需要在用
  • ARM M0+各种定时器驱动的编写

    systick 系统滴答时间 这个定时器之前的文章已经讲过 这个是一个递减的定时器 xff0c 有个模数寄存器 在此不多说 就是一个系统的模块 xff0c 这个模块是集成在ARM M0 43 内核中的 xff0c 其实主要是集成在NVIC
  • MG323所有命令使用

    AT 43 CGMR 61 OK AT 43 GMR 61 OK AT 43 GMR 12 210 10 05 00 OK AT 43 CGSN 351869042318140 OK AT 43 CIMI 460021734971641 O
  • BAT文件的常用语法

    bat文件中常用的命令有 xff1a echo 64 rem pause goto call if copy等 下面简要给出这几个命令的用法 1 echo命令 echo 表示显示此命令后的字符 例如echoHello World choHe
  • c++ http请求,json解析

    一 文章内容 解决c 43 43 http请求以及对返回结果json串进行解析 xff0c 使用jsoncpp库 二 安装jsoncpp插件 vs2015通过NuGet直接安装jsoncpp到项目下 安装好之后 xff0c 会在项目下有个p
  • Linux安装Oracle12c操作手册

    1 基本环境 服务器 xff1a 64位 16核CPU 384G内存 16T硬盘 操作系统 xff1a CentOS 7 4 Oracle版本 xff1a 12c 版本号12 1 0 2 0 2 安装必要的软件包 查看rpm包是否安装 xf
  • tiny6410按键驱动总结

    写了7个版本的按键驱动 xff1a 1 查询法 xff1a 在应用程序的while循环里不停的调用read函数读取按键值 xff0c 太耗费CPU资源了 2 中断发 xff1a 同样是在一个while循环里不停的调用read函数读按键值 x
  • linux中shell的常用命令

    shell 常用命令 什么是shell xff1f shell 也是操作系统中的一个软件 xff0c 它包在 linux 内核的外面 为用户和内核之间的交互提供了一个接口 一 diff命令 diff b表示忽略空格 xff0c B表示忽略空
  • 空心杯电机学习笔记

    空心杯电机学习笔记 1 空心杯电机 xff08 直流电机 xff09 的硬核拆解2 空心杯电机的驱动模块学习 xff08 1 xff09 无人机飞控原理学习的流程介绍 xff08 空心杯四旋翼DIY xff09 xff08 2 xff09
  • C++ 中“空引用”与“空指针”的区别

    网络上有很多讨论C 43 43 的 引用 与 指针 的区别的文章 xff0c 谈到区别 xff0c 其中有一条 xff1a 引用不能为空 xff08 NULL xff09 xff0c 引用必须与合法的存储单元关联 xff0c 指针则可以是N
  • 关于 std::vector 的下标越界检查

    当要获取 std vector 的第 n 个元素 xff0c 下面几种方式都可以 xff1a std vector lt int gt vec size t n 61 1 int amp i 61 vec n int amp j 61 ve
  • 【第三篇】 基于 Qt 的 REST 网络框架

    本文是 Qt 框架性开发实践 基础框架篇 的第三篇 本文所讲的内容已经开源 xff0c 你可以在 这里 找到源代码 在 Java 以及其他语言中 xff0c 处理与后端的 HTTP 通讯 xff0c 有专门的工具库 xff0c 使用起来特别
  • Qt/QML 实现图片圆角剪切效果

    在很多 UI 设计中 xff0c 需要将图片按照一定的方式整形 比如下面的 VIP 图片就是用一个圆形剪切原始图片 xff0c 形成的效果 其实它的原始图片是这样的 xff1a 要在 QML 中实现这样的效果 xff0c 可以使用 Opac
  • 实现 DirectShow 虚拟 Camera 驱动

    今天我们要实现一个虚拟 Camera 驱动 有这个驱动 xff0c 在 播放软件 xff08 如 VLC xff09 视频会议软件 主播视频制作软件 xff08 如 OBS xff09 中 xff0c 就可以播放 加入我们的各种特制内容了
  • 通过 ffmpeg 串流对接 OBS 等直播软件

    我们要将设备通过私有通道输出到 H264 流 xff0c 传给 OBS 等直播软件使用 为此 xff0c 设计了上图所示的串流工具 设计思路 私有通道通过 API 接口提供 H264 流 xff0c 要传给 ffmpeg xff0c 最简单
  • 排查 Edge WebView2 在某个设备上不出图像的问题

    我们在 Windows 应用内嵌入 Edge WebView2 xff0c 来展示部分用网页实现的界面 总得来说还是不错的 xff0c 比如 xff1a 渲染很快 xff0c 基本上内置网页100毫秒以内控件样式很清爽 xff0c 没有多余
  • 一个 Qml MenuBar 的问题

    基本情况 使用 QQuick Control 中的 MenuBar 实现主菜单栏 菜单栏包括 File Edit View Help 菜单项 点击菜单项 xff0c 会弹出对应的菜单 ApplicationWindow id window