【问题标题】:QWidget can we get/modify existing context menu of a widgetQWidget 我们可以获取/修改小部件的现有上下文菜单吗
【发布时间】:2014-10-29 08:43:09
【问题描述】:

我有第三方小部件,它为我提供了一些上下文菜单。可以说剪切,复制粘贴,全选。 现在我只想修改现有上下文菜单的粘贴功能。我知道我可以在contextMenuEvent 中从头开始实现整个上下文菜单。但我不想这样做,因为我对其他上下文菜单操作很满意,只想修改粘贴功能。

我在 Mac OSX 上使用 QT 4.8。

如果目前无法做到这一点,有人可以给我链接/参考吗?这样我就可以满足我的利益相关者。

编辑:为了更清楚地了解我想要做的是,出于某种原因禁用粘贴上下文菜单,并希望稍后根据情况/事件启用它。

【问题讨论】:

  • 看看装饰器模式:en.wikipedia.org/wiki/Decorator_pattern
  • 只是为了确保:您的第 3 方小部件是 QWidget,即写在Qt 上吗?
  • @Ezee:是的,我已经看过头文件了。顶级类继承自 QWidget。
  • @Merlin069:我已经继承了第三方类。问题是在 contextMenuEvent 中,我可以从头开始创建整个上下文菜单,但我不知道如何获取/修改现有的上下文菜单。

标签: qt qt4


【解决方案1】:

我不确定它是否可以以通用方式完成。 这是一个棘手的解决方案:

contextMenuEvent 中创建对某个插槽的排队调用:

QMetaObject::invokeMethod(this, "patchMenu", Qt::QueuedConnection);

在插槽中获取可见窗口并找到QMenu。从中获取操作并启用/禁用它们:

Q_SLOT patchMenu()
{
  QWidgetList widgets = QApplication::topLevelWidgets();
  foreach (QWidget* widget, widgets)
  {
    if (QMenu* menu = qobject_cast<QMenu*>(widget))
    {
        QList<QAction*> actions = menu->actions();
        // here you can either get an action by index actions[5]
        // or search the action by text
        actions;
    }
  } 
}

编辑:
这是一个演示此方法的工作示例: 窗口.h

#pragma once
#include <QtGui>

class Window: public QMainWindow
{
    Q_OBJECT
public:
    Window(QWidget *parent = 0);
};

class A : public QWidget
{
public:
    virtual void contextMenuEvent(QContextMenuEvent* e);
};

class B : public A
{
    Q_OBJECT;
public:
    virtual void contextMenuEvent(QContextMenuEvent*);

    Q_SLOT void patchMenu();
};

window.cpp

#include "window.h"

Window::Window(QWidget *parent) : QMainWindow(parent)
{
    setCentralWidget(new B());
}

void B::patchMenu()
{
    QWidgetList widgets = QApplication::topLevelWidgets();
    foreach (QWidget* widget, widgets)
    {
        if (QMenu* menu = qobject_cast<QMenu*>(widget))
        {
            QList<QAction*> actions = menu->actions();
            // here you can either get an action by index actions[5]
            // or search the action by text
            actions;
        }
    }   
}

void B::contextMenuEvent(QContextMenuEvent* e)
{
    QMetaObject::invokeMethod(this, "patchMenu", Qt::QueuedConnection);
    A::contextMenuEvent(e);
}

void A::contextMenuEvent(QContextMenuEvent* e)
{
    QMenu menu;
    QAction* action = new QAction(QIcon(), "text", &menu);
    menu.addAction(action);
    menu.exec(e->globalPos());
}

【讨论】:

  • 我已应用上述代码并打印出操作文本和快捷方式。此解决方法向我展示了每个小部件的每个操作,但不幸的是上下文菜单操作不存在。尽管如此,解决方法是 +1。
  • 添加了一个您可以运行并确保其正常工作的示例。您无法获取每个小部件的操作,因为它会过滤掉除 QMenu 之外的所有内容。
  • 是的,每个小部件的每个操作我的意思是 QMenu 操作。我已经将您的代码与我的代码进行了比较。唯一的逻辑区别是基类 contextMenuEvent 调用的顺序。我先调用 A::contextMenuEvent(e),然后调用 QMetaObject::invokeMethod(...)。现在我以你的方式应用它,我可以看到上下文菜单操作列表。谢谢哥们:)。但是一个更奇怪的问题是这样做的正确方法吗?我的意思是禁用一项操作,您必须通过所有小部件及其操作。
  • “遍历”不是问题,但是假设基本小部件每次显示菜单时都不会重新创建操作,您可以在找到时存储指向您需要的操作的指针它是第一次,然后使用这个指针来启用/禁用操作。但如果它确实每次都重新创建操作,那么使用指针会导致崩溃。
  • 说得好,我明白了。不幸的是,我没有顶级基类的源代码。所以我必须先尝试一下,然后应用最适合我的解决方案。再次感谢您帮助我,接受您的解决方案。竖起大拇指。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多