using QKeyEvents
-
wrote on 7 May 2020, 21:26 last edited by
@SGaist you're referring to the KeyPressEater class in the QObject::installEventFilter() documentation, right?
Its behavior isn't the same as my KeyPress class, but I can worry about that later. I still don't see why I'm not hitting a breakpoint.
bool KeyPress::eventFilter(QObject *obj, QEvent *ev) { bool rc = false; if (ev->type() == QEvent::KeyPress) { if (obj == this) { rc = true; qDebug() << ev; } } return rc; }
My breakpoint is on my inner "if" and it's never reached.
-
Because as is, your filter will never be the target of a KeyPress event.
The value of obj will be one of the object you installed your filter on. -
wrote on 7 May 2020, 21:42 last edited by
I understand your 2nd statement, but not the first. I install the filter on my Widget object. Is a QWidget incapable of accepting KeyPress events?
-
wrote on 7 May 2020, 23:49 last edited by
Well, I got it partly working -- the problem was that I was deriving my KeyPress class from QWidget instead of QObject.
Now, though, my filter only seems to be trapping "meta keys." Control, alt, etc. all work, but regular keys like A, B, C don't. It appears that these keys generate a ShortcutOverride event. Does this make sense to you?
Thanks...
-
wrote on 8 May 2020, 15:47 last edited by
My filter seems to be doing what I want (when two keys are held down, I make a button visible).
if (C_pressed && D_pressed) { ui->pushButtonNics->setVisible(true); } else { ui->pushButtonNics->setVisible(false); }
But when I click on that button, my clicked slot isn't reached. I thought maybe holding down the keys was blocking the button push, but my other buttons work fine. My button is enabled when visible (I checked in the debugger). Any ideas why it's not generating the signal?
Thanks...
-
You are forgetting to call the base class implementation.
-
The last implementation I saw does not call it at all which means that all events are filtered out.
To check, comment out the filter installation and see if it does work correctly.
-
The last implementation I saw does not call it at all which means that all events are filtered out.
To check, comment out the filter installation and see if it does work correctly.
wrote on 8 May 2020, 18:06 last edited by@SGaist let's make sure we're talking about the same thing. Here's where I create the filter:
// create and connect a KeyPress object. m_keyPress = new KeyPress(this); connect(m_keyPress, &KeyPress::keyEvent, this, &Widget::handleKeyEvent); installEventFilter(m_keyPress); // hide the button for the NICs window. // ui->pushButtonNics->setVisible(false);
You'll notice that the last line is commented out. And, it works. So it would seem that it has something to do with the filter...?
-
Can you provide a minimal compilable example that shows the behaviour ?
Si au can check on my side what is going on. -
Can you provide a minimal compilable example that shows the behaviour ?
Si au can check on my side what is going on.wrote on 8 May 2020, 18:16 last edited bykeypress.h
#ifndef KEYPRESS_H #define KEYPRESS_H #include <QWidget> #include <QtGui> class KeyPress : public QObject { Q_OBJECT public: explicit KeyPress(QWidget *parent = nullptr); protected: bool eventFilter(QObject *obj, QEvent *ev) override; signals: void keyEvent(QEvent event, int key); }; #endif // KEYPRESS_H
keypress.cpp
#include "keypress.h" KeyPress::KeyPress(QWidget *parent) : QObject (parent) { } bool KeyPress::eventFilter(QObject *obj, QEvent *ev) { Q_UNUSED(obj) bool rc = false; int key; QKeyEvent *qke; if (ev->type() == QEvent::ShortcutOverride || ev->type() == QEvent::KeyRelease) { qke = static_cast<QKeyEvent *>(ev); key = qke->key(); // don't bother signaling when the key isn't meaningful to us. if (key == 'c' || key == 'C' || key == 'd' || key == 'D') { emit keyEvent(*ev, key); } rc = true; } else { rc = QObject::eventFilter(obj, ev); } return rc; }
Let me know if there's something more you want to look at...thanks.
-
A minimal widget that you install that filter on would be nice :-)
-
wrote on 8 May 2020, 19:03 last edited by
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "keypress.h" namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT private: Ui::Widget *ui; KeyPress *m_keyPress = nullptr; bool C_pressed = false; bool D_pressed = false; public: explicit Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_pushButtonQuit_clicked(); void on_pushButtonNics_clicked(); void handleKeyEvent(QEvent event, int key); signals: void quitButtonPushed(int rc); }; #endif // WIDGET_H
widget.cpp
#include <iostream> #include <sstream> #include <stdio.h> #include <QDebug> #include "editdialog.h" #include "nics.h" #include "widget.h" #include "ui_widget.h" using namespace std; Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // create and connect a KeyPress object. m_keyPress = new KeyPress(this); connect(m_keyPress, &KeyPress::keyEvent, this, &Widget::handleKeyEvent); installEventFilter(m_keyPress); // hide the button for the NICs window. ui->pushButtonNics->setVisible(false); } Widget::~Widget() { delete ui; } void Widget::on_pushButtonQuit_clicked() { emit quitButtonPushed(0); } void Widget::handleKeyEvent(QEvent event, int key) { if (event.type() == QEvent::ShortcutOverride) { if (key == 'c' || key == 'C') { C_pressed = true; } else if ((key == 'd' || key == 'D')) { D_pressed = true; } } else if (event.type() == QEvent::KeyRelease) { if (key == 'c' || key == 'C') { C_pressed = false; } else if ((key == 'd' || key == 'D')) { D_pressed = false; } } if (C_pressed && D_pressed) { ui->pushButtonNics->setVisible(true); } else { ui->pushButtonNics->setVisible(false); } } void Widget::on_pushButtonNics_clicked() { Nics nics(this); nics.exec(); }
You'll want to connect the Widget signal to something. Sorry...this was as compact as I dared make it.
Thanks for looking at this.
-
Since I don't have the .ui file I modified the code a bit.
I created a QPushButton and did an explicit connection and it worked was expected.
-
Since I don't have the .ui file I modified the code a bit.
I created a QPushButton and did an explicit connection and it worked was expected.
-
By explicit I meant writing the connect statement. Currently you are using the connectSlotsByName feature that is called as part of setupUi.
-
wrote on 9 May 2020, 13:11 last edited by
OK...I added the explicit connection in widget.cpp:
connect(ui->pushButtonNics, &QPushButton::clicked, this, &Widget::on_pushButtonNics_clicked);
Here's my widget.ui:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Widget</class> <widget class="QWidget" name="Widget"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>320</width> <height>160</height> </rect> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>320</width> <height>160</height> </size> </property> <property name="windowTitle"> <string>Discovery Utility</string> </property> <widget class="QPushButton" name="pushButtonNics"> <property name="geometry"> <rect> <x>130</x> <y>50</y> <width>75</width> <height>23</height> </rect> </property> <property name="text"> <string>NICs</string> </property> </widget> </widget> <layoutdefault spacing="6" margin="11"/> <resources/> <connections/> </ui>
And, just for good measure, here's main.cpp:
#include <QApplication> #include <stdio.h> #include "widget.h" using namespace std; int main(int argc, char *argv[]) { int rc; QApplication a(argc, argv); Widget *widget; widget = new Widget(); widget->show(); rc = a.exec(); return rc; }
This is my entire project, except for the pro file itself:
QT += core gui network serialport xml greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = discovery_utility_test DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ keypress.cpp \ main.cpp \ nics.cpp \ widget.cpp HEADERS += \ keypress.h \ nics.h \ widget.h \ FORMS += \ nics.ui \ widget.ui
Could it possibly be due to the way that I'm building it? Or, maybe a Windows issue (you're testing on Linux, right)?
Thanks...
-
wrote on 11 May 2020, 15:03 last edited by
This problem has to do with setting the button's visibility. If I disable this line in my widget c'tor:
// ui->pushButtonNics->setVisible(false);
My slot receives the signal, and opens the Nics dialog. After the dialog closes, I set the button to not visible, and the problem recurs.
This problem exists on Windows 10, but not on MacOS. Could it be a bug?
-
One silly test, did you try to make the button invisible after calling
connect
. AFAIK, it should have no relation but it's worth a shot. -
One silly test, did you try to make the button invisible after calling
connect
. AFAIK, it should have no relation but it's worth a shot.wrote on 11 May 2020, 15:24 last edited by@SGaist yes, that's how I had it:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // create and connect a KeyPress object. m_keyPress = new KeyPress(this); connect(m_keyPress, &KeyPress::keyEvent, this, &Widget::handleKeyEvent); connect(ui->pushButtonNics, &QPushButton::clicked, this, &Widget::on_pushButtonNics_clicked); installEventFilter(m_keyPress); // hide the button for the NICs window. // ui->pushButtonNics->setVisible(false); }
20/40