Как добавить список QActions в QMenu и обработать их одним слотом? - PullRequest
12 голосов
/ 08 февраля 2012

Во-первых, у меня есть список QWidget с, продолжительность которого я не буду знать до времени выполнения.Затем я создаю QListWidget, где я показываю их, и когда кто-то щелкает по ним, я использую сигнал currentItemChanged(QListWidgetItem*, QListWidgetItem*), чтобы поймать его и получить индекс выбранного элемента.

Теперь я хочу сделать то же самое в QMenu.Я буду знать список, когда QMenu и его действия будут созданы, но я не смогу жестко закодировать это.

Как я могу создавать действия, ловить их сигналы и подключать их к одному и тому же слотучто делает разные вещи в зависимости от позиции (индекса) действия в списке меню?Должен быть какой-то способ решить эту проблему, так как другие приложения используют это.Я пытался взглянуть на отображение, но не мог понять, как его использовать для этого.

Я пытался захватить sender в слоте, но не смог получить от него никакой полезной информации..

Ответы [ 3 ]

17 голосов
/ 08 февраля 2012

Вы можете связать индекс (или любые другие данные) с каждым действием, когда они создаются с помощью QAction::setData, и подключить сигнал QMenu::triggered(QAction*) к вашему слоту.

После этого вы сможете получить данные с помощью функции QAction::data() параметра вашего слота.

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();

}

Другие методы: отображение сигнала или использование sender(), объясняются в этой статье Qt Quaterly .

4 голосов
/ 15 июля 2015

Более общий (не специфичный для QMenu) способ приблизиться к этому - класс QActionGroup .Это позволяет вам выделять отдельные пункты меню как связанную группу или группировать разные виджеты вместе.

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*)));
}

и в слоте:

void MyClass::MySlot(QAction* triggeredAction)
{
    // use either the action itself... or an offset
    int value = triggeredAction->data().toInt()
}
0 голосов
/ 15 августа 2018

Вы также можете иметь QMap из QActions и ints, и как только вы добавите свое действие в меню, вы также можете добавить его на свою карту со значением +1, отличным от предыдущего.,Затем вы можете подключить QAction::triggered к общему слоту, откуда вы можете получить отправителя сигнала, вызвав sender(), динамически приведя его к QAction, а затем ищите значение на вашей карте:

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);
    }
}
...