c++ - 确定在 Qt 中按下了哪个快捷方式

标签 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 中,我需要知道按下了哪个快捷方式....无论如何都知道吗?

最佳答案

您可以使用 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 的工作方式,第三个连接是必需的:当快捷方式被激活时,由于第一个和第二个连接,它将被通知到 QSignalMapper,这将触发 map() 槽。

QSignalMapper::map() 槽将扫描其映射,由 setMapping() API 生成,其第一个参数是映射对象,第二个参数是将用于发出 mapped() 槽的参数QSignalMapper 的,一旦发射对象被识别。为此,它使用 sender() 方法并将返回的指针与您作为映射提供的映射 QObject 指针进行简单比较。

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

我使用了一个 lambda 来捕捉这个信号,在这个 lambda 中我简单地检查给定的参数是一个 QShortcut 指针,并将它的键序列存储在 QAction 的数据成员中 before行动本身。然后 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 实例。

另外,在使用 QShortcut 时,请注意它们的 contex ,即它们处于事件状态时,因为它可能在小部件或窗口范围内。

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

编辑:回答评论

首先,让我澄清一下,您当然可以完全跳过 QSignalMapper 的使用。这只是一个可能的解决方案(不是更好,也许是矫枉过正......但在性能方面并不是真的更差)。

正如 Mike 在评论中指出的,一种更简单的方法是对每个 QShotcut::activated 信号使用 lambda,但这会导致复制/粘贴代码,我总是尽量避免这种情况。 您可以改为在 MainWindow 中定义一个自定义插槽,并使用 sender() 来捕获 QShortcut 并在触发它之前准备操作。

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

此外,但这与我的个人品味有关,我喜欢将逻辑上相关的代码片段压缩成小片段的想法,而不是将它们分散在多个插槽/函数中,因为这样更容易阅读和理解在我需要更改它时进行追溯,当然前提是这不会损害代码本身的质量。

关于c++ - 确定在 Qt 中按下了哪个快捷方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50720742/

相关文章:

c++ - 函数中无法识别类的成员函数

c++ - C++ 中的 gslice 定义

c++ - 如何检测不再响应的事件 x 组件?

python - 如何连接到列代表的信号

qt - 如何获取给定小部件的所有信号集?

c++ - 使用通配符 C++ 从当前目录打开文件

c++ - 为什么要将 operator< 定义为非成员?

c++ - Qt - 使用 QSlider 放大/缩小

c++ - Qt 方法从另一个类调用?

c++ - Qt多重继承和信号