點擊右鍵彈出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