Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Make dialog modal but don't block context menu
Forum Updated to NodeBB v4.3 + New Features

Make dialog modal but don't block context menu

Scheduled Pinned Locked Moved Solved Qt for Python
7 Posts 3 Posters 2.7k Views 2 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.
  • E Offline
    E Offline
    efremdan1
    wrote on 9 Feb 2021, 04:55 last edited by efremdan1 2 Sept 2021, 15:56
    #1

    I have an application which has a pyqtgraph instance in a dialog box. I want this dialog box to be modal (I don't want the user to be able to interact with the main window while the dialog box is open), so normally I would set setWindowModality() to Qt.ApplicationModal. However, this blocks the pyqtgraph's context menu from being accessible (I can right click on the pyqtgraph instance, and it shows me the context menu, but I'm not allowed to click on it).

    I tried instead to set setWindowModality() to Qt.WindowModal. However, this locks the dialog box to the main window, which I don't like (I want the user to be able to see the main window while interacting with the dialog box).

    Is there anyway to either:

    1. Use setWindowModality(Qt.ApplicationModal) but not block the pyqtgraph context menu?
      or
    2. Use setWindowModality(Qt.WindowModal) but be able to undock the dialog box?

    A minimal working example showing the behavior is below. You can see the 3 behaviors that result when setting the window modality to Qt.ApplicationModal, Qt.WindowModal, and Qt.NonModal.

    import sys
    
    from PySide2.QtWidgets import *
    from PySide2.QtGui import *
    from PySide2.QtCore import *
    
    import pyqtgraph as pg
    
    class MainWindow(QMainWindow):
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
            b = QPushButton()
            b.setText("Open dialog")
            self.setCentralWidget(b)
            b.clicked.connect(self.showdialog)
    
        def showdialog(self):
            self.d = CustomDialog(self)
    
    #        # not modal
    #        self.d.setWindowModality(Qt.NonModal)
    #        self.d.show()
    
            # location can't be moved
            self.d.setWindowModality(Qt.WindowModal)
            self.d.exec_()
    
    #        # blocks context menu
    #        self.d.setWindowModality(Qt.ApplicationModal)
    #        self.d.exec_()
    
    
    class CustomDialog(QDialog):
        def __init__(self, *args, **kwargs):
            super(CustomDialog, self).__init__(*args, **kwargs)
    
            buttons = QDialogButtonBox.Cancel
            self.buttonBox = QDialogButtonBox(buttons)
            self.buttonBox.rejected.connect(self.reject)
            self.layout = QVBoxLayout()
            self.layout.addWidget(pg.PlotWidget(self))
            self.layout.addWidget(self.buttonBox)
            self.setLayout(self.layout)
    
    
    if __name__ == '__main__':
       app = QApplication(sys.argv)
       window = MainWindow()
       window.show()
       sys.exit(app.exec_())
    
    1 Reply Last reply
    0
    • E Offline
      E Offline
      efremdan1
      wrote on 10 Feb 2021, 16:14 last edited by
      #5

      A nice workaround was sent to me on the PyQtGraph forum (see https://groups.google.com/g/pyqtgraph/c/gNYYmVkP7hE).

      We disable the entire parent window (repainting it to get around a separate bug: https://bugreports.qt.io/browse/PYSIDE-695), enable the dialog window (which was disabled automatically when its parent was disabled), throw in a Qt.WindowStaysOnTopHint window flag, and connect the dialog window's close to enable the parent window. This has almost the same effect as making the dialog modal (the only difference I can discern is that the parent window is grayed out), but the PyQtGraph object's context menu is accessible.

      import sys
      
      from PySide2.QtWidgets import *
      from PySide2.QtGui import *
      from PySide2.QtCore import *
      
      import pyqtgraph as pg
      
      class MainWindow(QMainWindow):
          def __init__(self, *args, **kwargs):
              super(MainWindow, self).__init__(*args, **kwargs)
              b = QPushButton()
              b.setText("Open dialog")
              self.setCentralWidget(b)
              b.clicked.connect(self.showdialog)
      
          def showdialog(self):
              self.d = CustomDialog(self)
      
      #        # not modal
      #        self.d.setWindowModality(Qt.NonModal)
      #        self.d.show()
      
      #        # location can't be moved
      #        self.d.setWindowModality(Qt.WindowModal)
      #        self.d.exec_()
      
      #        # blocks context menu
      #        self.d.setWindowModality(Qt.ApplicationModal)
      #        self.d.exec_()
      
              if sys.platform == 'darwin':
                  self.setEnabled(False)
                  self.repaint()
                  self.d.setEnabled(True)
                  self.d.setWindowFlag(Qt.WindowStaysOnTopHint)
                  self.d.finished.connect(lambda: self.setEnabled(True))
                  self.d.show()   # This dialog is not modal (though we make it modal manually).
              else:
                  self.d.exec_()  # This dialog is modal.
      
      
      class CustomDialog(QDialog):
          def __init__(self, *args, **kwargs):
              super(CustomDialog, self).__init__(*args, **kwargs)
      
              buttons = QDialogButtonBox.Cancel
              self.buttonBox = QDialogButtonBox(buttons)
              self.buttonBox.rejected.connect(self.reject)
              self.layout = QVBoxLayout()
              self.layout.addWidget(pg.PlotWidget(self))
              self.layout.addWidget(self.buttonBox)
              self.setLayout(self.layout)
      
      
      if __name__ == '__main__':
         app = QApplication(sys.argv)
         window = MainWindow()
         window.show()
         sys.exit(app.exec_())
      
      1 Reply Last reply
      1
      • E Offline
        E Offline
        efremdan1
        wrote on 9 Feb 2021, 15:59 last edited by efremdan1 2 Sept 2021, 16:09
        #2

        Update:

        Apparently the pyqtgraph context menu only gets blocked on a Mac. When I run the working example using Qt.ApplicationModal on my Ubuntu OS, I can access the context menu. Still trying to figure out how to fix this issue on a Mac...

        1 Reply Last reply
        0
        • E Offline
          E Offline
          efremdan1
          wrote on 9 Feb 2021, 17:13 last edited by
          #3

          Solution:

          Replace:
          self.d = CustomDialog(self)
          with:
          self.d = CustomDialog()

          Then, using Qt.WindowModal won't anchor the dialog to its parent window, since it doesn't have a parent window.

          1 Reply Last reply
          0
          • E Offline
            E Offline
            efremdan1
            wrote on 9 Feb 2021, 17:35 last edited by
            #4

            Sorry, that is not a valid solution. That makes the dialog box modeless; it's the same as doing self.d.setWindowModality(Qt.NonModal). The user can then access the MainWindow dialog, which I don't want.

            Any suggestions?

            1 Reply Last reply
            0
            • E Offline
              E Offline
              efremdan1
              wrote on 10 Feb 2021, 16:14 last edited by
              #5

              A nice workaround was sent to me on the PyQtGraph forum (see https://groups.google.com/g/pyqtgraph/c/gNYYmVkP7hE).

              We disable the entire parent window (repainting it to get around a separate bug: https://bugreports.qt.io/browse/PYSIDE-695), enable the dialog window (which was disabled automatically when its parent was disabled), throw in a Qt.WindowStaysOnTopHint window flag, and connect the dialog window's close to enable the parent window. This has almost the same effect as making the dialog modal (the only difference I can discern is that the parent window is grayed out), but the PyQtGraph object's context menu is accessible.

              import sys
              
              from PySide2.QtWidgets import *
              from PySide2.QtGui import *
              from PySide2.QtCore import *
              
              import pyqtgraph as pg
              
              class MainWindow(QMainWindow):
                  def __init__(self, *args, **kwargs):
                      super(MainWindow, self).__init__(*args, **kwargs)
                      b = QPushButton()
                      b.setText("Open dialog")
                      self.setCentralWidget(b)
                      b.clicked.connect(self.showdialog)
              
                  def showdialog(self):
                      self.d = CustomDialog(self)
              
              #        # not modal
              #        self.d.setWindowModality(Qt.NonModal)
              #        self.d.show()
              
              #        # location can't be moved
              #        self.d.setWindowModality(Qt.WindowModal)
              #        self.d.exec_()
              
              #        # blocks context menu
              #        self.d.setWindowModality(Qt.ApplicationModal)
              #        self.d.exec_()
              
                      if sys.platform == 'darwin':
                          self.setEnabled(False)
                          self.repaint()
                          self.d.setEnabled(True)
                          self.d.setWindowFlag(Qt.WindowStaysOnTopHint)
                          self.d.finished.connect(lambda: self.setEnabled(True))
                          self.d.show()   # This dialog is not modal (though we make it modal manually).
                      else:
                          self.d.exec_()  # This dialog is modal.
              
              
              class CustomDialog(QDialog):
                  def __init__(self, *args, **kwargs):
                      super(CustomDialog, self).__init__(*args, **kwargs)
              
                      buttons = QDialogButtonBox.Cancel
                      self.buttonBox = QDialogButtonBox(buttons)
                      self.buttonBox.rejected.connect(self.reject)
                      self.layout = QVBoxLayout()
                      self.layout.addWidget(pg.PlotWidget(self))
                      self.layout.addWidget(self.buttonBox)
                      self.setLayout(self.layout)
              
              
              if __name__ == '__main__':
                 app = QApplication(sys.argv)
                 window = MainWindow()
                 window.show()
                 sys.exit(app.exec_())
              
              1 Reply Last reply
              1
              • B Offline
                B Offline
                Bob_Walton_Apple
                wrote on 12 Apr 2021, 05:54 last edited by
                #6

                I have the same problem on an OSX previously developed application, which was fully operational using PyQt5 V5.14.2 but stopped working from V5.15.0 onward. This seems to be a PyQt bug which is blocking the context menu mouse signal. Right click brings up the context menu fine but selecting an item is blocked using the mouse, using the keyboard however to navigate and select works fine. I have no idea how to raise this as a bug in Qt.

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  mabeghin
                  wrote on 29 Sept 2021, 07:51 last edited by
                  #7
                  I have the same problem on an OSX previously developed application, which was fully operational using PyQt5 V5.14.2 but stopped working from V5.15.0 onward. This seems to be a PyQt bug
                  

                  No this is a Qt bug. I have a same issue in C++. I have a menu set to a button in an Application Modal dialog and menu items are not selectable (macOS) since Qt5.15. I finally set it as WindowModal with a parent even if I'd prefer the window to have a title bar and be movable, not popping up inside parent window... Disabling parent and setting always on top is an idea but it would make all parent window disabled which is not a standard behavior.

                  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