QMessageBox::warning replacement that wont process the event loop
-
@stefanwoe said in QMessageBox::warning replacement that wont process the event loop:
And i still wonder how the approach in the linked Stackoverflow (above) answer would work. this seems to solve the problem.
Just like I suggested on the previous page!
In order to be able to click on any button or even to draw/show the dialog, the event loop has to be processed.
That is either done by the main event loop or by one QMessagebox is spawning or by one you yourself create. BUT event processing will be happening, if you wan't a responsive UI-window.
In your case you want only the main event loop to be spinning.
-
In your case you want only the main event loop to be spinning.
How could that be done? Is there a example?
#ifndef SOMECLASS_H #define SOMECLASS_H #include <QWidget> #include <QMessageBox> class SomeClass : public QWidget { Q_OBJECT public: explicit SomeClass(QWidget *parent = nullptr); void oldBlocking(); void newNonBlocking(); signals: private slots: void continuationOfnewNonBlocking(); private: bool someCondition() {return rand() % 2;} private: QMessageBox m_messageBox; QMetaObject::Connection m_lastConnect; }; #endif // SOMECLASS_H
#include "someclass.h" #include <QDebug> SomeClass::SomeClass(QWidget *parent) : QWidget(parent) { m_messageBox.setWindowModality(Qt::ApplicationModal); } void SomeClass::oldBlocking() { if(!someCondition()) { QMessageBox::information(this, "Bla", "blubb"); } qDebug() << "Do stuff as normal"; } void SomeClass::newNonBlocking() { if(!someCondition()) { m_messageBox.setText("blubb"); m_lastConnect = connect(&m_messageBox, &QMessageBox::accepted, this, &SomeClass::continuationOfnewNonBlocking); m_messageBox.show(); } else { continuationOfnewNonBlocking(); } } void SomeClass::continuationOfnewNonBlocking() { QObject::disconnect(m_lastConnect); qDebug() << "Do stuff as normal"; }
-
@stefanwoe said in QMessageBox::warning replacement that wont process the event loop:
And i still wonder how the approach in the linked Stackoverflow (above) answer would work. this seems to solve the problem.
Just like I suggested on the previous page!
In order to be able to click on any button or even to draw/show the dialog, the event loop has to be processed.
That is either done by the main event loop or by one QMessagebox is spawning or by one you yourself create. BUT event processing will be happening, if you wan't a responsive UI-window.
In your case you want only the main event loop to be spinning.
@J-Hilk said in QMessageBox::warning replacement that wont process the event loop:
In your case you want only the main event loop to be spinning.
My understanding is that the OP says he wants/demands no Qt event loop to be running while his dialog is shown, that is the problem....
If you read his original report, for example, a window receives an "activate" event for some reason, and he does not want that or any other event to be processed....
-
@J-Hilk said in QMessageBox::warning replacement that wont process the event loop:
In your case you want only the main event loop to be spinning.
My understanding is that the OP says he wants/demands no Qt event loop to be running while his dialog is shown, that is the problem....
If you read his original report, for example, a window receives an "activate" event for some reason, and he does not want that or any other event to be processed....
@J.Hilk said
In order to be able to click on any button or even to draw/show the dialog, the event loop has to be processed.
That is either done by the main event loop or by one QMessagebox is spawning or by one you yourself create. BUT event processing will be happening, if you wan't a responsive UI-window.
@stefanwoe said in QMessageBox::warning replacement that wont process the event loop:
In your case you want only the main event loop to be spinning.
How could that be done? Is there a example?
therefore my answer/example
-
@J.Hilk said
In order to be able to click on any button or even to draw/show the dialog, the event loop has to be processed.
That is either done by the main event loop or by one QMessagebox is spawning or by one you yourself create. BUT event processing will be happening, if you wan't a responsive UI-window.
@stefanwoe said in QMessageBox::warning replacement that wont process the event loop:
In your case you want only the main event loop to be spinning.
How could that be done? Is there a example?
therefore my answer/example
-
#ifndef SOMECLASS_H #define SOMECLASS_H #include <QWidget> #include <QMessageBox> class SomeClass : public QWidget { Q_OBJECT public: explicit SomeClass(QWidget *parent = nullptr); void oldBlocking(); void newNonBlocking(); signals: private slots: void continuationOfnewNonBlocking(); private: bool someCondition() {return rand() % 2;} private: QMessageBox m_messageBox; QMetaObject::Connection m_lastConnect; }; #endif // SOMECLASS_H
#include "someclass.h" #include <QDebug> SomeClass::SomeClass(QWidget *parent) : QWidget(parent) { m_messageBox.setWindowModality(Qt::ApplicationModal); } void SomeClass::oldBlocking() { if(!someCondition()) { QMessageBox::information(this, "Bla", "blubb"); } qDebug() << "Do stuff as normal"; } void SomeClass::newNonBlocking() { if(!someCondition()) { m_messageBox.setText("blubb"); m_lastConnect = connect(&m_messageBox, &QMessageBox::accepted, this, &SomeClass::continuationOfnewNonBlocking); m_messageBox.show(); } else { continuationOfnewNonBlocking(); } } void SomeClass::continuationOfnewNonBlocking() { QObject::disconnect(m_lastConnect); qDebug() << "Do stuff as normal"; }
@J-Hilk Thanks very much for your efforts!
Unfortunately this does not what i need. If i writeSomeClass testMessageBox(this); testMessageBox.newNonBlocking(); nextStatement();
A Dialog window is shown but code keeps executing nextStatement(); etc. before i have a chance to press any button or even to read the text of the MessageBox as the it disappears when the object "testMessageBox" is destroyed as its scope is left. oldBlocking() behaves like the existing QMessageBox .
What i need is a call like
testMessageBox.execWithoutProcessingUnrelatedEvents();
This call should BLOCK (not nonBlock) execution of further code (it shall not cal nextStatement() as long as the MessageBox is shown) and it should only process events for its own window. From the StackOverflow post this seems possible - but i dont know how to do this.
The class you supplied does not do this. -
The OP probably worked around this somehow already but, the issue by itself is still valid.
The problem is, this is not well-supported at the OS level. There are some workarounds though:
-
Use a helper program. Run it, let it show the message, and wait for it to finish. Should work on any OS.
-
On Windows, you can use a thread instead of a program, but only with native UI. Qt UI doesn’t support multithreading. And to my knowledge, on macOS all UI is limited to the main thread.
-
Technically, on X11 it is possible to create an additional connection to the display and use that one to show the message. But good luck finding a toolkit that supports that, or showing a readable message without one.
-
At least on Windows, it is possible to filter events by window. So e.g. on Windows, you could create a dialog and then run an event loop with
GetMessage(&msg, hwnd_your_dialog, 0, 0)
. This is somewhat fragile but should work. See the docs for GetMessage for details. -
Technically, X11 supports the same. But like in (3) that requires working with raw X11 which is quite different from working with raw WinAPI. I don’t know whether macOS support anything similar.
-
-
The OP probably worked around this somehow already but, the issue by itself is still valid.
The problem is, this is not well-supported at the OS level. There are some workarounds though:
-
Use a helper program. Run it, let it show the message, and wait for it to finish. Should work on any OS.
-
On Windows, you can use a thread instead of a program, but only with native UI. Qt UI doesn’t support multithreading. And to my knowledge, on macOS all UI is limited to the main thread.
-
Technically, on X11 it is possible to create an additional connection to the display and use that one to show the message. But good luck finding a toolkit that supports that, or showing a readable message without one.
-
At least on Windows, it is possible to filter events by window. So e.g. on Windows, you could create a dialog and then run an event loop with
GetMessage(&msg, hwnd_your_dialog, 0, 0)
. This is somewhat fragile but should work. See the docs for GetMessage for details. -
Technically, X11 supports the same. But like in (3) that requires working with raw X11 which is quite different from working with raw WinAPI. I don’t know whether macOS support anything similar.
-
-
Hi, you could try spinning your own event loop inside SomeClass.
Say you add a QEventLoop instance in the .h file:... private: QEventloop m_eventLoop; QMessageBox m_messageBox; QMetaObject::Connection m_lastConnect; };
then in SomeClass.cpp:
,,, void SomeClass::newNonBlocking() { if(!someCondition()) { m_messageBox.setText("blubb"); m_lastConnect = connect(&m_messageBox, &QMessageBox::accepted, this, &SomeClass::continuationOfnewNonBlocking); m_messageBox.show(); m_eventLoop.exec(); // spin here and wait for .exit() } else { continuationOfnewNonBlocking(); } } void SomeClass::continuationOfnewNonBlocking() { QObject::disconnect(m_lastConnect); m_eventLoop.exit(); qDebug() << "Do stuff as normal"; } ```
-
Hi, you could try spinning your own event loop inside SomeClass.
Say you add a QEventLoop instance in the .h file:... private: QEventloop m_eventLoop; QMessageBox m_messageBox; QMetaObject::Connection m_lastConnect; };
then in SomeClass.cpp:
,,, void SomeClass::newNonBlocking() { if(!someCondition()) { m_messageBox.setText("blubb"); m_lastConnect = connect(&m_messageBox, &QMessageBox::accepted, this, &SomeClass::continuationOfnewNonBlocking); m_messageBox.show(); m_eventLoop.exec(); // spin here and wait for .exit() } else { continuationOfnewNonBlocking(); } } void SomeClass::continuationOfnewNonBlocking() { QObject::disconnect(m_lastConnect); m_eventLoop.exit(); qDebug() << "Do stuff as normal"; } ```
@hskoglund To my knowledge,
QEventloop::exec
will process all events and not only those related to the message box, and that’s exactly what causes problems for the OP. -
Hi, you could try spinning your own event loop inside SomeClass.
Say you add a QEventLoop instance in the .h file:... private: QEventloop m_eventLoop; QMessageBox m_messageBox; QMetaObject::Connection m_lastConnect; };
then in SomeClass.cpp:
,,, void SomeClass::newNonBlocking() { if(!someCondition()) { m_messageBox.setText("blubb"); m_lastConnect = connect(&m_messageBox, &QMessageBox::accepted, this, &SomeClass::continuationOfnewNonBlocking); m_messageBox.show(); m_eventLoop.exec(); // spin here and wait for .exit() } else { continuationOfnewNonBlocking(); } } void SomeClass::continuationOfnewNonBlocking() { QObject::disconnect(m_lastConnect); m_eventLoop.exit(); qDebug() << "Do stuff as normal"; } ```
@hskoglund I already tried something like that.