如何在Qt中迭代菜单的操作?

时间:2012-02-22 17:24:38

标签: qt qmenu qmenubar

我在一个项目中工作,我需要自动打开(显示或弹出)QMenuBar中的项目。

假设我有下一个菜单栏:

 File     Edit      Help
   -op1     -op1      -op1
   -op2     -op2      -op2

要设置操作(显示与该操作相关的菜单),我使用:

menuBar->setActiveAction(mymenuactionpointer);

据我所知,我可以使用以下其中一项来获取指向QMenuBar元素的指针列表:

QMenuBar::actions();

QList<Object*> lst1 = QMenuBar::findChildren<QObject*>();

QList<Object*> lst2 = QMenuBar::findChildren<QAction*>();

当我使用QMenuBar::findChildren<QAction*>()MenuBar::actions()时,我得到菜单栏中的菜单列表,我的意思是,我从QMenuBar获得"File, Edit, Help",在这种情况下,QList的大小是3。

当我使用QMenuBar::findChildren<QObject*>()时,我得到了一个大小为6的QObject列表,它是菜单栏中正确的项目数。但是,我已经尝试过演员QAction *

QAction *a = (QAction *)lst1.at(0);
QAction *a = qobject_cast<QAction*>(lst1.at(0));
QAction *a = dynamic_cast<QAction*>(lst1.at(0));

在所有这些情况下,a不是NULL,但是当我尝试获取操作名称QAction::title()时,它总是导致我出现分段错误。

我一直在搜索,我发现here在获取菜单栏操作列表后,可以询问QAction::menu()(如果项目是菜单则返回有效的QMenu指针)以了解是否item是QMenu,如果是,可以重复获取该菜单的动作列表,并继续迭代。但这对我不起作用,我期待

QList<Object*> lst2 = QMenuBar::findChildren<QAction*>();

每个元素“文件,编辑帮助”QAction::menu()都会返回一个有效的菜单指针,因此我可以获取每个菜单的操作列表,但这对我来说根本不起作用。

我非常感谢您的时间和帮助,我希望这个问题可以帮助更多人。我真的很难过。

提前致谢。

4 个答案:

答案 0 :(得分:19)

枚举QMenu的正确方法是使用actions()函数,但有一个问题 - 一些操作是子菜单,它们需要递归迭代。事实上,每个QMenu都与QAction相关联,并且它们都互为指针 - 请参阅QMenu::menuAction()QAction::menu()

了解每个QMenu还与QAction相关至关重要。所以知道,正确的实现如下:

void enumerateMenu(QMenu *menu)
{
    foreach (QAction *action, menu->actions()) {
        if (action->isSeparator()) {
            qDebug("this action is a separator");
        } else if (action->menu()) {
            qDebug("action: %s", qUtf8Printable(action->text()));
            qDebug(">>> this action is associated with a submenu, iterating it recursively...");
            enumerateMenu(action->menu());
            qDebug("<<< finished iterating the submenu");
        } else {
            qDebug("action: %s", qUtf8Printable(action->text()));
        }
    }
}

答案 1 :(得分:7)

下面是如何遍历菜单栏中的每个菜单项,它还会搜索下面的任何菜单,因此这里不需要递归调用。

// assuming you have a private QActionGroup* actions; defined in the header..
// ...and a slot named 'onAction(QAction*)' as well... this should work:
QList<QMenu*> lst;
lst = ui->menuBar->findChildren<QMenu*>();
actions = new QActionGroup(this);
foreach (QMenu* m, lst)
{
    foreach (QAction* a, m->actions())
    {
        actions->addAction(a);
    }
}
connect(actions,SIGNAL(triggered(QAction*)),this,SLOT(onAction(QAction*)));

正如您所看到的,您可以连接一个主插槽来处理动作可能带来的各种事件(我刚刚在这里显示触发,但您明白了)。希望这有助于......某人..

注 我使用QActionGroup作为示例目的使用你可能会迭代的列表,但你真的不应该使用它,除非你正在处理无线电组,因为那是它的用途。其次,如果您想要操作,因为您计划将它们链接到一个方法来处理所有项目,我建议您使用QMenu的触发/悬停信号,或者如果您需要知道菜单即将弹出的时候,您需要QMenuBar的aboutToShow()信号。我无法想到一个原因(对我来说无论如何)你不能在那些信号中做你需要的,因为你在插槽中通过了QAction *。但是如果你必须在其他方面做到这一点,你可以按照我上面展示的方式进行,你可能不想使用QActionGroup,因为无线电分组是它的设计目的。 (你可以通过不添加“可检查”的项目来解决这个问题。

答案 2 :(得分:0)

qobject_cast失败的原因是QMenuBar只有三个QAction作为父级。其他三个是不同的QObjects(我的猜测是三个QMenus),所以演员表失败了。然后,与那些菜单相关联的QActions不在根QMenuBar之下。我不明白为什么你不能通过递归迭代QMenus来建立QActions的主列表。

如果您在可能不会触发父菜单的已知菜单之后,可能能够仅使用UI定义中的QAction指针。如果您正在尝试自动化测试,那么您所需的QAction上的trigger()可能就像您需要的那样详细。如果您正在尝试响应用户操作而执行操作,则修改工具栏可能是更好的上下文反馈方式,因为它不会破坏焦点。关于你实际想要完成什么的更多细节会有所帮助。

答案 3 :(得分:0)

将这一切放在一起:

template <class Function>
class QMenuBarIterator {
    QMenuBar    *i_barP;

    void    iterate_sub(Function f, size_t tabsL, QMenu* m) {
        foreach (QAction *action, m->actions()) {
            f(tabsL, action);

            if (action->menu()) {
                iterate_sub(f, tabsL + 1, action->menu());
            }
        }
    }

    public:
    QMenuBarIterator(QMenuBar *barP) : i_barP(barP) {}

    virtual void operator()(size_t levelL, QAction *actionP) {
    }

    void    iterate(Function f) {
        QList<QMenu *>  menuBar = i_barP->findChildren<QMenu *>();

        foreach (QMenu* m, menuBar) {
            f(0, m->menuAction());
            iterate_sub(f, 1, m);
        }
    }
};

/***************************************************************************/
class CMenuLogger {
    public:

    void operator()(size_t tabsL, QAction *action) {
        SuperString     tabStr(GetIndentString(tabsL)); //  returns a string with tabsL tab characters in it

        if (action->isSeparator()) {
            qDebug("%s-------------------", tabStr.utf8Z());

        } else {
            qDebug("%s%s (%s)",
                tabStr.utf8Z(),
                qUtf8Printable(action->text()),
                qUtf8Printable(action->objectName()));
        }
    }
};

然后在你的主要:

{
    QMenuBarIterator<CMenuLogger>           bar(ui->menuBar);

    bar.iterate(CMenuLogger());
}