Custom Python QDialog crash

Hi everyone !

I am trying to create a custom QDialog in Python. Whenever you add a custom signal/slot connection, the application crashes on exit.

Here is the minimal example you can reproduce the crash with, following the steps:

  • Open Slicer
  • Run the python code below:
class CustomDialog(qt.QDialog):
    def __init__(self, parent = None):
        qt.QDialog.__init__(self, parent)
        self.connect('accepted()', self.myCustomSlot)
    def myCustomSlot(self):
        print("Doesn't matter")

w = CustomDialog()
w.open()
  • Exit Slicer
    CRASH :frowning:

Has someone else encountered something like this ? I managed to reproduce it in the nightly and in an older windows build (2019-08-20 hash: 499d10b035181586489f5e3d60ff486a136a12bb).

Thanks !

P.S.: Here is an example of the call-stack after the crash:

I’m currently unable to replicate the crash using today’s Slicer nightly (28737) built by the factory machine on Windows 10.

[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input: class CustomDialog(qt.QDialog):
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input:     def __init__(self, parent = None):
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input:         qt.QDialog.__init__(self, parent)
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input:         self.connect('accepted()', self.myCustomSlot)
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input:     def myCustomSlot(self):
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input:         print("Doesn't matter")
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input: w = CustomDialog()
[DEBUG][Qt] 21.01.2020 15:37:22 [] (unknown:0) - Python console user input: w.open()
[DEBUG][Qt] 21.01.2020 15:37:34 [] (unknown:0) - Python console user input: w.accept()
[INFO][Stream] 21.01.2020 15:37:34 [] (unknown:0) - Doesn't matter
[DEBUG][Qt] 21.01.2020 15:38:17 [] (unknown:0) - Python console user input: slicer.app.repositoryRevision
[INFO][Stream] 21.01.2020 15:38:17 [] (unknown:0) - '28737'

You need to disconnect all signals and delete all widget instances before application shutdown (while the widget that you created in the above example is kept alive forever by the global Python variable).

The module widget’s cleanup method is added exactly for performing this kind of cleanup.

Following your suggestion, I realized that my mistake came from having the QDialog un-parented. Here is what I ended up doing:

class CustomDialog(qt.QDialog):
    def __init__(self, parent = None):
        qt.QDialog.__init__(self, parent)
        self.connect('accepted()', self.myCustomSlot)
    def myCustomSlot(self):
        pass

w = CustomDialog(slicer.util.mainWindow()) # Parent could be your module GUI
w.show()

No more crash, the dialog is properly deleted when the application exits, also no need to worry about the dialog life-cycle.

Thanks a lot for your help !

Parent widget deletes all child widgets in its destructor. Probably that’s why you don’t need to delete your widget manually when you set the main window as parent.