Как добавить список QActions в QMenu и обработать их с помощью одного слота?
во-первых, у меня есть список QWidget
s, что я не буду знать длину до выполнения. Затем я создаю QListWidget
где я показываю их, и когда кто-то нажимает на них, я использую сигнал currentItemChanged(QListWidgetItem*, QListWidgetItem*)
, чтобы поймать его и получить индекс выбранного элемента.
теперь я хочу сделать аналогичную вещь в QMenu
. Я буду знать список, когда QMenu
и его действия строятся, но я не смогу жестко кодировать это.
как я могу создавать действия, ловить их сигналы и подключать их к тот же слот, который делает разные вещи в зависимости от позиции действия (индекса) в списке меню? Должен быть какой-то способ решить эту проблему, так как другие приложения используют это. Я попытался посмотреть на карту, но не мог понять, как ее использовать.
Я попытался схватить sender
в слоте, но не смог получить от него никакой полезной информации.
3 ответов
вы можете связать индекс (или любые другие данные) с каждым действием, когда они создаются с 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.
более общий (не специфичный для 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()
}
вы можете QMap
of 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);
}
}