【问题标题】:Reset QMenu to accept new set of QActions重置 QMenu 以接受新的 QActions
【发布时间】:2018-02-20 14:12:08
【问题描述】:

我希望重置/重新创建自定义上下文菜单。我正在使用 QMenu 和 QAction(成员变量) 来实现这一点。

 QMenu* m_menu;
 QAction* m_actionTitle;

我的插槽是这样连接的:

connect(m_ui->actionLoad_Definition_File, &QAction::triggered, m_Item.get(),
        &Item::loadDefinitionFilesFromMenu);

工作部分:

在我的构造函数中,我设置了这样的东西:

 Item::Item(QWidget* parent)
 {
     // Connect context menu
     this->setContextMenuPolicy(Qt::CustomContextMenu);
     connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
        this,   SLOT(showContextMenu(const QPoint&)));  
 }


/* virtual */ void Item::showContextMenu(const QPoint& pos)
{
    // Obtain global position
    QPoint globalPos = mapToGlobal(pos);

   // Change the first menu entry to show the range
   m_actionTitle->setText(QString::number(m_from) + " - " +
                       QString::number(m_to));  //Access Violation error

   QAction* action = m_menu->exec(globalPos); 
   if (action != NULL)
   {
      if (action->text() == "something")
   {
        // Remove the item
        m_view->removeItem(this);
   }
   else
   {
        // Display the text
        setText(action->text());
        setColor(action->text());
        setToolTip(action->text());
        m_edit.setText(action->text());
        m_view->arrange();
   }
 }
}

我想要什么:

我想重置 m_menu 的所有操作并将新操作推入其中。因此,每当我右键单击时,都会出现新的上下文菜单。

问题:

创建 QToolButton 后,如果我右键单击它,我会收到“访问冲突错误”。调试它,m_menu 和 m_actionTitle 都超出范围或被简单地破坏。不知道为什么会这样。

到目前为止我做了什么:

void Item::loadDefinitionFilesFromMenu()
{
    //Clear the vector of existing values
    m_defaults.clear();
    //Clear the menu of actions
    m_menu->clear();

    QString file = QFileDialog::getOpenFileName(nullptr, "Choose a definition file", QString(),
                                            QString("(*.ad)"));

    if (!file.isNull())
    {
        MLParser ml;

        std::map<std::string, std::string> base = ml.readDefinitions(file.toStdString());

        for (auto const& gestureValues : base)
        {
            m_defaults.push_back(gestureValues.first);  // string (key)
        }

        m_menu = new QMenu(this);
        m_actionTitle = new QAction("Note", m_menu);
        m_actionTitle->setEnabled(false);
        m_menu->addAction(m_actionTitle);
        m_menu->addSeparator();

        for (std::vector<std::string>::iterator it = m_defaults.begin();
         it != m_defaults.end();
         ++it)
        {
            m_menu->addAction(QString::fromStdString(*it)); //works ok
        }

        m_menu->addSeparator();
    }
}

我想在整个程序中重复使用m_menu,但我无法让它重置并接受新的操作集。我在这里有什么遗漏吗?

编辑 1:

删除了构造函数中的QMenuQAction。仅在loadDefinitionFilesFromMenu 内。

【问题讨论】:

  • 我只是在每次打开上下文菜单时创建一个新菜单和操作。
  • 这个Item类是什么?有很多例子吗?为什么每个人都有自己的菜单?
  • 您从m_defaults 创建菜单操作并从定义文件中读取默认值。可能您每次都加载相同的file.ad
  • @vahancho no 你可以看到我正在使用文件对话框来选择不同的文件,我很确定它是不同的文件。
  • @p-a-o-l-o Item 类继承 QToolButton。是的,我在整个项目中使用了它的多个实例。

标签: c++ qt qmenu


【解决方案1】:

使菜单在所有Item 实例之间共享。

在项目类标题中:

private:
    static QMenu* m_menu;
    static QAction * m_actionTitle;
    static std::vector<std::string> m_defaults;

在Item类cpp中,定义之后和方法定义之前:

QMenu* Item::m_menu = 0;
QAction * Item::m_actionTitle = 0;
std::vector<std::string> Item::m_defaults;

菜单只实例化一次,在Item构造函数中:

if(m_menu == 0)
{
    m_menu = new QMenu();
    // load defaults here
}

无需再次实例化菜单:从loadDefinitionFilesFromMenu 中删除这一行:

m_menu = new QMenu(this);

关于你的m_actionTitle指针:不要给它分配一个新的QAction,让它保存addAction方法的返回值:

    m_actionTitle = m_menu->addAction("Note");
    m_actionTitle->setEnabled(false);
    m_menu->addSeparator();

最后,有一个静态方法来删除(唯一的)菜单实例。在头文件中:

static void dismissMenu();

在 cpp 中:

void Item::dismissMenu()
{
  delete m_menu;
}

你可以在退出之前调用这个方法,在QApplication::exec返回之后:

Item::dismissMenu();

【讨论】:

  • 我编辑了答案,希望现在可以了。不过,不确定m_defaults 是否需要是静态的。
  • 我想出了与静态类似的东西。在尝试您的代码时,我在m_actionTitle = m_menu-&gt;addAction("Note", m_menu) 收到错误消息。通过 addActions 重载,我看到它需要某种插槽或指向对象的指针。因此我想是信号槽错误。不确定是不是因为它是静态的。 error C2338: Signal and slot arguments are not compatibleerror C2228: left of '.()' must have class/struct/union
  • 我已经编辑了您的部分代码以使其正确。这种组合实际上对我有用。您指出静态内容仍然归功于您,因此我会将您的评论标记为答案。
  • 为什么我需要明确删除m_menu,即使它有父对象?
  • 好的@MarKS,我回滚到我最初的答案:不要父菜单!它是静态的,所以它是共享的。如果父母超出范围怎么办?共享菜单将被删除...我还纠正了一个错误,它是 m_menu-&gt;addAction("Note"); 应该现在编译的行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-17
  • 2023-03-03
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
相关资源
最近更新 更多