Trouble with Event Filter for key presses

3k Views Asked by At

I am trying to learn how to make software with GUIs using QtCreator. I've done some programming before, but never anything this involved. So far, I have made a window with 5 items: 2 labels, 1 button, 1 lineEdit, and 1 listWidget.

My goal is to be able to enter text in the lineEdit and make it appear in the listWidget. If you click on the button with the mouse, this works fine.

I would also like to be able to use the enter/return key on a keyboard to activate the button. This is the part I need help with.

I created a new class for handling key events called KeyboardFilter.

I have installed the event filter on the main window object. The eventFilter function should receive any event, check if it's a key event, then check if it's the enter button. If it is, then I want to activate the button.

I can't tell if any of the stuff I've written for the eventFilter is actually working.

// == 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();
}

When I run this code, the window pops up and I can enter text into the lineEdit. If I click the button with the mouse, the text gets moved to the listWidget, as desired. If I enter text and then hit "Enter", nothing happens.

I have tried hitting tab to give focus to the lineEdit, listWidget, and button before hitting enter, but hasn't helped though.

2

There are 2 best solutions below

1
Antonio Dias On

A simple way to catch Enter/Return keys globally is using QShortcut and, then, connect the trigger event to button click.

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);
6
Xplatforms On

Maybe Qt docs for installEventFilter isn't absolutely clear, you need to install event filter to the object which events you want to filter. In your case it is QLineEdit(Input?) and not the MainWindow. Also you don't need actually extra class for event filter. you could override eventFilte of your MainWindow and install it on QLineEdit. Just be sure to return false if you don't want to stop processing event.

Here is how that could look:

main.cpp

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

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

mainwindow.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

mainwindow.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;
}