点击右键弹出QMenu的使用问题。



转至元数据结尾

 

转至元数据起始

 

目前来看QMenu的使用存在这几个问题。

1、如果使用了临时变量的QMenu,并且没有指定父窗体,例如:

QMenu menuDemo;

menuDemo.addAction(“test”);

menuDemo.exec();

那么会存在一个问题,就是如果使用某个快捷键将QMenu所在的Widget给关闭掉,QMenu并不会随着消失,这样子在流程上就存在着问题。

 

2、如果使用了临时变量的QMenu,并且指定父窗体,例如:

QMenu menuDemo(this);

menuDemo.addAction(“test”);

menuDemo.exec();

那么会存在一个问题,就是如果使用某个快捷键将QMenu所在的Widget给关闭掉,QMenu的父窗体会delete一次QMenu,然后QMenu作为临时变量又会被delete一次,就会导致crash的问题。

 

3、如果使用了指针QMenu,并且没有指定父窗体,例如:

QMenu *menuDemo = new QMenu;

menuDemo->addAction(“test”);

menuDemo->exec();

那么情况将会和1一样,使用某个快捷键将QMenu所在的Widget关闭掉,QMenu不会随着消失,改变了原本的流程,并且因为使用了指针,还会造成内存泄露。

 

综上所述,所以在使用QMenu的时候一定要使用指针的QMenu, 并且需要明确指定他的父窗体。例如在Preview这个Widget右键弹出一个QMenu,就需要用如下的方式进行创建

QMenu *menuDemo = new QMenu(Preview);

menuDemo->addAction(“test”);

menuDemo->exec();

这样子就可以保存在使用快捷键关闭Preview的时候,可以将menuDemo关闭,且销毁,不会造成内存泄露。

 

但是目前所说都是在关闭QMenu父窗体的时候,连带的将QMenu 销毁,不会造成内存泄露,但是如果没有销毁QMenu的父窗体,而是点击QMenu的时候造成的QMenu关闭,那么上面的写法依赖会造成内存泄露,所以此时就要使用QMenu的一个属性setAttribute(Qt::WA_DeleteOnClose), 这样就可以保证QMenu关闭的时候一定会被销毁,不会造成内存泄漏。

 

之所以这么修改就是为了解决目前再使用QMenu中存在的两个问题,一个是内存泄露,一个重复delete造成crash。如下的两个错误示例:

该示例中,如果在弹出QMenu的时候,如果使用快捷键(Ctrl+w)关闭文档,就会造成QMenu被析构两次,出现crash。

该示例就是会造成QMenu的内存泄露。

 

总结:

所以我们在使用QMenu的时候需要注意:

  1. 采用指针。

  2. 明确QMenu的父窗体

  3. 设置属性WA_DeleteOnClose

就像这样:

QMenu *menuDemo = new QMenu(Preview);

menuDemo->setAttribute(Qt::WA_DeleteOnClose);

menuDemo->addAction(“test”);

menuDemo→exec();

 

补充:如果QMenu中存在存在子Menu,需要将子Menu的parent设置为父Menu,否则可能会出现父Menu关闭了,但是子Menu没有关闭。

QMenu *menuDemo = new QMenu(Preview);

QMenu *subMenu = new QMenu("subMenu", menuDemo);

menuDemo->setAttribute(Qt::WA_DeleteOnClose);

menuDemo→addAction(“test”);

menuDemo->addMenu(subMenu);

menuDemo→exec();

 

补充:QMenu的exec中可能会存在的问题,假如现在有一个场景:存在一个Widget,做了右键操作,代码如下:

QMenu *menuDemo = new QMenu(Widget);

menuDemo->setAttribute(Qt::WA_DeleteOnClose);

menuDemo->addAction(“test”);

menuDemo→exec();

Widget.update();

但是你最后的在exec后还有使用到该Widget,但是实际上通过快捷键的方式可以再QMenu执行exec的时候将Widget销毁,这个时候就会造成Widget野指针,导致crash问题,对于该问题目前有两种想法,一种可以采用QMenu的popup这种异步的方式,然后将Widget.update()放入到对应的test的action中执行,这种方式对流程上可能会有所改变,所以需要对应的模块具体问题具体进行分析。

另外一种就是可以考虑采用只能指针的方式,代码如下:

QMenu *menuDemo = new QMenu(Widget);

QPointer<QWidget> pointer= Widget;

menuDemo->setAttribute(Qt::WA_DeleteOnClose);

menuDemo->addAction(“test”);

menuDemo→exec();

if(!pointer)

    return;

Widget.update();

就是采用智能指针来判断该Widget是否已经被释放,如果已经被释放则不再往下执行。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM