How to add a list of QActions to a QMenu and handle them with a single slot?

大城市里の小女人 提交于 2019-11-29 06:10:25

You can associate an index (or any other data) to each action when they are created with QAction::setData and connect the signal QMenu::triggered(QAction*) to your slot.

You'll then be able to retrieve the data through the QAction::data() function of your slot parameter.

MyClass::MyClass() {
    // menu creation
    for(...) {
        QAction *action = ...;
        action->setData(10);
        ...
        menu->addAction(action);
    }
    // only one single signal connection
    connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(mySlot(QAction*)));
}

void MyClass::mySlot(QAction *action) {
   int value = action->data().toInt();

}

Other methods: signal mapping or the use of sender(), are explained in that article of Qt Quaterly.

A more generic (not specific to QMenu) way to approach this is the QActionGroup class. This allows you to isolate specific menu items as a related group, or group different widgets together.

void MyClass::InitMenu(QMenu* menu)
{
    QActionGroup* actions1 = new QActionGroup(menu);
    actions1->setExclusive(false);
    actions1->addAction(menu->addAction(tr("Action1")))->setData(1);
    actions1->addAction(menu->addAction(tr("Action2")))->setData(2);
    actions1->addAction(menu->addAction(tr("Action3")))->setData(3);
    actions1->addAction(menu->addAction(tr("Action4")))->setData(4);
    actions1->addAction(menu->addAction(tr("Action5")))->setData(5);
    connect(actions1, SIGNAL(triggered(QAction*)), SLOT(MySlot(QAction*)));

    QActionGroup* actions2 = new QActionGroup(menu);
    actions2->addAction(menu->addAction(tr("Undo Action1")))->setData(1);
    actions2->addAction(menu->addAction(tr("Undo Action2")))->setData(2);
    //...
    connect(actions2, SIGNAL(triggered(QAction*)), SLOT(MyUndoSlot(QAction*)));
}

and in the slot:

void MyClass::MySlot(QAction* triggeredAction)
{
    // use either the action itself... or an offset
    int value = triggeredAction->data().toInt()
}

You can also have a QMap of QActions and ints and as soon as you add your action to the menu you can also add it to your map with a value that is +1 different from the previous one. You can then wire QAction::triggered to a generic slot, from where you can get the sender of the signal by calling sender(), dynamic cast it to a QAction and then look up with value in your map:

class MyClass {
public:
    void Init();
private slots:
    void onTriggered();
private:
    QMap<QAction*, int> _actionToInt;
}


MyClass::Init() {
    QMenu* menu = new QMenu();
    // Loop for illustration purposes
    // For general purpose keep an index and increment it every time you add
    for(int i=0; i<10; ++i) {
        QAction* action = menu->addAction("Item1");
        _actionToInt.insert(action, i);
        connect(action, &QAction::triggered, this, &MyClass::onTriggered);
    }
}

void MyClass::onTriggered() {
    QAction* action = qobject_cast<QAction*>(sender());
    //For safety purposes
    if (action && _actionToInt.contains(action) {
        //And here you have your index!
        int index = _actionToInt.value(action);
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!