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

Her*_*man 17 qt qmenu qmenubar

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

假设我有下一个菜单栏:

 File     Edit      Help
   -op1     -op1      -op1
   -op2     -op2      -op2
Run Code Online (Sandbox Code Playgroud)

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

menuBar->setActiveAction(mymenuactionpointer);
Run Code Online (Sandbox Code Playgroud)

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

QMenuBar::actions();
Run Code Online (Sandbox Code Playgroud)

要么

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

QList<Object*> lst2 = QMenuBar::findChildren<QAction*>();
Run Code Online (Sandbox Code Playgroud)

当我使用QMenuBar::findChildren<QAction*>()或者MenuBar::actions()我在菜单栏中获得菜单列表时,我的意思是,我"File, Edit, Help"从我的QMenuBar获得,在这种情况下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));
Run Code Online (Sandbox Code Playgroud)

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

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

QList<Object*> lst2 = QMenuBar::findChildren<QAction*>();
Run Code Online (Sandbox Code Playgroud)

每个元素"文件,编辑帮助" QAction::menu()返回一个有效的菜单指针,所以我可以得到每个菜单的动作列表,但这对我来说根本不起作用.

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

提前致谢.

sas*_*alm 21

枚举a的正确方法QMenu是使用actions()函数,但是有一个catch - 一些动作是子菜单,它们需要递归迭代.事实上,每个QMenu都与a相关联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()));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


osi*_*hra 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*)));
Run Code Online (Sandbox Code Playgroud)

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

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


小智 0

qobject_cast 失败的原因是只有三个以 QMenuBar 作为父级的 QAction。其他三个是不同的 QObject(我猜是三个 QMenus),因此转换失败。与这些菜单关联的 QAction 位于这些菜单之下,而不是根 QMenuBar。我不明白为什么你不能通过递归迭代 QMenus 来构建 QActions 主列表。

如果您在使用已知菜单,则可能可以仅使用 UI 定义中的 QAction 指针,这可能不会触发父菜单如果您正在尝试自动化测试,那么您所需的 QAction 上的 trigger() 可能会如您所需要的那样详细。如果您尝试响应用户操作,修改工具栏可能是上下文反馈的更好方法,因为它不会破坏焦点。有关您实际想要完成的任务的更多详细信息将会有所帮助。