Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt Creator and other tools
  4. Create widget modal or detect mousePressEvent outside QDialog
Forum Updated to NodeBB v4.3 + New Features

Create widget modal or detect mousePressEvent outside QDialog

Scheduled Pinned Locked Moved Solved Qt Creator and other tools
19 Posts 3 Posters 3.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    bozo6919
    wrote on last edited by
    #1

    Hi, In my app, I want to display a window modal at a moment. But if the user press the mouse outside the widget, the widget will be closed.
    I tried to detect in a QDialog a solution to detect mouse outside the widget but I can't
    And I tried to create a new widget as a modal widget too but it's same, I can't...
    Anyone?

    My class :

    class ModalPopup : public QWidget
    {
    	Q_OBJECT
    
    public:
    	ModalPopup(QPoint cursor);
    	~ModalPopup(void);
    	QString getAct() { return act; }
    
    private:
    	void onActClicked(void);
    
    	QVBoxLayout *layout;
    	QPushButton *ActNew;
    	QPushButton *ActAdd;
    	QPushButton *ActSub;
    	QString act;
    
    protected:
    	void mousePressEvent(QMouseEvent *event) override;
    };
    
    ModalPopup::ModalPopup(QPoint cursor)
    {
    	grabMouse();
    	setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
    
    	ActNew = new QPushButton(tr("new"));
    	connect(ActNew, &QPushButton::clicked, this, &ModalPopup::onActClicked);
    
    	ActAdd = new QPushButton(tr("add"));
    	connect(ActAdd, &QPushButton::clicked, this, &ModalPopup::onActClicked);
    
    	ActSub = new QPushButton(tr("sub"));
    	connect(ActSub, &QPushButton::clicked, this, &ModalPopup::onActClicked);
    
    	layout = new QVBoxLayout(this);
    	layout->addWidget(ActNew);
    	layout->addWidget(ActAdd);
    	layout->addWidget(ActSub);
    	move(cursor);
    	show();
    }
    
    ModalPopup::~ModalPopup(void)
    {
    	delete ActNew;
    	delete ActAdd;
    	delete ActSub;
    	delete layout;
    }
    
    void ModalPopup::onActClicked(void)
    {
    	act = qobject_cast<QPushButton *>(sender())->text();
    	close();
    }
    
    void ModalPopup::mousePressEvent(QMouseEvent *event)
    {
    	QRect pos = this->geometry();
    	QPoint cursor = event->globalPos();
    
    	if (cursor.x() < pos.x() || cursor.x() > pos.x() + pos.width())
    		close();
    	else if (cursor.y() < pos.y() || cursor.y() > pos.y() + pos.height())
    		close();
    }
    

    Thanks in advance

    Sorry for my English ^^'

    1 Reply Last reply
    0
    • B Offline
      B Offline
      bozo6919
      wrote on last edited by
      #19

      Hi,

      I have solved my problem with QMenu, adding QAction, and exec(pos)

      Thanks a lot :)

      Sorry for my English ^^'

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi,

        The goal of a modal dialog is to block all inputs outside of the dialog. Can you explain your use case ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • B Offline
          B Offline
          bozo6919
          wrote on last edited by
          #3

          I want to close the widget and don't play the sound.

          Sorry for my English ^^'

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #4

            What sound ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • B Offline
              B Offline
              bozo6919
              wrote on last edited by
              #5

              The beep of the QDialog when I presse the left mouse button outside the QDialog

              Sorry for my English ^^'

              1 Reply Last reply
              0
              • B Offline
                B Offline
                bozo6919
                wrote on last edited by
                #6

                So ? Nobody ? :/

                Sorry for my English ^^'

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #7

                  Then why make it a modal dialog at all ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  1
                  • B Offline
                    B Offline
                    bozo6919
                    wrote on last edited by
                    #8

                    Yesterday I have tried to do that with a QWidget no modal but when I want to show it, it doesn't work

                    Sorry for my English ^^'

                    JonBJ 1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #9

                      it doesn't work is not a statement that allows to go further.

                      Show what you are doing, how you are using your dialog etc.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      2
                      • B bozo6919

                        Yesterday I have tried to do that with a QWidget no modal but when I want to show it, it doesn't work

                        JonBJ Online
                        JonBJ Online
                        JonB
                        wrote on last edited by
                        #10

                        @bozo6919
                        As @SGaist says, if you really care about getting rid of the native-OS-windows behaviour of beeping when clicking outside a modal dialog (why?), then you should use a modeless dialog instead and implement your desired behaviour in its totality. Though it's a lot easier to just accept the natural window manager behaviour....

                        1 Reply Last reply
                        0
                        • B Offline
                          B Offline
                          bozo6919
                          wrote on last edited by
                          #11

                          My class modalpopup :

                          	class ModalPopup : public QWidget
                          	{
                          		Q_OBJECT
                          
                          	public:
                          		ModalPopup(QPoint cursor);
                          		~ModalPopup(void);
                          		QString getAct() { return act; }
                          
                          	private:
                          		void onActClicked(void);
                          		QVBoxLayout *layout;
                          		QPushButton *ActNew;
                          		QPushButton *ActAdd;
                          		QPushButton *ActSub;
                          		QString act;
                          
                          	protected:
                          		void mousePressEvent(QMouseEvent *event) override;
                          	};
                          

                          It's implementation :

                          #include "ModalPopup.hpp"
                          
                          ModalPopup::ModalPopup(QPoint cursor)
                          {
                          	setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
                          
                          	ActNew = new QPushButton(tr("new"));
                          	connect(ActNew, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                          
                          	ActAdd = new QPushButton(tr("add"));
                          	connect(ActAdd, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                          
                          	ActSub = new QPushButton(tr("sub"));
                          	connect(ActSub, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                          
                          	layout = new QVBoxLayout(this);
                          	layout->addWidget(ActNew);
                          	layout->addWidget(ActAdd);
                          	layout->addWidget(ActSub);
                          
                          	move(cursor);
                          	show();
                          }
                          
                          ModalPopup::~ModalPopup(void)
                          {
                          	delete ActNew;
                          	delete ActAdd;
                          	delete ActSub;
                          	delete layout;
                          }
                          
                          void ModalPopup::onActClicked(void)
                          {
                          	act = qobject_cast<QPushButton *>(sender())->text();
                          	close();
                          }
                          
                          void ModalPopup::mousePressEvent(QMouseEvent *event)
                          {
                          	if (event->buttons() != Qt::LeftButton)
                          		return;
                          	QRect pos = this->geometry();
                          	QPoint cursor = event->globalPos();
                          
                          	if (cursor.x() < pos.x() || cursor.x() > pos.x() + pos.width())
                          		close();
                          	else if (cursor.y() < pos.y() || cursor.y() > pos.y() + pos.height())
                          		close();
                          }
                          

                          His call :

                          
                          void FlowView::dropEvent(QDropEvent *event)
                          {
                          	ModalPopup modal(event->pos());
                          
                          	foreach(const QUrl &url, event->mimeData()->urls()) {
                          		if (modal.getAct() == "new")
                          			_scene->loadThisPath(url.toLocalFile());
                          		else if (modal.getAct() == "add")
                          			_scene->add(url.toLocalFile());
                          	}
                          }
                          

                          But the widget is never display

                          Sorry for my English ^^'

                          JonBJ 1 Reply Last reply
                          0
                          • B bozo6919

                            My class modalpopup :

                            	class ModalPopup : public QWidget
                            	{
                            		Q_OBJECT
                            
                            	public:
                            		ModalPopup(QPoint cursor);
                            		~ModalPopup(void);
                            		QString getAct() { return act; }
                            
                            	private:
                            		void onActClicked(void);
                            		QVBoxLayout *layout;
                            		QPushButton *ActNew;
                            		QPushButton *ActAdd;
                            		QPushButton *ActSub;
                            		QString act;
                            
                            	protected:
                            		void mousePressEvent(QMouseEvent *event) override;
                            	};
                            

                            It's implementation :

                            #include "ModalPopup.hpp"
                            
                            ModalPopup::ModalPopup(QPoint cursor)
                            {
                            	setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
                            
                            	ActNew = new QPushButton(tr("new"));
                            	connect(ActNew, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                            
                            	ActAdd = new QPushButton(tr("add"));
                            	connect(ActAdd, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                            
                            	ActSub = new QPushButton(tr("sub"));
                            	connect(ActSub, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                            
                            	layout = new QVBoxLayout(this);
                            	layout->addWidget(ActNew);
                            	layout->addWidget(ActAdd);
                            	layout->addWidget(ActSub);
                            
                            	move(cursor);
                            	show();
                            }
                            
                            ModalPopup::~ModalPopup(void)
                            {
                            	delete ActNew;
                            	delete ActAdd;
                            	delete ActSub;
                            	delete layout;
                            }
                            
                            void ModalPopup::onActClicked(void)
                            {
                            	act = qobject_cast<QPushButton *>(sender())->text();
                            	close();
                            }
                            
                            void ModalPopup::mousePressEvent(QMouseEvent *event)
                            {
                            	if (event->buttons() != Qt::LeftButton)
                            		return;
                            	QRect pos = this->geometry();
                            	QPoint cursor = event->globalPos();
                            
                            	if (cursor.x() < pos.x() || cursor.x() > pos.x() + pos.width())
                            		close();
                            	else if (cursor.y() < pos.y() || cursor.y() > pos.y() + pos.height())
                            		close();
                            }
                            

                            His call :

                            
                            void FlowView::dropEvent(QDropEvent *event)
                            {
                            	ModalPopup modal(event->pos());
                            
                            	foreach(const QUrl &url, event->mimeData()->urls()) {
                            		if (modal.getAct() == "new")
                            			_scene->loadThisPath(url.toLocalFile());
                            		else if (modal.getAct() == "add")
                            			_scene->add(url.toLocalFile());
                            	}
                            }
                            

                            But the widget is never display

                            JonBJ Online
                            JonBJ Online
                            JonB
                            wrote on last edited by JonB
                            #12

                            @bozo6919
                            Your modal is modeless now. The constructor ends with a show(). That does not block, and it will not actually show till the next time the event loop is hit. Your code (dropEvent) constructs it, then immediately tests some action, and then the local variable modal goes out of scope and the function exits, destroying the dialog (step through in debugger or put in some qDebug()s to see the flow). Hence you probably see nothing.

                            If you are going to use a modeless dialog, it's your job to allow the event loop to be hit and the modeless to stay in existence & open until such time as the user does something where you want it closed.

                            1 Reply Last reply
                            0
                            • B Offline
                              B Offline
                              bozo6919
                              wrote on last edited by
                              #13

                              Yes, what I'm searching for, it's that my program in dropEvent wait that my modalPopup is closed. But I don't know how to do that. So my program continues and my modalPopup is destroyed, as you said. But he has to wait for the close of my modalPopup.

                              Sorry for my English ^^'

                              JonBJ 1 Reply Last reply
                              0
                              • B bozo6919

                                Yes, what I'm searching for, it's that my program in dropEvent wait that my modalPopup is closed. But I don't know how to do that. So my program continues and my modalPopup is destroyed, as you said. But he has to wait for the close of my modalPopup.

                                JonBJ Online
                                JonBJ Online
                                JonB
                                wrote on last edited by JonB
                                #14

                                @bozo6919
                                If you cannot rewrite your logic such that the actions are executed from within the dialog on button press, instead of returning to calling code and having it do it, then I think (untested) you can simulate a modal dialog via something like:

                                1. Create a QEventLoop at the very start of dropEvent.
                                2. Pass the QEventLoop * to the ModalPopup constructor.
                                3. Have dropEvent go loop.exec() after the ModalPopup constructor.
                                4. Have the actions in ModalPopup go loop.quit.

                                Or, you could put the QEventLoop into the ModalPopup constructor right at the end after the show() (or in another function) if that seems easier, keeping all the code in ModalPopup.

                                1 Reply Last reply
                                0
                                • B Offline
                                  B Offline
                                  bozo6919
                                  wrote on last edited by
                                  #15

                                  I have already tried this without result... But this was my first time that I use QEventLoop, so I'm going to try this method again ^^

                                  Sorry for my English ^^'

                                  1 Reply Last reply
                                  0
                                  • B Offline
                                    B Offline
                                    bozo6919
                                    wrote on last edited by bozo6919
                                    #16

                                    I have try again :

                                    #include "ModalPopup.hpp"
                                    
                                    ModalPopup::ModalPopup(QPoint cursor)
                                    	: loop(this)
                                    {
                                    	setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
                                    
                                    	ActNew = new QPushButton(tr("new"));
                                    	connect(ActNew, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                                    
                                    	ActAdd = new QPushButton(tr("add"));
                                    	connect(ActAdd, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                                    
                                    	ActSub = new QPushButton(tr("sub"));
                                    	connect(ActSub, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                                    
                                    	layout = new QVBoxLayout(this);
                                    	layout->addWidget(ActNew);
                                    	layout->addWidget(ActAdd);
                                    	layout->addWidget(ActSub);
                                    
                                    	move(cursor);
                                    	show();
                                    	loop.exec(QEventLoop::AllEvents);
                                    }
                                    
                                    ModalPopup::~ModalPopup(void)
                                    {
                                    	delete ActNew;
                                    	delete ActAdd;
                                    	delete ActSub;
                                    	delete layout;
                                    }
                                    
                                    void ModalPopup::onActClicked(void)
                                    {
                                    	act = qobject_cast<QPushButton *>(sender())->text();
                                    	loop.quit();
                                    	close();
                                    }
                                    
                                    void ModalPopup::mousePressEvent(QMouseEvent *event)
                                    {
                                    	if (event->buttons() != Qt::LeftButton)
                                    		return;
                                    	QRect pos = this->geometry();
                                    	QPoint cursor = event->globalPos();
                                    
                                    	if (cursor.x() < pos.x() || cursor.x() > pos.x() + pos.width()) {
                                    		loop.quit();
                                    		close();
                                    	} else if (cursor.y() < pos.y() || cursor.y() > pos.y() + pos.height()) {
                                    		loop.quit();
                                    		close();
                                    	}
                                    }
                                    
                                    

                                    My widget is displayed, but I never enter in my function mousePressEvent so, my window is never closed :/

                                    Sorry for my English ^^'

                                    JonBJ 1 Reply Last reply
                                    0
                                    • B bozo6919

                                      I have try again :

                                      #include "ModalPopup.hpp"
                                      
                                      ModalPopup::ModalPopup(QPoint cursor)
                                      	: loop(this)
                                      {
                                      	setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
                                      
                                      	ActNew = new QPushButton(tr("new"));
                                      	connect(ActNew, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                                      
                                      	ActAdd = new QPushButton(tr("add"));
                                      	connect(ActAdd, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                                      
                                      	ActSub = new QPushButton(tr("sub"));
                                      	connect(ActSub, &QPushButton::clicked, this, &ModalPopup::onActClicked);
                                      
                                      	layout = new QVBoxLayout(this);
                                      	layout->addWidget(ActNew);
                                      	layout->addWidget(ActAdd);
                                      	layout->addWidget(ActSub);
                                      
                                      	move(cursor);
                                      	show();
                                      	loop.exec(QEventLoop::AllEvents);
                                      }
                                      
                                      ModalPopup::~ModalPopup(void)
                                      {
                                      	delete ActNew;
                                      	delete ActAdd;
                                      	delete ActSub;
                                      	delete layout;
                                      }
                                      
                                      void ModalPopup::onActClicked(void)
                                      {
                                      	act = qobject_cast<QPushButton *>(sender())->text();
                                      	loop.quit();
                                      	close();
                                      }
                                      
                                      void ModalPopup::mousePressEvent(QMouseEvent *event)
                                      {
                                      	if (event->buttons() != Qt::LeftButton)
                                      		return;
                                      	QRect pos = this->geometry();
                                      	QPoint cursor = event->globalPos();
                                      
                                      	if (cursor.x() < pos.x() || cursor.x() > pos.x() + pos.width()) {
                                      		loop.quit();
                                      		close();
                                      	} else if (cursor.y() < pos.y() || cursor.y() > pos.y() + pos.height()) {
                                      		loop.quit();
                                      		close();
                                      	}
                                      }
                                      
                                      

                                      My widget is displayed, but I never enter in my function mousePressEvent so, my window is never closed :/

                                      JonBJ Online
                                      JonBJ Online
                                      JonB
                                      wrote on last edited by JonB
                                      #17

                                      @bozo6919
                                      And are you saying your mousePressEvent() function would be entered if you removed the loop.exec()? How do you know the function is not even entered (please put some debug in)?

                                      I don't really get the concept here. I believe your ModalPopup::mousePressEvent() is intending to recognise that a mouse click's coordinates are outside of the "dialog" and then close itself, right? But why would a mouse press event outside of a window be sent to that window? I would have thought you'd need this test in the app/main window's event filter or widget or something, not in an override of the window you want to close? Unless I'm not getting it....

                                      (P.S. There's a window style like "Popup" [Qt::Popup] or similar, I believe, which does auto-dismiss on click outside without beep, which I think is what you're wanting. I don't know if it stays there while you interact with its buttons. But if that would do what you want it would be a lot simpler, you sure that won't do you...)

                                      EDIT: The longer I think about this, I wonder if the last paragraph above is your problem? Go back to how you started. If I were doing this I would expect to create a modeless dialog (you said you know how to do that). But the code to recognise the "click outside" (elsewhere in your app, e.g. on the main window) cannot be written in the dialog (I assume it won't be sent the event). I would expect that code to be in your other window or main event loop, and there you would recognise a click on it and tell the modeless dialog to close if it's open. No?

                                      I see stuff like https://stackoverflow.com/a/16513021/489865, where the OP does

                                      2.I installed an event filter with my Qt::tool window and I began receiving events that assisted me in understanding when other parts of my application were clicked, or if the application itself lost focus to another application. This was what I needed, functionality wise. I could also get an event when users click the non-client areas of the application's main window, such as the windows caption so that I can close it when dragging begins etc.

                                      All sounds hideous...

                                      1 Reply Last reply
                                      0
                                      • B Offline
                                        B Offline
                                        bozo6919
                                        wrote on last edited by
                                        #18

                                        Thanks a lot, I have some result, my window displays and closed when I click outside. But I'm searching for how close the QEventLoop when I switch windows whit Alt+Tab
                                        In my constructor, I added :

                                        	setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
                                        	setAttribute(Qt::WA_NoSystemBackground, true);
                                        	setAttribute(Qt::WA_TranslucentBackground, true);
                                        	setWindowFlag(Qt::WindowType::NoDropShadowWindowHint, true);
                                        	setFocusPolicy(Qt::ClickFocus);
                                        

                                        And in my class, a function reimplemented :

                                        
                                        void ModalPopup::leaveEvent(QEvent *event)
                                        {
                                        	if (event->type() == QEvent::ApplicationDeactivate)
                                        		loop.quit();
                                        }
                                        

                                        But with no effect :/

                                        Sorry for my English ^^'

                                        1 Reply Last reply
                                        0
                                        • B Offline
                                          B Offline
                                          bozo6919
                                          wrote on last edited by
                                          #19

                                          Hi,

                                          I have solved my problem with QMenu, adding QAction, and exec(pos)

                                          Thanks a lot :)

                                          Sorry for my English ^^'

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved