如何将 QActions 列表添加到 QMenu 并使用单个插槽处理它们?

发布于 2025-01-03 16:25:20 字数 438 浏览 0 评论 0原文

首先,我有一个 QWidget 列表,直到运行时我才知道其长度。然后,我创建一个 QListWidget 来显示它们,当有人单击它们时,我使用信号 currentItemChanged(QListWidgetItem*, QListWidgetItem*) 来捕获它并获取单击的项目的索引。

现在我想在 QMenu 中做类似的事情。当 QMenu 及其操作构建时我会知道该列表,但我无法对其进行硬编码。

如何创建操作,捕获它们的信号并将它们连接到同一个插槽,该插槽根据操作在菜单列表中的位置(索引)执行不同的操作?必须有某种方法来解决这个问题,因为其他应用程序也使用它。我尝试查看映射,但无法理解如何使用它来实现此目的。

我尝试抓取插槽中的sender,但无法从中获取任何有用的信息。

First, I have a list of QWidgets that I won't know the length of until runtime. I then create a QListWidget where I show them and when someone clicks them I use the signal currentItemChanged(QListWidgetItem*, QListWidgetItem*) to catch it and get the clicked item's index.

Now I want to do a similar thing in the QMenu. I will know the list when the QMenu and its actions get built, but I won't be able to hard code this.

How can I create actions, catch their signals and connect them to the same slot which does different things depending on the action's position (index) in the menu list? There must be some way to solve this since other applications use this. I tried to look at mapping but I couldn't get my head around how to use it for this.

I tried to grab the sender in the slot but was not able to get any useful information from it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

热风软妹 2025-01-10 16:25:20

您可以在使用 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 Quarterly 的那篇文章

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.

为你拒绝所有暧昧 2025-01-10 16:25:20

解决此问题的更通用(并非特定于 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()
}

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()
}
浅笑依然 2025-01-10 16:25:20

您还可以拥有 QActionsintsQMap,一旦您将操作添加到菜单中,您也可以将其添加到地图中其值与前一个值相差 +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);
    }
}

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文