Custom Synchronous Message Dialog with QEventLoop



  • Hello. I'm working on a desktop application using QtQuick. It's a wizard-like application, and I would like to have only one window. I'm trying to make a custom message dialog control to match my application graphics. It would be better if it were synchronous, because then I wouldn't need a slot every time I show a message, as most of the times I need user input (OK,Cancel,Yes,No) in order to proceed. It's working as expected, except for one issue. I don't like posting lots of code, but there was not other way this time. I'm sorry. Let's say this is my main window:

    ApplicationWindow {
    	Button {
    		text: "Do Task"
    		onClicked: controller.doTask()
    	}
    	Rectangle {
    		id: msgRec
    		anchors.fill: parent /* takes the whole window */
    		visible: false
    		MouseArea { /* blocks user input on controls behind */
    			anchors.fill: parent
    		}
    		Text {
    			id: msgText
    		}
    		Button {
    			text: "OK"
    			onClicked: {
    				msgRec.visible = false;
    				msgbox.endShow();
    			}
    		}
    		Connections {
    			target: msgbox
    			onShow: {
    				msgText.text = message;
    				msgRec.visible = true;
    			}
    		}
    	}
    }
    

    "msgbox" and "controller" are C++ classes.

    class MyMsgBox : public QObject {
    	Q_OBJECT
    
    private:
    
    	QEventLoop* myLoop;
    
    public:
    
    	MyMsgBox(QObject *parent) : QObject(parent){
    		myLoop = NULL;
    	}
    
    	static MyMsgBox* getInstance(){
    		static MyMsgBox* instance = NULL;
    		if(instance == NULL) instance = new MyMsgBox;
    		return instance;
    	}
    	
    	static void alert(QString message){
    		MyMsgBox::getInstance()->beginShow(message);
    	}
    
    	int beginShow(QString message){
    
    		qDebug() << "beginShow()"; /* happens on showing dialog and on first clicking OK */
    
    		if(myLoop != NULL) return -1;
    	
    		this->show(message);
    	
    		myLoop = new QEventLoop(this);
    
    		myLoop->exec();
    	
    		delete myLoop;
    	
    		myLoop = NULL;
    	
    		return 0; // it will return the button index
    	
    	}
    
    	Q_INVOKABLE void endShow(){
    		myLoop->exit(0);
    	}
    
    signals:
    
    	void show(QString message);
    }
    
    class MyController : public QObject {
    	Q_OBJECT
    
    public:
    
    	Q_INVOKABLE void doTask() {
    		// ...
    		MyMsgBox::alert("Hello world!");
    		// ...
    	}
    
    }
    
    //=============
    
    context->setContextProperty("controller", MyController());
    context->setContextProperty("msgbox", MyMsgBox::getInstance());
    

    When the user clicks on the "OK" button, it fires "beginShow" again. Then, when he clicks again, now it fires "endShow" as it should and dismisses the dialog. It's so weird I'm having a hard time putting it into words. Please, check this image:

    So, any ideas about what might be going on?

    Thank you.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Not really an answer but, why not use a state machine ? That would make your code logic more wizard like and might avoid the use of that QEventLoop

    Hope it helps



  • @SGaist Hi. Thank you for your help. I'll give it a try, but I still don't get why my code doesn't work... If anyone could take a guess, I'd appreciate.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.