确定在Qt​​中按下了哪个快捷方式

时间:2018-06-06 12:44:46

标签: c++ qt qt-signals qaction

我有一个QAction,我为它分配了多个快捷方式

   test = new QAction();
   this->addAction(test);
   QList<QKeySequence> shortcuts;
   shortcuts << QKeySequence(Qt::Key_N) << QKeySequence(Qt::Key_T);
   test->setShortcuts(shortcuts);
   connect(test,SIGNAL(triggered()),this,SLOT(SomeFucntion()))

SomeFucntion我需要知道哪个快捷方式被按下了......反正知道了吗?

2 个答案:

答案 0 :(得分:3)

您可以尝试使用QSignalMapper更精细的模式,避免需要定义尽可能多的快捷操作,但需要c ++ 11(至少这个实现)。

在窗口的构造函数中,使用以下代码声明QShortcut个对象和QSignalMapper

QSignalMapper* signalMapper = new QSignalMapper(this);
QShortcut* sc1 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_N), this);
QShortcut* sc2 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_T), this);

connect(sc1, &QShortcut::activated, signalMapper, static_cast<void (QSignalMapper::*)(void)>(&QSignalMapper::map));
connect(sc2, &QShortcut::activated, signalMapper, static_cast<void (QSignalMapper::*)(void)>(&QSignalMapper::map));

signalMapper->setMapping(sc1, sc1);
signalMapper->setMapping(sc2, sc2);

QAction* action = new QAction();
connect(signalMapper, static_cast<void (QSignalMapper::*)(QObject*)>(&QSignalMapper::mapped),
    [action](QObject *object){

    QShortcut* sc = qobject_cast<QShortcut*>(object);
    if (sc)
    {
        action->setData(sc->key().toString());
        action->trigger();
    }
});

connect(action, &QAction::triggered, this, &MainWindow::doStuff);

由于QSignalMapper的工作方式,第三个连接是必需的:当激活一个快捷方式时,由于第一个和第二个连接将触发map()插槽,它将被通知给QSignalMapper。

QSignalMapper :: map()插槽将扫描其映射,使用setMapping()API创建,其第一个参数是映射对象,第二个是用于发出mapped()插槽的参数一旦确定了发射对象,就可以使用QSignalMapper。为此,它使用sender()方法,并简单地将返回的指针与作为映射提供的映射QObject指针进行比较。

一旦识别出QObject,QSignalMapper将发出QSignalMapper :: mapped(QObject *)信号,其参数是给予setMapping的第二个参数,在这种情况下它与第一个相同,也就是指针到已激活的QShortcut。

我使用lambda来捕获这个信号,在这个lambda中,我只是检查给定的参数是否为QShortcut指针,并在触发之前将其键序列存储在QAction 的数据成员中。行动本身。然后,QAction :: trigger()槽将发出QAction :: triggered()信号,该信号将依次调用您的自定义槽,在本例中为doStuff()。在那里,您可以检索键序列并使用它执行您想要的操作。

所以你的插槽实现应该与这个类似:

void MainWindow::doStuff()
{
    // use sender() to fetch data from action
    QAction* act = qobject_cast<QAction*>(sender());
    if (act)
    {
        QString sequence = act->data().toString();

        // debug output will show you the triggering key sequence
        qDebug() << sequence;

        // use sequence string to determine which shortcut was used

        // On Mike hint: better to reset data after use :)
        act.setData(QVariant());
    }
}

请注意,我使用基于QObject指针的映射。通过这种方式,您可以重用signalMapper实例来连接来自其他类型的QObject(例如QPushButtons)的事件,并在自定义槽中识别它们,并为QAction数据成员设置适当的值,可以存储通用的QVariant istance。

同样在使用QShortcut时,请注意他们的contex,即它们处于活动状态时,因为它可能位于窗口小部件或窗口范围内。

不幸的是,这种模式违反了纯粹的oop原则,但可能比为同一目的管理许多操作(图标,文本,工具提示等......)更好。

编辑:回答评论

首先,让我澄清一下你当然可以跳过使用QSignalMapper。这只是一个可能的解决方案(不是更好,可能是一种过度杀伤......但在性能方面并不是真的更差)。

更简单的方法,正如迈克在评论中所指出的那样,每个QShotcut ::激活信号使用lambdas,但这会导致复制/粘贴代码,我总是试图避免。 您可以在MainWindow中定义自定义槽,并使用sender()捕获QShortcut并在触发之前准备好操作。

无论如何,QSignalMapper恕我直言,更好地解释你在做什么(从语义的角度来看),并且在你需要扩展与其他QObject的连接时也更灵活,同时支持其他类型的映射。

此外,但这与我的个人品味有关,我喜欢将逻辑上绑定的代码片段压缩成小片段,而不是让它在几个插槽/函数中稀疏,因为它使得它更容易阅读和当我需要更改它时追溯,当然只有这不会损害代码本身的质量。

答案 1 :(得分:2)

您应为每个快捷方式创建单独的QAction,并使用QSignalMapper对其进行分组。