My Qt eventFilter () does not stop events as it should

Something is fundamentally wrong with my eventFilter, as it skips every single event, and I want to stop everything . I read a lot of documentation on QEvent , eventFilter() , etc., but obviously I am missing something big. Essentially, I'm trying to create my own modal functionality for my QDialog based QDialog . I want to implement my own, since the built-in setModal(true) includes many functions, for example. playing QApplication::Beep() which I want to exclude. Basically, I want to discard all events going to the QWidget (window) that created my popup . What am I still

 // popupdialog.h #ifndef POPUPDIALOG_H #define POPUPDIALOG_H #include <QDialog> #include <QString> namespace Ui {class PopupDialog;} class PopupDialog : public QDialog { Q_OBJECT public: explicit PopupDialog(QWidget *window=0, QString messageText=""); ~PopupDialog(); private: Ui::PopupDialog *ui; QString messageText; QWidget window; // the window that caused/created the popup void mouseReleaseEvent(QMouseEvent*); // popup closes when clicked on bool eventFilter(QObject *, QEvent*); }; 

...

 // popupdialog.cpp #include "popupdialog.h" #include "ui_popupdialog.h" PopupDialog::PopupDialog(QWidget *window, QString messageText) : QDialog(NULL), // parentless ui(new Ui::PopupDialog), messageText(messageText), window(window) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); // Prevents memory leak setWindowFlags(Qt::Window | Qt::FramelessWindowHint); ui->message_text_display->setText(messageText); window->installEventFilter(this); //this->installEventFilter(window); // tried this also, just to be sure .. } PopupDialog::~PopupDialog() { window->removeEventFilter(this); delete ui; } // popup closes when clicked on void PopupDialog::mouseReleaseEvent(QMouseEvent *e) { close(); } 

Here is the problem, the filter does not work. Please note that if I write a std::cout inside if(...) , I see that it fires whenever events are sent to window , it just does not stop them.

 bool PopupDialog::eventFilter(QObject *obj, QEvent *e) { if( obj == window ) return true; //should discard the signal (?) else return false; // I tried setting this to 'true' also without success } 

When a user interacts with the main program, PopupDialog can be created as follows:

 PopupDialog *popup_msg = new PopupDialog(ptr_to_source_window, "some text message"); popup_msg->show(); // I understand that naming the source 'window' might be a little confusing. // I apologise for that. The source can in fact be any 'QWidget'. 

Everything else works as expected. The event filter is disabled. I want the filter to delete events sent to the window that created the popup; like a mouse click and keystroke until the pop-up window is closed . I expect to be very confused when someone marks a trivial fix in my code.

+5
source share
3 answers

You should ignore all events that arrive in the window widget tree. Therefore, you need to install the eventFilter application and check if the object you are filtering on is a descendant of window . In other words: Replace

 window->installEventFilter(this); 

by

 QCoreApplication::instance()->installEventFilter(this); 

and implement the event filter function this way:

 bool PopupDialog::eventFilter(QObject *obj, QEvent *e) { if ( !dynamic_cast<QInputEvent*>( event ) ) return false; while ( obj != NULL ) { if( obj == window ) return true; obj = obj->parent(); } return false; } 

I tried it, tested it, and it worked for me.

Note. Using event filters in Qt is a little useless in my experience, since it is not completely transparent what is happening. Expect errors from time to time. Instead, you can turn off the main window if you and your clients have no problems with the gray main window.

+2
source

After a huge amount of answers, feedback, suggestions and time spent in extensive research, I finally found what I consider the best and safe solution. I want to express my sincere thanks to everyone for their help in what Cuba Ober describes as "(...) not as simple as you think."

We want to filter out all the specific events from the widget, including its children. This is difficult because events can be caught in the default child event filters and responded before they are caught and filtered using the parent custom filter that the programmer implements for. The following code solves this problem by setting a filter for all children when they are created. This example uses the Qt Creator user interfaces and is based on the following blog post: How to set eventfilters for all children .

 // The widget class (based on QMainWindow, but could be anything) for // which you want to install the event filter on, includings its children class WidgetClassToBeFiltered : public QMainWindow { Q_OBJECT public: explicit WidgetClassToBeFiltered(QWidget *parent = 0); ~WidgetClassToBeFiltered(); private: bool eventFilter(QObject*, QEvent*); Ui::WidgetClassToBeFiltered *ui; }; 

...

 WidgetClassToBeFiltered::WidgetClassToBeFiltered(QWidget *parent) : QMainWindow(parent), // Base Class constructor ui(new Ui::WidgetClassToBeFiltered) { installEventFilter(this); // install filter BEFORE setupUI. ui->setupUi(this); } 

...

 bool WidgetClassToBeFiltered::eventFilter(QObject *obj, QEvent* e) { if( e->type() == QEvent::ChildAdded ) // install eventfilter on children { QChildEvent *ce = static_cast<QChildEvent*>(e); ce->child()->installEventFilter(this); } else if( e->type() == QEvent::ChildRemoved ) // remove eventfilter from children { QChildEvent *ce = static_cast<QChildEvent*>(e); ce->child()->removeEventFilter(this); } else if( (e->type() == QEvent::MouseButtonRelease) ) // eg filter out Mouse Buttons Relases { // do whatever .. return true; // filter these events out } return QWidget::eventFilter( obj, e ); // apply default filter } 

Note that this works because eventfilter sets itself to the added children! Therefore, it should also work without using user interfaces.

+1
source

Refer to this code to filter out a specific event: -

 class MainWindow : public QMainWindow { public: MainWindow(); protected: bool eventFilter(QObject *obj, QEvent *ev); private: QTextEdit *textEdit; }; MainWindow::MainWindow() { textEdit = new QTextEdit; setCentralWidget(textEdit); textEdit->installEventFilter(this); } bool MainWindow::eventFilter(QObject *obj, QEvent *event) { if (obj == textEdit) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); qDebug() << "Ate key press" << keyEvent->key(); return true; } else { return false; } } else { // pass the event on to the parent class return QMainWindow::eventFilter(obj, event); } } 

If you want to set a more specific event filter for several widgets, you can refer to the following code:

  class KeyPressEater : public QObject { Q_OBJECT protected: bool eventFilter(QObject *obj, QEvent *event); }; bool KeyPressEater::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); qDebug("Ate key press %d", keyEvent->key()); return true; } else { // standard event processing return QObject::eventFilter(obj, event); } } KeyPressEater *keyPressEater = new KeyPressEater(this); QPushButton *pushButton = new QPushButton(this); pushButton->installEventFilter(keyPressEater); 
0
source

Source: https://habr.com/ru/post/1262729/


All Articles