简体   繁体   English

在Qt 4中无法在eventFilter中检测到多个按键

[英]Cannot detect multiple keypresses in eventFilter in Qt 4

I am trying to understand the event filtering mechanism in Qt. 我试图了解Qt中的事件过滤机制。 To that effect, I have subclassed QLineEdit and tried to capture any key presses before the actual QLineEdit does. 为此,我已经将QLineEdit子类化,并尝试在实际的QLineEdit之前捕获任何按键。 The code I have written (mostly pasted from the Qt documentation) partially works: if I press any one key, the QLineEdit correctly says "Ate key press LETTER". 我编写的代码(主要是从Qt文档粘贴)部分有效:如果我按任意一个键,QLineEdit正确地说“Ate key press LETTER”。

If I press down the Option key (I am on a Mac) and press, say, "S", I correctly get "Ate key press ∫"; 如果我按下Option键(我在Mac上)并按下,比如说“S”,我正确地按“Ate键按∫”; however, if I press again "S" while still holding down the Option key, the QLineEdit reads "Ate key press ∫∫", which I cannot explain. 但是,如果我在按住Option键的同时再次按下“S”,则QLineEdit会显示“Ate键按∫∫”,这是我无法解释的。 It looks like this second (and subsequent) press of the key "S" is not a QKeyEvent or QShortcutEvent and is delivered directly to the actual widget but then, what kind of event is it? 看起来第二次(和后续)按键“S”不是QKeyEvent或QShortcutEvent并直接传递给实际的小部件但是,它是什么类型的事件?

To further complicate things, if, while holding down the Option key, I press a key other than "S", the results vary depending on which key is it. 更复杂的是,如果在按住Option键的同时按下“S”以外的键,结果会根据哪个键而变化。 For instance, for the key sequence Option+{S,D,F,G,H}, the QLineEdit reads "Ate key press ∫∂ƒ™". 例如,对于键序列Option + {S,D,F,G,H},QLineEdit读取“Ate键按下∫∂ƒ™”。 However, if I go on to press "J", then the QLineEdit reads only "Ate key press ¶". 但是,如果我继续按下“J”,那么QLineEdit只读取“Ate keypress¶”。

Can anyone replicate this behaviour and, better yet, explain it? 任何人都可以复制这种行为,更好的是,解释一下吗? Thank you all in advance. 谢谢大家。

main.cpp : main.cpp

#include <QApplication>
#include "customlineedit.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    CustomLineEdit w;
    w.show();
    return a.exec();
}

customlineedit.h customlineedit.h

#ifndef CUSTOMLINEEDIT_H
#define CUSTOMLINEEDIT_H

#include <QLineEdit>

class CustomLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit CustomLineEdit(QWidget *parent = 0);
    virtual bool eventFilter(QObject *watched, QEvent *event);
};

#endif // CUSTOMLINEEDIT_H

customlineedit.cpp customlineedit.cpp

#include "customlineedit.h"
#include <QKeyEvent>

CustomLineEdit::CustomLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
    this->installEventFilter (this);
}

bool CustomLineEdit::eventFilter (QObject *watched, QEvent *event)
{
    if (event->type () == QEvent::KeyPress
        || event->type () == QEvent::ShortcutOverride) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        this->setText("Ate key press " + keyEvent->text());
        return true;
    } else if (event->type () == QEvent::Shortcut) {
        this->setText ("Shortcut event");
        return true;
    } else {
        return false;
    }
}

There's a lot of unusual stuff going on there. 那里有很多不寻常的东西。

First, event filters are meant to allow a QObject to receive and optionally react to events intended for another QObject. 首先,事件过滤器旨在允许QObject接收并可选地响应用于另一个QObject的事件。 What you are doing, particularly this line: 你在做什么,尤其是这一行:

 this->installEventFilter (this);

is basically redirecting events of your widget to itself. 基本上是将窗口小部件的事件重定向到自身。 This isn't congruent with how the feature is designed to work and doesn't really reflect how you will use event filtering in real projects. 这与功能的设计工作方式不一致,并不能真实反映您将如何在实际项目中使用事件过滤。 When this is combined with your very strong event eating, you are essentially breaking the widget. 当这与你非常强烈的活动结合时,你实际上是打破了小部件。 For example, modifier key presses are delivered as a QKeyEvent, so by eating them in the eventfilter function you are likely throwing off shortcut handling. 例如,修改键按下作为QKeyEvent传递,因此通过在eventfilter函数中使用它们,您可能会抛弃快捷方式处理。

