1

My child widget does not get keyPressEvents, while if I put the same widget as top level window, it does. I try to set it get focus, but it has no effect on this. Code is below, showing what I try to get to work.

#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>

class DigitSummer: public QLCDNumber {
    Q_OBJECT

public:
    DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
    }

protected:
    void keyPressEvent(QKeyEvent *event) override {
        display(intValue() + event->text().toInt());
    }
};

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

#if 1 // this version does not work, number does not increase
    QWidget widget;
    widget.setLayout(new QVBoxLayout());
    widget.layout()->addWidget(new QLabel("Press digits!"));
    DigitSummer summer; // in stack: must be after widget to avoid child delete
    widget.layout()->addWidget(&summer);
    widget.setFocusProxy(&summer); // I notice no effect!
    widget.show();

#else // this version works, number grows with keypresseas
    DigitSummer summer;
    summer.show();
#endif

    return a.exec();
}

#include "main.moc"

And for completenes, .pro file for the same:

QT += core gui widgets
TARGET = QtMCVE
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11
QMAKE_CXXFLAGS += -Wall -Wextra
SOURCES += main.cpp

How to fix the widget to receive key events?

This related question suggests installing event filter, but I don't want to do that, there must be a self-contained way to fix the widget itself.

hyde
  • 60,639
  • 21
  • 115
  • 176

1 Answers1

5

I think you need to set the focus policy for the widget before it will accept keyboard input. In your ctor try...

setFocusPolicy(Qt::StrongFocus);

Having said that, I'm really not sure why the behaviour would differ for top-level and non-top-level widgets.


Working version of the question code:

#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>

class DigitSummer: public QLCDNumber {
    Q_OBJECT

public:
    DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
        setFocusPolicy(Qt::StrongFocus);
    }

protected:
    void keyPressEvent(QKeyEvent *event) override {
        display(intValue() + event->text().toInt());
    }
};

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

    QWidget widget;
    widget.setLayout(new QVBoxLayout());
    widget.layout()->addWidget(new QLabel("Press digits!"));
    widget.layout()->addWidget(new DigitSummer);
    widget.show();

    return a.exec();
}

#include "main.moc"
hyde
  • 60,639
  • 21
  • 115
  • 176
G.M.
  • 12,232
  • 2
  • 15
  • 18
  • Indeed. Adding `widget.setFocusPolicy(Qt::StringFocus);` to main function fixes it too, but the correct solution is to add it to `DigitSummer` constructor, and not mess with focus in main at all. I think I'll edit your answer with the correct code. – hyde May 10 '19 at 11:54
  • @hyde My answer does actually state `"In your ctor try..."` so that was the intention. Or have I misunderstood your comment? – G.M. May 10 '19 at 11:56
  • I just meant to say that setting focusPolicy *and* focusProxy for `widget` works too, but it (in most scenarios) won't be the right solution, it's better to indeed do it in DigitSummer constructor. – hyde May 10 '19 at 11:58