何时以及如何正确销毁QMenu上下文菜单?

时间:2016-08-31 22:19:09

标签: c++ qt qmenu

我允许自定义上下文菜单显示在表格上。这是使用接受目标小部件和坐标的通用函数生成菜单的方式:

#include <QMenu>
void MainWindow::makeContextMenu(const QPoint& pos, QWidget* target)
{
    QMenu *menu = new QMenu(this);
    menu->addAction(new QAction("Action 1", menu));
    menu->addAction(new QAction("Action 2", menu));
    menu->addAction(new QAction("Action 3", menu));
    // Notify window about clicking
    QObject::connect(menu, &QMenu::triggered, this, &MainWindow::menuClicked);
    // If this is a scroll area, map coordinates to real app coordinates
    if(QAbstractScrollArea* area = dynamic_cast<QAbstractScrollArea*>(target))
        menu->popup(area->viewport()->mapToGlobal(pos));
    else
        menu->popup(pos);
}

问题是QMenu* menu永远不会被破坏并从内存中删除。即使隐藏了MainWindow的孩子,它也会一直存在。

我该怎么办?我可以将菜单设置为自行删除吗?或者我应该重复使用相同的菜单实例,还是将其保存到同一个指针中?

3 个答案:

答案 0 :(得分:3)

在您的代码中,似乎应该在此事件发生后删除menu

// Notify window about clicking
QObject::connect(menu, &QMenu::triggered, this, &MainWindow::menuClicked);
  

我可以将菜单设置为自行删除吗?

是的,您可以像这样拥有对象delete itself

// Notify window about clicking
QObject::connect(menu, &QMenu::triggered, this, &MainWindow::menuClicked);
QObject::connect(menu, &QMenu::triggered, menu, &QMenu::deleteLater);

如果您担心要调用这些广告位的顺序,请参阅this

  

或者我应该重复使用相同的菜单实例,也可以将其保存到同一菜单中   指针?

嗯,你可以做点什么

//Your constructor
MainWindow::MainWindow(....)
{
    menu = nullptr;
    ....
}

//Make context Menu
void MainWindow::makeContextMenu(const QPoint& pos, QWidget* target)
{
    if(menu)
        delete menu; 
    menu = new QMenu(this);
    ....
}

对于MainWindow::~MainWindow()析构函数,它会处理menu的清理工作。由于MainWindowQObject派生类)automatically deletes所有孩子

最后,您可以将menu作为MainWindow的成员,只要您需要对menu采取新的操作,就可以使用QMenu::clear删除所有现有的行动。

//Your constructor
MainWindow::MainWindow(....)
{
    menu = new QMenu(this);
    ....
}

void MainWindow::makeContextMenu(const QPoint& pos, QWidget* target)
{
    menu->clear();
    //QMenu *menu = new QMenu(this);
    menu->addAction(new QAction("Action 1", menu));
    menu->addAction(new QAction("Action 2", menu));
    menu->addAction(new QAction("Action 3", menu));
    // Notify window about clicking
    QObject::connect(menu, &QMenu::triggered, this, &MainWindow::menuClicked);
    // If this is a scroll area, map coordinates to real app coordinates
    if(QAbstractScrollArea* area = dynamic_cast<QAbstractScrollArea*>(target))
        menu->popup(area->viewport()->mapToGlobal(pos));
    else
        menu->popup(pos);
}

答案 1 :(得分:1)

不必太复杂。就是这样了:

$ cat foo.jsonnet 
local foo = import "foo.libsonnet";
[ foo["foo1"], foo["foo2"] ]

$ cat foo.libsonnet 
{
  foo1: "bar1",
  foo2: "bar2",
}

$ jsonnet foo.jsonnet 
[
   "bar1",
   "bar2"
]

这样,当QMenu关闭时,一旦再次进入事件循环,该类即被删除。而且,是否触发了操作或仅关闭弹出窗口都没有关系。

要证明我的答案,您可以通过检查菜单的创建时间以及是否使用相同的地址触发了“已删除”消息来对其进行自我测试:

menu->setAttribute(Qt::WA_DeleteOnClose);

答案 2 :(得分:0)

隐藏时可以删除QMenu。我为此目的设计了事件过滤器类:

#ifndef DELETEONHIDEFILTER_H
#define DELETEONHIDEFILTER_H

#include <QObject>
#include <QEvent>

class DeleteOnHideFilter : public QObject
{
        Q_OBJECT
    public:
        explicit DeleteOnHideFilter(QObject *parent = 0) : QObject(parent) {}

    protected slots:
        bool eventFilter(QObject *obj, QEvent *event) override {
            if(event->type() == QEvent::Hide) {
                obj->deleteLater();
            }
            return false;
        }
};

#endif // DELETEONHIDEFILTER_H

它也可以用于其他物体。