Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Showing a QMessageBox or QColorDialog disrupts mouse clicks in a QGraphicsScene
Qt 6.11 is out! See what's new in the release blog

Showing a QMessageBox or QColorDialog disrupts mouse clicks in a QGraphicsScene

Scheduled Pinned Locked Moved General and Desktop
18 Posts 3 Posters 6.0k Views 3 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.
  • J Offline
    J Offline
    JanLaloux
    wrote on last edited by JanLaloux
    #1

    I have a QGraphicsScene with circles for which the mousePressEvent method is defined. If in handling the mouse event for circle x a QMessageBox is shown, from then on all clicks wherever in the scene will trigger the mouse event for circle x again.
    In the code below if the messagebox is removed, the mouse clicks are performing normal.

    Is there a way to avoid this behaviour?

    #include <string>;
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QMessageBox>
    #include <QtWidgets/QMainWindow>
    #include <QtWidgets/QGraphicsScene>
    #include <QtWidgets/QGraphicsView>
    #include <QtWidgets/QGridLayout>
    #include <QtWidgets/QGraphicsEllipseItem>
    
    using namespace std;
    
    
    class Circle : public QGraphicsEllipseItem {
    public:
        Circle::Circle(int Id, const qreal ax, const qreal ay, const qreal wx, const qreal wy, QGraphicsScene *scene) :
            QGraphicsEllipseItem(ax, ay, wx, wy),
            Id(Id)
        {
            setPen( QPen(QBrush(Qt::black), 1, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) );
            setBrush( QBrush(Qt::gray) );
            setRect(ax, ay, wx, wy);
            setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
            scene->addItem(this);
        }
    
        ~Circle(){}
    
        void Circle::mousePressEvent(QGraphicsSceneMouseEvent *event) {
            QMessageBox msgBox;
            string msg{ "Circle " + to_string(Id) + " clicked" };
            QString QResult{ QString::fromLatin1(msg.c_str()) };
            msgBox.setText( QResult );
            msgBox.exec();
        }
        int Id;
    };
    
    
    
    
    class MainWindow : public QMainWindow
    {
    public:
        QWidget *baseWidget;
        QGridLayout *baseWidgetGrid;
        QGraphicsScene *graphicsScene;
        QGraphicsView *graphicsView;
    
    public:
        MainWindow::MainWindow(QWidget *parent=0) :
            QMainWindow(parent)
        {
            graphicsScene = new QGraphicsScene(0, 0, 120, 120);
            graphicsScene->addRect( 10, 10,  100, 100 );
            new Circle( 1, 20, 20, 20, 20, graphicsScene );
            new Circle( 2, 75, 75, 20, 20, graphicsScene );
    
            baseWidget = new QWidget(this);
            baseWidgetGrid = new QGridLayout(baseWidget);
                graphicsView = new QGraphicsView(baseWidget);
                graphicsView->setRenderHint(QPainter::Antialiasing);
                graphicsView->setScene(graphicsScene);
            baseWidgetGrid->addWidget(graphicsView, 0, 0, 1, 1);
    
            setCentralWidget(baseWidget);
        }
    
        ~MainWindow(){}
    };
    
    
    int main(int argc, char *argv[])
    {
        QApplication Application(argc, argv);
        MainWindow MainWin;
        MainWin.show();
        return Application.exec();
    }
    
    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi
      I found this very strange so I played around with it.

      The call msgBox.exec(); creates a new message loop which apparently completely confuses
      QGraphicsScene / view.

      I also tried with QDialog and got same result.

      Its related to this
      https://blog.qt.io/blog/2010/02/23/unpredictable-exec/
      (i think)

      using msgBox.open makes it close at once so found no workaround.

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

        Hi,

        To add to @mrjj, using open with a heap allocated msgBox where theQt::WA_DeleteOnClose flag is set is the way to go.

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

        mrjjM 1 Reply Last reply
        1
        • SGaistS SGaist

          Hi,

          To add to @mrjj, using open with a heap allocated msgBox where theQt::WA_DeleteOnClose flag is set is the way to go.

          mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @SGaist said:
          Doh. I cant believe I made the run out of scope error.
          Of Course it will close at once when on stack...
          Thank you.

          Anyways,

          using this

                 QMessageBox *msgBox=new QMessageBox() ;
                  msgBox->setText( "QResult" );
                  msgBox->setAttribute(Qt::WA_DeleteOnClose);
                  msgBox->open();
          

          Does not mess with the actually clicking but you can open more than one.

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

            IIRC, giving it a parent at creation time should take care of that.

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

            mrjjM 1 Reply Last reply
            0
            • SGaistS SGaist

              IIRC, giving it a parent at creation time should take care of that.

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @SGaist
              It does. so 100% working.

              So change the constructor to include pointer to parent
              Circle (QWidget *Parent, .....

              and store that in variable and use that in
              QMessageBox *msgBox=new QMessageBox(Parent) ;

              And you should be happy.

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

                I was thinking of something like QMessageBox *msgBox=new QMessageBox(this);

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

                mrjjM 1 Reply Last reply
                0
                • SGaistS SGaist

                  I was thinking of something like QMessageBox *msgBox=new QMessageBox(this);

                  mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by mrjj
                  #8

                  @SGaist
                  But its not a QObject ?
                  no matching function for call to 'QMessageBox::QMessageBox(Circle*)'

                  so a cast will work?
                  ^

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

                    My bad, I've misread, in that case I'd rather use:
                    QMessageBox *msgBox=new QMessageBox(scene());

                    But no, casting will not help at all, since QGraphicsItem is not a QWidget

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

                    mrjjM 1 Reply Last reply
                    0
                    • SGaistS SGaist

                      My bad, I've misread, in that case I'd rather use:
                      QMessageBox *msgBox=new QMessageBox(scene());

                      But no, casting will not help at all, since QGraphicsItem is not a QWidget

                      mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by mrjj
                      #10

                      @SGaist
                      Still it is not really happy
                      no matching function for call to 'QMessageBox::QMessageBox(QGraphicsScene*)'
                      But it is a QObject it seems.. ?

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

                        Damn, I've mixed scene and view...

                        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
                        • mrjjM Offline
                          mrjjM Offline
                          mrjj
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          aha!
                          so
                          QMessageBox *msgBox = new QMessageBox ( scene()->views()[0] ) ;
                          works even if ugly :)

                          should be
                          QGraphicsView *Par=scene()->views()[0];
                          if (!Par) return;
                          QMessageBox *msgBox = new QMessageBox ( Par) ;

                          for minimum safety.

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

                            Well for extra safety you should loop on the views to find one that currently shows the item clicked unless you know that you have exactly one view on the scene.

                            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
                            • J Offline
                              J Offline
                              JanLaloux
                              wrote on last edited by
                              #14

                              Thanks guys, this effectively works

                              1 Reply Last reply
                              0
                              • J Offline
                                J Offline
                                JanLaloux
                                wrote on last edited by
                                #15

                                I have to reopen this topic. I now want to open a QColorDialog when an item is clicked. I first used the static funtion QColorDialog::getColor() but experienced the same problem as with the QMessageBox.
                                A bit wiser now I modified it to mimic the solution for QMessageBox. Below is the "ready to go" code.

                                A problem is that I cannot set the Qt::WA_DeleteOnClose attribute on the dialog because I have to retrieve the selected color with selectedColor(). So I delete the dialog explictely after that. But no help, a second click where ever in the scene triggers a click on the first object. Any ideas?

                                #include <string>
                                #include <QtWidgets/QApplication>
                                #include <QtWidgets/QColorDialog>
                                #include <QtWidgets/QMainWindow>
                                #include <QtWidgets/QGraphicsScene>
                                #include <QtWidgets/QGraphicsView>
                                #include <QtWidgets/QGridLayout>
                                #include <QtWidgets/QGraphicsEllipseItem>
                                
                                using namespace std;
                                
                                
                                class Circle : public QGraphicsEllipseItem {
                                public:
                                    Circle::Circle(int Id, const qreal ax, const qreal ay, const qreal wx, const qreal wy, QGraphicsScene *scene, QWidget *parent) :
                                        QGraphicsEllipseItem(ax, ay, wx, wy),
                                        Id(Id),
                                		Parent(parent)
                                    {
                                        setPen( QPen(QBrush(Qt::black), 1, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) );
                                        setBrush( QBrush(Qt::gray) );
                                        setRect(ax, ay, wx, wy);
                                        setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
                                        scene->addItem(this);
                                    }
                                
                                    ~Circle(){}
                                
                                    void Circle::mousePressEvent(QGraphicsSceneMouseEvent *event) {
                                		QColorDialog* ColorDialog{ new QColorDialog( this->brush().color(), Parent ) };
                                		//ColorDialog->setAttribute(Qt::WA_DeleteOnClose);
                                		ColorDialog->exec();
                                		QColor ColourPick{ ColorDialog->selectedColor() };
                                		if( ColourPick.isValid() )
                                			setBrush( ColourPick );
                                  		delete ColorDialog;
                                  }
                                    int Id;
                                	QWidget *Parent;
                                };
                                
                                
                                
                                class MainWindowC : public QMainWindow
                                {
                                public:
                                    QWidget *baseWidget;
                                    QGridLayout *baseWidgetGrid;
                                    QGraphicsScene *graphicsScene;
                                    QGraphicsView *graphicsView;
                                
                                public:
                                    MainWindowC::MainWindowC(QWidget *parent=0) :
                                        QMainWindow(parent)
                                    {
                                        baseWidget = new QWidget(this);
                                        baseWidgetGrid = new QGridLayout(baseWidget);
                                			graphicsScene = new QGraphicsScene(0, 0, 120, 120);
                                			graphicsScene->addRect( 10, 10,  100, 100 );
                                			new Circle( 1, 20, 20, 20, 20, graphicsScene, baseWidget );
                                			new Circle( 2, 75, 75, 20, 20, graphicsScene, baseWidget );
                                
                                			graphicsView = new QGraphicsView(baseWidget);
                                            graphicsView->setRenderHint(QPainter::Antialiasing);
                                            graphicsView->setScene(graphicsScene);
                                        baseWidgetGrid->addWidget(graphicsView, 0, 0, 1, 1);
                                
                                        setCentralWidget(baseWidget);
                                    }
                                
                                    ~MainWindowC(){}
                                };
                                
                                
                                int main(int argc, char *argv[])
                                {
                                    QApplication ApplicationC(argc, argv);
                                    MainWindowC MainWinC;
                                    MainWinC.show();
                                    return ApplicationC.exec();
                                }
                                
                                1 Reply Last reply
                                0
                                • mrjjM Offline
                                  mrjjM Offline
                                  mrjj
                                  Lifetime Qt Champion
                                  wrote on last edited by mrjj
                                  #16

                                  Hi , its the
                                  ColorDialog->exec(); (makes own event loop)

                                  We found out that using open() helped.

                                  Try to see if open() works for ColorDialog ?

                                  Also read docs on "open." you can hook it up to a slot in your code when user
                                  select color and click ok . That way it can work.

                                  1 Reply Last reply
                                  0
                                  • J Offline
                                    J Offline
                                    JanLaloux
                                    wrote on last edited by
                                    #17

                                    No help, same behaviour. This is the modified code:

                                    #include <string>
                                    #include <QtWidgets/QApplication>
                                    #include <QtWidgets/QColorDialog>
                                    #include <QtWidgets/QMainWindow>
                                    #include <QtWidgets/QGraphicsScene>
                                    #include <QtWidgets/QGraphicsView>
                                    #include <QtWidgets/QGridLayout>
                                    #include <QtWidgets/QGraphicsEllipseItem>
                                    
                                    using namespace std;
                                    
                                    class Circle : public QGraphicsEllipseItem {
                                    public:
                                        Circle::Circle(int Id, const qreal ax, const qreal ay, const qreal wx, const qreal wy, QGraphicsScene *scene, QWidget *parent) :
                                            QGraphicsEllipseItem(ax, ay, wx, wy),
                                            Id(Id),
                                            Parent(parent)
                                        {
                                            setPen( QPen(QBrush(Qt::black), 1, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) );
                                            setBrush( QBrush(Qt::gray) );
                                            setRect(ax, ay, wx, wy);
                                            setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
                                            scene->addItem(this);
                                        }
                                    
                                        ~Circle(){}
                                    
                                        void Circle::mousePressEvent(QGraphicsSceneMouseEvent *event);
                                    
                                        int Id;
                                        QWidget *Parent;
                                    };
                                    
                                    
                                    
                                    class MainWin : public QMainWindow
                                    {
                                    public:
                                        QWidget *baseWidget;
                                        QGridLayout *baseWidgetGrid;
                                        QGraphicsScene *graphicsScene;
                                        QGraphicsView *graphicsView;
                                    
                                        MainWin::MainWin(QWidget *parent=0) :
                                            QMainWindow(parent)
                                        {
                                            baseWidget = new QWidget(this);
                                            baseWidgetGrid = new QGridLayout(baseWidget);
                                                graphicsScene = new QGraphicsScene(0, 0, 120, 120);
                                                graphicsScene->addRect( 10, 10,  100, 100 );
                                                new Circle( 1, 20, 20, 20, 20, graphicsScene, baseWidget );
                                                new Circle( 2, 75, 75, 20, 20, graphicsScene, baseWidget );
                                    
                                                graphicsView = new QGraphicsView(baseWidget);
                                                graphicsView->setRenderHint(QPainter::Antialiasing);
                                                graphicsView->setScene(graphicsScene);
                                            baseWidgetGrid->addWidget(graphicsView, 0, 0, 1, 1);
                                    
                                            setCentralWidget(baseWidget);
                                        }
                                    
                                        ~MainWin(){}
                                    
                                    	void colorSelected(const QColor & color);
                                    };
                                    
                                    Circle* CircleClicked;
                                    QColorDialog* ColorDialog;
                                    MainWin* pMainWindow;
                                    
                                    void MainWin::colorSelected(const QColor & color){
                                    	QColor ColorPick{ color };
                                    
                                    	CircleClicked->setBrush( QBrush( ColorPick ) );
                                    	CircleClicked->update();
                                    
                                    	ColorDialog->deleteLater();
                                    }
                                    
                                    void Circle::mousePressEvent(QGraphicsSceneMouseEvent *event) {
                                    	CircleClicked = this;
                                    
                                    	ColorDialog = new QColorDialog( this->brush().color(), pMainWindow->baseWidget );
                                    	pMainWindow->connect( ColorDialog, &QColorDialog::colorSelected, pMainWindow, &MainWin::colorSelected );
                                    	ColorDialog->open();
                                    }
                                    
                                    
                                    int main(int argc, char *argv[])
                                    {
                                        QApplication Application(argc, argv);
                                        MainWin MainWindow;
                                    	pMainWindow = &MainWindow;
                                        MainWindow.show();
                                        return Application.exec();
                                    }
                                    
                                    1 Reply Last reply
                                    0
                                    • mrjjM Offline
                                      mrjjM Offline
                                      mrjj
                                      Lifetime Qt Champion
                                      wrote on last edited by mrjj
                                      #18

                                      @JanLaloux said:

                                      Well the void QDialog::open() seems not the same as
                                      QMessageBox::open
                                      so sadly it still creates a message loop it seems
                                      so it wont work.

                                      That what I mean by
                                      "Try to see if open() works for ColorDialog ?"
                                      Did have doc so could not check.

                                      So unless ->show() do not create a messageloop , I dont know how you
                                      can make it work.

                                      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