A couple reasons why you might not be getting QShortcut events. 您可能无法获得QShortcut事件的几个原因。 I don't see any QShortcut objects being attached. 我没有看到任何QShortcut对象被附加。 I wouldn't expect to get any QShortcutEvent events until you do. 在你做之前我不希望得到任何QShortcutEvent事件。 Also, I believe they are meant to work with QMenus, not as a generic way to get modifier+key sequences in all widgets. 此外,我认为它们是与QMenus一起使用的,而不是在所有小部件中获取修饰符+键序列的通用方法。 You will typically use QKeyEvent::modifiers() to do that. 您通常会使用QKeyEvent :: modifiers()来执行此操作。

Also, it's not clear what you're trying to do by filtering shortcutoverride events and casting them as keyevents. 此外,通过过滤shortcutoverride事件并将它们作为关键事件投射,目前尚不清楚您要做什么。

According to the docs, keyEvent->text() will be empty for modifier keys, so that may explain the characters... On windows it shows as blank. 根据文档,keyEvent-> text()对于修饰键是空的,因此可以解释字符...在Windows上它显示为空白。

Event filters are VERY handy, though, and are great for keeping things loosely coupled and highly reusuable. 事件过滤器非常方便,非常适合保持松散耦合和高度可重用性。 Here's an example that might be a better starting point for you as you learn: 这是一个例子,在您学习时可能是一个更好的起点:

main.cpp main.cpp中

#include <QtGui/QApplication>

#include "customlineedit.h"

#include <QWidget>
#include <QLineEdit>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget w;
    QLineEdit *le1 = new QLineEdit( &w );
    le1->move( 4, 4 );
    le1->setMinimumWidth( 200 );
    CustomLineEdit *le2 = new CustomLineEdit( &w );
    le2->move( 4, 35 );
    le2->setMinimumWidth( 200 );

    le1->installEventFilter (le2);

    w.setMinimumWidth( 260);
    w.show();

    return a.exec();
}

customlineedit.h customlineedit.h

#ifndef CUSTOMLINEEDIT_H
#define CUSTOMLINEEDIT_H

#include <QLineEdit>

class CustomLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit CustomLineEdit(QWidget *parent = 0);
    virtual bool eventFilter(QObject *watched, QEvent *event);
};

#endif // CUSTOMLINEEDIT_H

customlineedit.cpp customlineedit.cpp

#include "customlineedit.h"

#include<QShortcutEvent>

CustomLineEdit::CustomLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
}


bool CustomLineEdit::eventFilter (QObject *watched, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        this->setText("QKeyEvent: " + QString::number(keyEvent->modifiers() ) +" / "+ QString::number(keyEvent->key()) );
        return false;
    } else if (event->type () == QEvent::Shortcut) { //you shouldn't see these here...
        QShortcutEvent *shrtcutEvent = static_cast<QShortcutEvent*>(event);
        this->setText ("Shortcut event: " + shrtcutEvent->key().toString() );
        return false;
    } else {
        return false;
    }
}

Edit: So I see from the comments that you're trying to add Emacs-style custom shortcuts. 编辑:所以我从评论中看到你正在尝试添加Emacs风格的自定义快捷方式。 That's a great idea! 好主意啊! Here's how I'd approach it without using event filtering: 以下是我在不使用事件过滤的情况下接近它的方法:

#include <QtGui/QApplication>

#include <QLineEdit>
#include <QKeyEvent>
#include <QDebug>


class LineEditEmacs : public QLineEdit
{
    void keyPressEvent( QKeyEvent* event )
    {
        //qDebug()<< QString::number( event->key(), 16 ).toUpper();
        switch ( event->key() )
        {
        case Qt::Key_Up:
            { undo(); return; }
        case Qt::Key_Down:
            { redo(); return; }
        case Qt::Key_Minus: //shift+underscore
            if( (event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier ) { undo(); return; }

        case Qt::Key_U:
            if( (event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) {
                SetSelectionToCase( true );
                return;
            }
        case Qt::Key_L:
            if( (event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) {
                SetSelectionToCase( false );
                return;
            }

        default: 
            break;
        }
        QLineEdit::keyPressEvent( event );
    }

    void SetSelectionToCase( bool Upper )
    {
        if( !hasSelectedText() )
            return;

        QString s = selectedText();
        int iPreviousCursorPos = cursorPosition();
        del();
        QString su = Upper? s.toUpper() : s.toLower();
        insert( su );
        int iNewCursorPos = cursorPosition();

        //restore selection
        if( iPreviousCursorPos < iNewCursorPos )
            cursorBackward( true, su.length() );
        else if( iPreviousCursorPos == iNewCursorPos )
            setSelection( iPreviousCursorPos-su.length(), su.length() );
    }



};


int main( int argc, char *argv[] )
{
    QApplication a( argc, argv );
    LineEditEmacs w;
    w.show();
    return a.exec();
}

You can swallow keys and key+modifier combinations this way as well. 您也可以通过这种方式吞下键和键+修饰符组合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM