【问题标题】:Trouble with Event Filter for key presses按键事件过滤器出现问题
【发布时间】:2019-07-15 20:17:31
【问题描述】:

我正在尝试学习如何使用 QtCreator 制作带有 GUI 的软件。我以前做过一些编程,但从来没有涉及到任何事情。到目前为止,我已经制作了一个包含 5 个项目的窗口:2 个标签、1 个按钮、1 个 lineEdit 和 1 个 listWidget。

我的目标是能够在 lineEdit 中输入文本并使其出现在 listWidget 中。如果您用鼠标单击按钮,则可以正常工作。

我还希望能够使用键盘上的回车键来激活按钮。这是我需要帮助的部分。

我创建了一个名为 KeyboardFilter 的用于处理键事件的新类。

我已经在主窗口对象上安装了事件过滤器。 eventFilter 函数应该接收任何事件,检查它是否是按键事件,然后检查它是否是回车按钮。如果是,那么我想激活按钮。

我无法判断我为 eventFilter 编写的任何内容是否真的有效。

// == keyboardfilter.h =======================================================

#ifndef KEYBOARDFILTER_H
#define KEYBOARDFILTER_H

#include <QApplication>
#include <QLineEdit>
#include <QKeyEvent>

class KeyboardFilter : public QObject
{
public:
    KeyboardFilter( QObject *parent = nullptr ) : QObject( parent ) {}

//protected:
public:
    bool eventFilter( QObject *target, QEvent *event );
};

#endif // KEYBOARDFILTER_H


// == mainwindow.h ===========================================================

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

// handles clicking the enter button with the mouse
//private slots:
public slots:
    void EnterPressed();

// supposed to handle key presses. doesn't actually work
//protected:
public:
    void KeyPressEvent(QKeyEvent *event);
    void KeyReleaseEvent(QKeyEvent *event);
    bool EventFilter(QEvent *event);
};

#endif // MAINWINDOW_H


// == keyboardfilter.cpp =====================================================

#include "keyboardfilter.h"

bool KeyboardFilter::eventFilter(QObject *target, QEvent *event)
{
    if(event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
            return true;
        }
    }
    if(event->type() == QEvent::KeyRelease){
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
            return true;
        }
    }
    return false;
}


// == mainwindow.cpp =========================================================

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include <QKeyEvent>
#include <iostream>

QString stack[10];

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    stack[1] = "stack";
    ui->Display->addItem(stack[1]);

    connect(ui->Enter, SIGNAL(released()), this, SLOT(EnterPressed()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

//qDebug() << "Debug Message";
//QDebug("text");

void MainWindow::EnterPressed(){
    //ui->Input->setText(QString("text"));

    ui->Display->clear();

    QString input = ui->Input->text();
    ui->Input->clear();

    ui->Display->addItem(input);
}

// -- keyboardfilter.cpp

#include "keyboardfilter.h"

bool KeyboardFilter::eventFilter(QObject *target, QEvent *event)
{
    if(event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
            return true;
        }
    }
    if(event->type() == QEvent::KeyRelease){
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
            return true;
        }
    }
    return false;
}

// == main.cpp ===============================================================

#include "mainwindow.h"
#include "keyboardfilter.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    //    KeyboardFilter filter;
    //    a.installEventFilter(&filter);

    KeyboardFilter* key = new KeyboardFilter();
    w.installEventFilter(key);

    if(key){
        w.EnterPressed();
    }
    return a.exec();
}

当我运行此代码时,会弹出窗口,我可以在 lineEdit 中输入文本。如果我用鼠标单击按钮,文本会根据需要移动到 listWidget。如果我输入文本然后点击“Enter”,什么也不会发生。

我曾尝试在按 Enter 之前点击 tab 以将焦点放在 lineEdit、listWidget 和按钮上,但没有帮助。

【问题讨论】:

    标签: c++ qt qkeyevent


    【解决方案1】:

    全局捕获Enter/Return 键的简单方法是使用QShortcut,然后将触发事件连接到按钮单击。

    QWidget *widget = new QWidget(this); //The main window central widget
    
    QLineEdit *edit = new QLineEdit(this); //Your edit
    
    QPushButton *button = new QPushButton("Accept", this); //Your button
    
    QLabel *label = new QLabel(this); //Your label
    
    QHBoxLayout *layout = new QHBoxLayout(widget); //Arrange items horizontally
    layout->addWidget(edit);
    layout->addWidget(button);
    layout->addWidget(label);
    
    connect(button, &QPushButton::clicked, this, [=](bool checked){ //The button clicked event
        Q_UNUSED(checked)
    
        label->setText(edit->text());
        edit->clear();
    });
    
    QShortcut *shortcut_return = new QShortcut(Qt::Key_Return, this); //The return shortcut event
    connect(shortcut_return, &QShortcut::activated, button, &QPushButton::click);
    QShortcut *shortcut_enter = new QShortcut(Qt::Key_Enter, this); //The enter shortcut event
    connect(shortcut_enter, &QShortcut::activated, button, &QPushButton::click);
    
    button->setDefault(true); //Set the button as default
    
    setCentralWidget(widget);
    

    【讨论】:

    • 谢谢。快捷解决方案看起来比事件过滤器简单一些。非常感谢您的帮助!
    【解决方案2】:

    也许installEventFilter 的Qt 文档不是很清楚,您需要将事件过滤器安装到要过滤的事件的对象上。在您的情况下,它是 QLineEdit(Input?) 而不是 MainWindow。此外,您实际上不需要额外的事件过滤器类。您可以覆盖 MainWindow 的 eventFilte 并将其安装在 QLineEdit 上。如果您不想停止处理事件,请务必返回 false

    这可能是这样的:

    ma​​in.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
        int main(int argc, char *argv[])
        {
            QApplication a(argc, argv);
            MainWindow w;
            w.show();
            return a.exec();
        }
    

    ma​​inwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QLineEdit>
    #include <QKeyEvent>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow() override;
    
    private:
        Ui::MainWindow *ui;
    
    public slots:
        void EnterPressed();
        bool eventFilter(QObject *target, QEvent *event) override;
    };
    
    #endif // MAINWINDOW_H
    

    ma​​inwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    #include <QKeyEvent>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        //... your code here
    
        this->ui->Input->installEventFilter(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::EnterPressed(){
        //.... your code here
    }
    
    bool MainWindow::eventFilter(QObject *target, QEvent *event)
    {
        if(target != this->ui->Input)return false;
    
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
                qDebug() << "eventFilter Enter pressed";
                this->EnterPressed(); // call your slot 
                return true;
            }
        }
        if(event->type() == QEvent::KeyRelease){
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
                qDebug() << "eventFilter Enter pressed released";
                return true;
            }
        }
        return false;
    }
    

    【讨论】:

    • 谢谢。将事件过滤器放在不同的类中会使一切变得痛苦。它实际上能够注册按键,但是我需要它通过对 ui 执行某些操作来响应,并且 keyBoardFilter 对象无法访问 MainWindow 类。这个答案非常有帮助。 mainwindow.cpp 的第 14 行是我在其他一些线程中看到的,但是没有人说具体放在哪里。由于我是新手,这对我来说不是很清楚。谢谢!
    • 你的建议真的很有帮助。出于某种原因,它似乎只在返回键上注册了 keyRelease 事件。我也尝试过 shift、backspace 和 enter(小键盘输入)键,它们都记录了按下和释放。它只是不想注册返回新闻事件。您是否知道可能导致这种情况的原因,或者知道我可以在哪里找到有关此的更多信息?如果相关的话,我在 windows10 机器上。
    • @wftmate,嗯,再次对其进行了测试,展位活动适用于返回键。您是否使用某种仿真或虚拟机?我知道远程客户端和 VM 客户端工具的关键事件存在一些问题。在值更改或输入释放后,您是否还将焦点设置为另一个对象?如果您的 LineEdit 在 keyRelease 之前失去焦点,您将不会获得发布事件。
    • @wftmate,将此添加到 eventFilter 函数的开头,您将按名称查看输入中发生的所有事件:bool MainWindow::eventFilter(QObject *target, QEvent *event ) { qDebug() objectName():"null") " ( ).valueToKey((event != Q_NULLPTR?event->type():0));
    • 我没有使用虚拟机。我正在使用带有 windows/linux 双启动的笔记本电脑。我在两个操作系统上都试过了,结果相同。我没有明确地将焦点设置为任何东西,我只是在窗口运行时单击窗口以更改焦点。无论选择什么,都不会捕获 Return 键按下事件。我也尝试添加你的 qDebug 行,但是它给了我一堆关于 Q_NULLPTR 没有在这个范围内定义的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2020-07-15
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    相关资源
    最近更新 更多