web-dev-qa-db-ja.com

Qtでメニューのアクションを繰り返す方法は?

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()を取得しようとすると、常にセグメンテーション違反が発生します。

私は検索していて、 ここ メニューバーのアクションリストを取得した後、QAction::menu()(アイテムがメニューの場合は有効なQMenuポインタを返す)に問い合わせることができることを発見しましたアイテムがQMenuの場合、はいの場合、そのメニューのアクションリストの取得を繰り返し、繰り返しを続けることができます。しかし、これは私にはうまくいきません、私は

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

各要素「ファイル、ヘルプの編集」QAction::menu()は有効なメニューポインタを返すため、各メニューのアクションのリストを取得できましたが、これはまったく機能しません。

私はあなたの時間とあなたの助けに本当に感謝します、私はこの質問がより多くの人々に役立つことを願っています。私はこれで本当に苦労しています。

前もって感謝します。

18
Herman

QMenuを列挙する正しい方法は、actions()関数を使用することですが、落とし穴があります。一部のアクションはサブメニューであり、再帰的に繰り返す必要があります。実際、各QMenuQActionに関連付けられており、どちらも相互のポインタを保持しています。 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()));
        }
    }
}
20
sashoalm

以下は、メニューバーのすべてのメニュー項目を反復処理する方法です。また、下にあるメニューも検索するため、ここで再帰的に呼び出す必要はありません。

// 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を使用しましたが、無線グループを扱っている場合を除いて、QActionGroupを使用しないでください。次に、すべてのアイテムを処理する単一のメソッドにアクションをリンクすることを計画しているためにアクションが必要な場合は、QMenuのトリガー/ホバリングシグナルを使用することをお勧めします。または、メニューがポップアップするタイミングを知る必要がある場合は、 QMenuBarのaboutToShow()シグナル。スロットでQAction *が渡されるため、これらの信号で必要なことを実行できない理由は(とにかく私にとっては)考えられません。ただし、他の方法で実行する必要がある場合は、上記の方法で実行できます。無線グループ化が目的であるため、QActionGroupを使用したくない場合があります。 (「チェック可能」なアイテムをグループに追加しないことで、これを回避できます。

7
osirisgothra

Qobject_castが失敗する理由は、QMenuBarを親とするQActionが3つしかないためです。他の3つは異なるQObjects(私の推測では3つのQMenus)であるため、キャストは失敗します。これらのメニューに関連付けられているQActionは、ルートQMenuBarではなく、それらの下にあります。 QMenuを再帰的に反復して、QActionのマスターリストを作成できない理由がわかりません。

親メニューをトリガーしない可能性のある既知のメニューを探している場合は、mayがUI定義からQActionポインターを使用できる可能性があります。テストを自動化しようとしている場合、目的のQActionのtrigger()はおそらく必要なだけ詳細です。ユーザーの操作に応じて何かをしようとしている場合、ツールバーを変更することは、フォーカスを壊さないため、コンテキストフィードバックのより良い手段である可能性があります。あなたが実際に達成しようとしていることについてのもう少しの詳細が役立つでしょう。

0
IAmRoot

これですべてがまとめられます。

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());
}
0
David M. Cotter