跳到內容
  • 版面
  • 最新
  • 標籤
  • 熱門
  • 使用者
  • 群組
  • 搜尋
  • Get Qt Extensions
  • Unsolved
Collapse
品牌標誌
  1. 首頁
  2. Qt Development
  3. General and Desktop
  4. Modeless dialog problem
Forum Updated to NodeBB v4.3 + New Features

Modeless dialog problem

已排程 已置頂 已鎖定 已移動 Solved General and Desktop
8 貼文 3 Posters 2.2k 瀏覽 2 Watching
  • 從舊到新
  • 從新到舊
  • 最多點贊
回覆
  • 在新貼文中回覆
登入後回覆
此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
  • JonBJ 離線
    JonBJ 離線
    JonB
    寫於 最後由 JonB 編輯
    #1

    Qt 5.9. Tested under Linux. Target both Linux & Windows (which I cannot test). Hopefully none of this is actually relevant.

    I have a problem whereby a modeless dialog is getting put behind another dialog/window when I intend it to be 100% independent/top-level/free to be clicked to be either behind or on top, like any independent window.

    1. Main window creates QDialog (call it modalDialog) with itself (main window) as parent, and displays it via exec(). Correctly produces a modal dialog:
      0_1559218470470_Screenshot from 2019-05-30 13-12-22.png

    2. That modal dialog creates another QDialog (call it modelessDialog) with None/nullptr as parent, and displays it via show(). Produces a modeless dialog, but...:
      0_1559218533906_Screenshot from 2019-05-30 13-15-17.png
      See how the modeless dialog is behind the main window/currently displayed modal dialog? If I click on the modeless, it briefly brings it up top but then immediately brings the main window/modal dialog back on top of the modeless (this may be Linux/GNOME behaviour, I don't know). It's as though while inside an exec() something checks and brings it back on top if something else is clicked to bring that on top?? That is not what I want: I wish the main+modal to be 100% independent of the modeless, I should be able to click either to be on top as I please.

    3. On a whim, I click the X to close the modal dialog. Now the modeless dialog is indeed fully independent of the main window, and I can click either to bring up-front.
      0_1559218601667_Screenshot from 2019-05-30 13-16-21.png
      This is the behaviour I want, but cannot achieve, even when a modal dialog is currently shown with an exec().

    If anyone wants, here is about the minimal code I am using. See my comments about parent vs no parent and exec() vs show().

    import sys
    from PyQt5 import QtWidgets
    
    
    class Main(QtWidgets.QMainWindow):
        def __init__(self):
            super().__init__()
    
            self.setWindowTitle("Main")
            self.setGeometry(100, 100, 500, 500)
    
            self.btnModal = QtWidgets.QPushButton("Open Modal", self)
            self.btnModal.clicked.connect(self.openModal)
    
        def openModal(self):
            # Note: dlgModal has parent QMainWindow
            self.dlgModal = QtWidgets.QDialog(self)
            self.dlgModal.setWindowTitle("Modal Dialog")
            self.dlgModal.setFixedSize(400, 400)
    
            self.dlgModal.btnModeless = QtWidgets.QPushButton("Open Modeless", self.dlgModal)
            self.dlgModal.btnModeless.clicked.connect(self.openModeless)
    
            # Note: dlgModal is opened modal via exec()
            # If I replace `exec()` with `show()` I do not get unwanted behaviour
            # but I do want this invoking dialog to be modal
            self.dlgModal.exec()
    
        def openModeless(self):
            # Note: dlgModal has parent None
            self.dlgModeless = QtWidgets.QDialog(None)
            self.dlgModeless.setWindowTitle("Modeless Dialog")
            self.dlgModeless.setFixedSize(300, 300)
    
            # Note: dlgModeless is opened modeless via show()
            # It should be "fully independent of anything else", but it is not...?
            self.dlgModeless.show()
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
    
        main = Main()
        main.show()
    
        sys.exit(app.exec_())
    
    

    If I replace the self.dlgModal.exec() by self.dlgModal.show() I do not get the unwanted up-fronting behaviour, the modeless can go on top of it. But I do want the invoking dialog to be modal....

    SamurayHS 1 條回覆 最後回覆
    0
    • JonBJ 離線
      JonBJ 離線
      JonB
      寫於 最後由 編輯
      #8

      I didn't really get a perfect answer. An application-modeless dialog still gets blocked if you open an application-modal dialog, which is not what I want, but there it is. I do not want to change all my application's modal dialogs to be parent-window-modal to solve.

      To move on I am redesigning so that when the modeless is opened all the modals get closed now. It'll have to do, it's time for me to close this issue now....

      1 條回覆 最後回覆
      0
      • Kent-DorfmanK 離線
        Kent-DorfmanK 離線
        Kent-Dorfman
        寫於 最後由 Kent-Dorfman 編輯
        #2

        IIRC, modal dialogs always have focus, so are always on top. Also, I believe that exec() is the correct way to run a modal dialog, as the modal dialog has its own event loop.

        What you are experiencing is the expected behaviour.

        JonBJ 1 條回覆 最後回覆
        1
        • JonBJ JonB

          Qt 5.9. Tested under Linux. Target both Linux & Windows (which I cannot test). Hopefully none of this is actually relevant.

          I have a problem whereby a modeless dialog is getting put behind another dialog/window when I intend it to be 100% independent/top-level/free to be clicked to be either behind or on top, like any independent window.

          1. Main window creates QDialog (call it modalDialog) with itself (main window) as parent, and displays it via exec(). Correctly produces a modal dialog:
            0_1559218470470_Screenshot from 2019-05-30 13-12-22.png

          2. That modal dialog creates another QDialog (call it modelessDialog) with None/nullptr as parent, and displays it via show(). Produces a modeless dialog, but...:
            0_1559218533906_Screenshot from 2019-05-30 13-15-17.png
            See how the modeless dialog is behind the main window/currently displayed modal dialog? If I click on the modeless, it briefly brings it up top but then immediately brings the main window/modal dialog back on top of the modeless (this may be Linux/GNOME behaviour, I don't know). It's as though while inside an exec() something checks and brings it back on top if something else is clicked to bring that on top?? That is not what I want: I wish the main+modal to be 100% independent of the modeless, I should be able to click either to be on top as I please.

          3. On a whim, I click the X to close the modal dialog. Now the modeless dialog is indeed fully independent of the main window, and I can click either to bring up-front.
            0_1559218601667_Screenshot from 2019-05-30 13-16-21.png
            This is the behaviour I want, but cannot achieve, even when a modal dialog is currently shown with an exec().

          If anyone wants, here is about the minimal code I am using. See my comments about parent vs no parent and exec() vs show().

          import sys
          from PyQt5 import QtWidgets
          
          
          class Main(QtWidgets.QMainWindow):
              def __init__(self):
                  super().__init__()
          
                  self.setWindowTitle("Main")
                  self.setGeometry(100, 100, 500, 500)
          
                  self.btnModal = QtWidgets.QPushButton("Open Modal", self)
                  self.btnModal.clicked.connect(self.openModal)
          
              def openModal(self):
                  # Note: dlgModal has parent QMainWindow
                  self.dlgModal = QtWidgets.QDialog(self)
                  self.dlgModal.setWindowTitle("Modal Dialog")
                  self.dlgModal.setFixedSize(400, 400)
          
                  self.dlgModal.btnModeless = QtWidgets.QPushButton("Open Modeless", self.dlgModal)
                  self.dlgModal.btnModeless.clicked.connect(self.openModeless)
          
                  # Note: dlgModal is opened modal via exec()
                  # If I replace `exec()` with `show()` I do not get unwanted behaviour
                  # but I do want this invoking dialog to be modal
                  self.dlgModal.exec()
          
              def openModeless(self):
                  # Note: dlgModal has parent None
                  self.dlgModeless = QtWidgets.QDialog(None)
                  self.dlgModeless.setWindowTitle("Modeless Dialog")
                  self.dlgModeless.setFixedSize(300, 300)
          
                  # Note: dlgModeless is opened modeless via show()
                  # It should be "fully independent of anything else", but it is not...?
                  self.dlgModeless.show()
          
          
          if __name__ == '__main__':
              app = QtWidgets.QApplication(sys.argv)
          
              main = Main()
              main.show()
          
              sys.exit(app.exec_())
          
          

          If I replace the self.dlgModal.exec() by self.dlgModal.show() I do not get the unwanted up-fronting behaviour, the modeless can go on top of it. But I do want the invoking dialog to be modal....

          SamurayHS 離線
          SamurayHS 離線
          SamurayH
          寫於 最後由 編輯
          #3

          Hi @JonB,

          Try replacing self.dlgModal.exec() with self.dlgModal.open(), working perfectly on Windows 10.

          Note: " Unlike exec(), open() is asynchronous, and does not spin an additional event loop. So when using open() you can connect to the finished() signal of QDialog to be notified when the dialog is closed. " - Qt 5.12 docs

          "قال رسول الله صلى الله عليه وسلم : " أحب الناس إلى الله أنفعهم للناس

          JonBJ 2 條回覆 最後回覆
          1
          • Kent-DorfmanK Kent-Dorfman

            IIRC, modal dialogs always have focus, so are always on top. Also, I believe that exec() is the correct way to run a modal dialog, as the modal dialog has its own event loop.

            What you are experiencing is the expected behaviour.

            JonBJ 離線
            JonBJ 離線
            JonB
            寫於 最後由 JonB 編輯
            #4

            @Kent-Dorfman

            IIRC, modal dialogs always have focus, so are always on top.
            What you are experiencing is the expected behaviour.

            Hmm, you may be correct. Which may not be good for me.

            That would mean I can never make an application's modeless dialog/window be up-front whenever the app is showing a modal somewhere. Say it was a debug window --- I couldn't even do that?

            One thing: from how it behaves under Linux, and what someone said looking at it under Windows, it sounded like this is not an OS windowing system behaviour/limitation. It looks like you can temporarily click to get the modeless up-front, but something in the exec() loop sees that and brings its modal dialog back on top. So a Qt behaviour, rather than a native windowing one. What do you think?

            1 條回覆 最後回覆
            0
            • SamurayHS SamurayH

              Hi @JonB,

              Try replacing self.dlgModal.exec() with self.dlgModal.open(), working perfectly on Windows 10.

              Note: " Unlike exec(), open() is asynchronous, and does not spin an additional event loop. So when using open() you can connect to the finished() signal of QDialog to be notified when the dialog is closed. " - Qt 5.12 docs

              JonBJ 離線
              JonBJ 離線
              JonB
              寫於 最後由 JonB 編輯
              #5

              @SamurayH
              Thanks, will investigate tomorrow and see if open() is required instead of exec() to get what I expect. Also I recall some "window on top" flag, maybe that affects behaviour (though I'm not sure that wouldn't introduce its own misbehaviours). Or there might be another window/dialog flag suitable?

              What I want is: a modeless dialog which belongs to the application but is simply unaffected by what other modal dialogs happen to be currently displayed elsewhere in the app. It's an independent window/dialog sitting there letting user interact with it whenever he wants till he closes it. He may need to interact with it while a modal is displayed, e.g. to garner information from the modeless to paste into the modal, or vice versa.

              1 條回覆 最後回覆
              0
              • Kent-DorfmanK 離線
                Kent-DorfmanK 離線
                Kent-Dorfman
                寫於 最後由 編輯
                #6

                @JonB said in Modeless dialog problem:

                So a Qt behaviour, rather than a native windowing one. What do you think?

                I would agree with that assertion.

                1 條回覆 最後回覆
                1
                • SamurayHS SamurayH

                  Hi @JonB,

                  Try replacing self.dlgModal.exec() with self.dlgModal.open(), working perfectly on Windows 10.

                  Note: " Unlike exec(), open() is asynchronous, and does not spin an additional event loop. So when using open() you can connect to the finished() signal of QDialog to be notified when the dialog is closed. " - Qt 5.12 docs

                  JonBJ 離線
                  JonBJ 離線
                  JonB
                  寫於 最後由 JonB 編輯
                  #7

                  @SamurayH

                  Try replacing self.dlgModal.exec() with self.dlgModal.open(), working perfectly on Windows 10.

                  I replaced

                  self.dlgModal.exec()
                  

                  by

                  self.dlgModal.setWindowModality(QtCore.Qt.WindowModal)
                  self.dlgModal.show()
                  # or it turns out I can also still use here:
                  # self.dlgModal.exec()
                  

                  and sure enough that does behave as I wanted --- when the modeless is later opened it is quite independent of the invoking modal and I can switch between them as desired.

                  This shows the problem lies in the dlgModal.windowModality() behaviour. I then tried:

                  self.dlgModal.setWindowModality(QtCore.Qt.ApplicationModal)
                  self.dlgModal.show()
                  # or self.dlgModal.exec()
                  

                  and behaviour reverts to the undesirable. QDialog.exec() uses application modal, hence its behaviour:

                  If the dialog is application modal, users cannot interact with any other window in the same application until they close the dialog. If the dialog is window modal, only interaction with the parent window is blocked while the dialog is open. By default, the dialog is application modal.

                  So this must be the root of my issue. However, I have a problem: application has many, many modal dialogs opened via exec() (without specifying any setWindowModality()), any of which might have a button which wants to open the independent modeless dialog. I do not want to have to change the behaviour in the invoking modal dialogs. What I need is something on opening the modeless dialog which makes it a top-level, independent window, without having to alter the invoking dialogs' code, which I should not have to. But it may be that is not possible... :(

                  Can you think of anything I might try on opening the modeless which would make it independent of any application-modal dialog which might be open or become open at a later point??

                  1 條回覆 最後回覆
                  0
                  • JonBJ 離線
                    JonBJ 離線
                    JonB
                    寫於 最後由 編輯
                    #8

                    I didn't really get a perfect answer. An application-modeless dialog still gets blocked if you open an application-modal dialog, which is not what I want, but there it is. I do not want to change all my application's modal dialogs to be parent-window-modal to solve.

                    To move on I am redesigning so that when the modeless is opened all the modals get closed now. It'll have to do, it's time for me to close this issue now....

                    1 條回覆 最後回覆
                    0

                    • 登入

                    • Login or register to search.
                    • 第一個貼文
                      最後的貼文
                    0
                    • 版面
                    • 最新
                    • 標籤
                    • 熱門
                    • 使用者
                    • 群組
                    • 搜尋
                    • Get Qt Extensions
                    • Unsolved