1

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.

wftmate
  • 11
  • 1
  • 2

2 Answers2

1

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;
}
Xplatforms
  • 2,102
  • 17
  • 26
  • Thanks. Putting the event filter in a different class made everything a pain. It was actually able to register key presses, but then I needed it to respond by doing something with the ui, and the keyBoardFilter object can't access the MainWindow class. This answer was super helpful. Line 14 from mainwindow.cpp was something I saw in some other threads but, no one said where specifically to put it. As I am a novice, that wasn't clear to me. Thanks! – wftmate Jul 18 '19 at 02:46
  • Your suggestion was really helpful. For some reason, it only seems to register the keyRelease event on the return key. I've tried the shift, backspace, and enter (numpad enter) keys as well and they all register the press and release. It just doesn't want to register the return press event. Do you have any idea what might cause this, or know where I could look for more info on this? I'm on a windows10 machine, if that's relevant. – wftmate Jul 19 '19 at 00:38
  • @wftmate, hm, tested it again and booth events works for return key. Are you using some kind of emulation or virtual machine? I know there is exist some troubles with key events with remote clients and VM client tools. Also do you set Focus to another object after value changed or enter released? If your LineEdit loose focus before keyRelease you will not get release event. – Xplatforms Jul 19 '19 at 07:18
  • @wftmate, Add this to the beginning of your eventFilter function and you will see all events which happens in your Input by name: **bool MainWindow::eventFilter(QObject *target, QEvent *event) { qDebug() << "Object: " << (target!= Q_NULLPTR?target->objectName():"null") << "EventType -> " << QMetaEnum::fromType().valueToKey((event != Q_NULLPTR?event->type():0));** – Xplatforms Jul 19 '19 at 07:19
  • I'm not using a VM. I am working on a laptop with windows/linux dual boot. I've tried it on both OSs with the same results. I have not explicitly set the focus to anything, I just click around the window while it's running to change focus. Regardless of what is selected, the Return key pressed event is never captured. I also tried added your qDebug line but, it gave me a bunch of errors about Q_NULLPTR not being defined in this scope. – wftmate Jul 21 '19 at 19:57
  • Change Q_NULLPTR to nullptr. Q_NULLPTR is Qt typedef for nullptr, NULL, etc. Very strange why it is not defined in your configuration. – Xplatforms Jul 22 '19 at 05:48
0

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);
Antonio Dias
  • 2,751
  • 20
  • 40
  • Thanks. The shortcut solution looks a little simpler than the event filter. I really appreciate the help! – wftmate Jul 18 '19 at 02:51