`
tomhibolu
  • 浏览: 1406946 次
文章分类
社区版块
存档分类
最新评论

QMainWindow上下文菜单内存泄露(QTBUG)

 
阅读更多

起源

CSDN论坛有网友抱怨:

创建Qt工程,基于QMainwindow,什么也不做,程序会自带一个上下文菜单。
不断点击鼠标右键,菜单将反复出现,此时我用任务管理器查看其内存变化,发现每次不断增加,请问大家这是Qt的内存泄漏吗???我用MFC,CB均没有发现类此错误。

在Qt4.7.0 和 4.7.3下可以重现该问题,在Qt4.6.3下不存在该问题。可以确定是Qt的一个bug。

  • 惭愧 :还没学会怎么提交bug、提交patch、然后找人来审核。先记录下来,晚些时候学习好好学习一下这些流程然后再提交

问题重现

在工具栏或停靠窗口中点击右键(弹出上下文菜单),多点击几次,然后点击按钮。观察控制台输出,可以看到很多个 QMenu 对象。

#include <QtGui>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);

private slots:
    void onButtonClicked();
};

MainWindow::MainWindow(QWidget *parent)
{
    addToolBar("ToolBar");
    addDockWidget(Qt::LeftDockWidgetArea, new QDockWidget("DockWidget"));

    QPushButton * btn = new QPushButton("dump object tree");
    setCentralWidget(btn);

    connect(btn, SIGNAL(clicked()), SLOT(onButtonClicked()));
}

void MainWindow::onButtonClicked()
{
    dumpObjectTree();
}

#include "main.moc"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

原因

既然是QMainWindow的上下文菜单问题,直接看 contextMenuEvent 事件处理函数吧。

void QMainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    event->ignore();
...
    QMenu *popup = createPopupMenu();
    if (popup) {
        if (!popup->isEmpty()) {
            popup->setAttribute(Qt::WA_DeleteOnClose);
            popup->popup(event->globalPos());
            event->accept();
        } else {
            delete popup;
        }
    }
}

看仔细喽,这儿设置了 Qt::WA_DeleteOnClose 属性。

  • 有什么用?设置该属性后,当我们调用该对象的 close() 成员时,隐藏(hide)窗口同时会删除(delete)该对象
  • 有什么问题?问题出在,实际上隐藏菜单时没有 调用菜单的close(),而是 调用的hide()的成员。

调用hide()而不是close(),是的该属性不能发挥任何作用,进而导致内存泄露(Qt 之 show,hide,setVisible,setHidden,close 等小结 )。

为了对比,我们看看Qt4.6.3的源码部分:

void QMainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    event->ignore();
...
    QMenu *popup = createPopupMenu();
    if (popup && !popup->isEmpty()) {
        popup->exec(event->globalPos());
        event->accept();
    }
    delete popup;
}

而这个,也就是我们的比较理想的答案了。

进一步学习

前面说了,菜单隐藏时调用的是hide() 成员,而不是close() 成员。有神马依据??

想想?如何让菜单隐藏

  • 鼠标:点击菜单外区域
  • 键盘:按下Esc键等

这样就比较明朗了,对吧,直接看这两个事件处理函数

  • 键盘的按键事件(调用了hideMenu)
void QMenu::keyPressEvent(QKeyEvent *e)
{
    Q_D(QMenu);
    d->updateActionRects();
    int key = e->key();
...
    bool key_consumed = false;
    switch(key) {
    case Qt::Key_Escape:
        key_consumed = true;
        {
            QPointer<QWidget> caused = d->causedPopup.widget;
            d->hideMenu(this); // hide after getting causedPopup
            if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
                mb->d_func()->setCurrentAction(d->menuAction);
                mb->d_func()->setKeyboardMode(true);
            }
        }
        break;
  • 鼠标在菜单区域外按键,调用了hideUpToMenuBar(进而调用hideMenu)
void QMenu::mousePressEvent(QMouseEvent *e)
{
    Q_D(QMenu);
...
    if (!rect().contains(e->pos())) {
         if (d->noReplayFor
             && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPos()))
             setAttribute(Qt::WA_NoMouseReplay);
         if (d->eventLoop) // synchronous operation
             d->syncAction = 0;
        d->hideUpToMenuBar();
        return;
    }
...
}
  • 前面都调用了hideMenu,从名字也能猜猜它想干什么:
void QMenuPrivate::hideMenu(QMenu *menu, bool justRegister)
{
...
        menu->hide();
}
分享到:
评论

相关推荐

    QTMenu_窗口_QT菜单_QT_子菜单_

    QTMenu是QT库中关于创建窗口菜单和子菜单的一个实践示例,对于初学者来说,理解和掌握这个主题是非常重要的。QT是一个跨平台的应用程序开发框架,广泛用于创建图形用户界面(GUI)应用。QT库提供了丰富的API,使得...

    基于QMainWindow主程序窗口

    QMainWindow是Qt框架中一个基本的GUI组件,通常用作主程序窗口。它继承自QWidget,提供了许多有用的功能和信号,可以用来创建复杂的GUI应用程序。 在Linux平台下,使用QMainWindow可以创建一个功能丰富的主程序窗口...

    05_QMainWindow.rar

    QT软件学习记录主要聚焦于"QMainWindow"这个关键组件,它是Qt库中的核心窗口类,用于构建复杂的用户界面。QMainWindow是许多桌面应用程序的基础,它提供了菜单栏、工具栏、状态栏以及DockWidgets等基本元素,使...

    Qt按钮菜单

    在Qt框架中,按钮菜单(通常称为上下文菜单或右键菜单)是用户界面中一个常见的功能,它允许用户通过单击按钮或者右键点击触发一个包含多个操作选项的菜单。这种设计使得用户能快速访问复杂的操作而不必占据屏幕空间...

    【QT】07 QMainWindow文章代码

    同样,我们可以在QMainWindow上使用`addToolBar()`方法添加工具栏,然后在工具栏上添加QAction,这些QAction可以代表一个按钮或菜单项,同样需要绑定相应的槽函数。 状态栏(QStatusBar)通常用于显示短暂的信息或...

    Qt 实现抽屉式菜单

    在本文中,我们将深入探讨如何使用Qt框架实现抽屉式菜单。Qt是一个强大的跨平台应用程序开发框架,广泛用于创建美观且功能丰富的用户界面。抽屉式菜单,也称为侧滑菜单或滑出式菜单,常见于移动应用设计中,允许用户...

    11 菜单工具栏和状态栏QMainWindow.zip

    总之,"11 菜单工具栏和状态栏QMainWindow.zip"这个压缩包内容涵盖了Qt开发中非常重要的部分,对于任何希望构建专业桌面应用的开发者来说,这些都是不可或缺的知识点。通过学习和实践,你将能够创建出功能丰富且用户...

    qt 设计菜单图标qt 设计菜单图标

    在Qt框架中,设计用户界面(UI)时,菜单图标是增强用户体验的重要组成部分。Qt库提供了丰富的功能,允许开发者创建带有图标的自定义菜单。在本篇中,我们将深入探讨如何在Qt应用中使用PNG格式的20*20像素大小的图标...

    Qt菜单操作

    它可以被用作窗口的系统菜单栏,也可以作为其他控件如QPushButton的上下文菜单。QMenu提供了添加菜单项、子菜单以及关联动作的功能,使得用户可以通过点击菜单来执行相应的操作。 1. **系统菜单**:在许多操作系统...

    QT样式(包含:系统托盘,独立标题栏,自定义菜单,窗口自由移动,样式效果)

    QT样式是一种基于Qt框架的应用程序设计风格,它允许开发者创建具有独特外观和交互方式的用户界面。...通过深入研究Qt的文档和相关教程,可以进一步提升在Qt样式设计上的技能,创造出更具吸引力和用户体验的应用程序。

    QT实现全屏和右击菜单的源代码

    在Qt中,可以使用QMenu类创建上下文菜单。通常,你会在鼠标右键点击事件中显示这个菜单。在`mainwindow.h`中,你需要声明一个QMenu对象: ```cpp class MainWindow : public QMainWindow { Q_OBJECT public: ...

    基于QMainWindow的主窗口程序例子

    在Qt框架中,`QMainWindow`是构建复杂用户界面的核心组件,它提供了主窗口所需的许多标准功能,如菜单栏、工具栏、状态栏以及 Dock Widgets。这篇博客文章"基于QMainWindow的主窗口程序例子"旨在指导开发者如何使用`...

    QT添加自定义控件

    ### QT添加自定义控件 #### 一、引言 在使用QT进行界面设计时,开发者往往会遇到标准控件库无法完全满足特定需求的情况。此时,实现自定义控件成为解决问题的有效途径之一。本文旨在详细介绍如何在QT环境中快速...

    QWidget,QMainWindow和QDialog的区别

    QWidget、QMainWindow 和 QDialog 是 Qt 中三个基础的 GUI 组件类,它们之间的区别是非常重要的,在创建 Qt Gui Application 时,总会让你选择在 QWidget、QMainWindow 和 QDialog 中选择一个 Base Class。...

    QMainWindow实现文本编辑器

    `QMainWindow`是Qt界面设计中的一个重要组件,它提供了窗口的基础框架,可以容纳各种小部件如菜单栏、工具栏、状态栏等,使得我们可以构建出具有专业外观的应用程序。 首先,我们要理解`QMainWindow`的基本结构。`...

    QMainWindow的了解及应用

    在QT库中,`QMainWindow`是一个非常重要的类,它是构建复杂GUI应用程序的基础。`QMainWindow`提供了许多内置的功能,如菜单栏、工具栏、状态栏以及 dockable widgets(可停靠小部件),使得开发者能够轻松地创建具有...

    QMainWindow无标题栏和边框依然可以通过四周改变窗口大小

    QMainWindow通过setWindowFlags(Qt::FramelessWindowHint)该函数隐藏掉标题栏以后,就不能通过窗口四周来拖动大小了,所以必须要重写,重写两种方法:第一种重写是:mouseMoveEvent,该方法要设置以下两点(1)...

    QT QMainWindow 界面的创建笔记

    qt中 QMainWindow 界面的创建

    qmainwindow无边框可拉伸拖动的实现

    Qt是一个强大的跨平台应用程序开发框架,而QMainWindow是其核心组件之一,通常用于构建带有菜单栏、工具栏和状态栏的复杂窗口。我们将基于Qt5和CMake构建这样的界面。 首先,让我们了解QMainWindow无边框化。在Qt中...

    QT.rar_qt 主菜单_qt 菜单

    菜单栏是应用程序界面上顶部的一行菜单,通常包含一系列下拉菜单,如"文件"、"编辑"和"帮助"等。在QT中,可以使用`QMenuBar`类来创建和管理菜单栏。你可以通过`addMenu()`方法添加新的菜单,然后在菜单中添加动作(`...

Global site tag (gtag.js) - Google Analytics