Best approach to show / hide dialogs










-1














I have encountered a theoretical question. I'm using pyqt5, but this is probably are very generalistic and framework independent question. I have a QMainwindow sitting around waiting for the user to do stuff. The user can show / hide dialogues (subclasses of QDockwidgets) as he chooses using the QMenu and the associated shortcuts (it's a checkable QAction for each individual dialogue). I have been struggling with showing / hiding the dialogues efficiently. Currently, I'm just initiating them all at start up, hiding those that I don't want to show up in the beginning. This makes triggering the dialogues easy, since I can just dialogue.show() /dialogue.hide() depending on the dialogues current visibility.
But I cannot believe that this is best practice and very efficient.



I have tried (I currently do not have my pyqt environment set up on this computer, so I had to strip down my actual code without being able to test if this runs):



from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class InfoPanel(QDockWidget):
def __init__(self, title='Tool Box'):
QDockWidget.__init__(self, title)
self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

frame = QFrame()
layout = QGridLayout()
self.canvas = QGraphicsView()
self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
layout.addWidget(self.canvas)
frame.setLayout(layout)
self.setWidget(frame)


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)
self.setDockOptions(QMainWindow.AnimatedDocks)

def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
dialogueExists = True
try: self.infoPanel
#except NameError: #does not catch the error
except:
dialogueExists = False
if dialogueExists:
print('destroy')
self.infoPanel.destroy()
else:
print('create')
self.infoPanel = InfoPanel() #init
self.infoPanel.show()

if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()


Which works the first time, but after that, it only seems to trigger the destruction of the dialogue (which, surprisingly, does not crash anything it just keeps on going).
Why is that and is there a standard way to approach the showing hiding of dialogues?



Cheers, Sacha










share|improve this question



















  • 1




    IMHO, it's usual to setup any GUI stuff (like e.g. dialogs) at program start, show/hide it as needed by user's interaction, and destroy it at program end. I cannot imagine that GUI objects consume that much memory that it's worth to create/destroy them on demand. (View data is the exception e.g. model data for big tables. I usually discard such data when resp. parts of GUI become hidden due to closing a dialog.) This is how I do it in Qt. I did this as well before in gtkmm, and as well before in OSF/Motif. (I cannot remember how I did it when I started in GDI of Win3.1, probably wrong.) ;-)
    – Scheff
    Nov 13 at 9:43











  • For a standard way, you may consult the numerous examples in Qt doc. They probably illustrate how they (the Qt developers) think it should be used.
    – Scheff
    Nov 13 at 9:50






  • 1




    @Scheff Ok, so in my case I could do that with most dialogues and hide the creation / hiding of the dialogues at program start with the splash screen. I do have some dialogues that use mvc, for which I will probably destroy the data when closing it to save on memory. I would still love to know why the try: ... except: ... approach doesn't work as I expected!?
    – Sacha Viquerat
    Nov 13 at 10:00











  • Saving the memory is only the half of the intention. I don't know how you couple the data with model and view. I'm a big fan of signal driven things. I.e. I often have signals in my data which notify about changes. UI classes just connect to these signals and update them-selves automatically. This is especially maintenance-friendly concerning multiple (different) views onto the same data. However, Qt updates are in certain cases expensive (i.e. terrible slow) especially concerning MVC widgets. Hence, I try to limit the updates to the absolute necessary amount (by clearing models of hidden UI).
    – Scheff
    Nov 13 at 10:08










  • Concerning the try: ... except: ...: Could you extend your sample to a Minimal, Complete, and Verifiable example?
    – Scheff
    Nov 13 at 10:11
















-1














I have encountered a theoretical question. I'm using pyqt5, but this is probably are very generalistic and framework independent question. I have a QMainwindow sitting around waiting for the user to do stuff. The user can show / hide dialogues (subclasses of QDockwidgets) as he chooses using the QMenu and the associated shortcuts (it's a checkable QAction for each individual dialogue). I have been struggling with showing / hiding the dialogues efficiently. Currently, I'm just initiating them all at start up, hiding those that I don't want to show up in the beginning. This makes triggering the dialogues easy, since I can just dialogue.show() /dialogue.hide() depending on the dialogues current visibility.
But I cannot believe that this is best practice and very efficient.



I have tried (I currently do not have my pyqt environment set up on this computer, so I had to strip down my actual code without being able to test if this runs):



from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class InfoPanel(QDockWidget):
def __init__(self, title='Tool Box'):
QDockWidget.__init__(self, title)
self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

frame = QFrame()
layout = QGridLayout()
self.canvas = QGraphicsView()
self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
layout.addWidget(self.canvas)
frame.setLayout(layout)
self.setWidget(frame)


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)
self.setDockOptions(QMainWindow.AnimatedDocks)

def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
dialogueExists = True
try: self.infoPanel
#except NameError: #does not catch the error
except:
dialogueExists = False
if dialogueExists:
print('destroy')
self.infoPanel.destroy()
else:
print('create')
self.infoPanel = InfoPanel() #init
self.infoPanel.show()

if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()


Which works the first time, but after that, it only seems to trigger the destruction of the dialogue (which, surprisingly, does not crash anything it just keeps on going).
Why is that and is there a standard way to approach the showing hiding of dialogues?



Cheers, Sacha










share|improve this question



















  • 1




    IMHO, it's usual to setup any GUI stuff (like e.g. dialogs) at program start, show/hide it as needed by user's interaction, and destroy it at program end. I cannot imagine that GUI objects consume that much memory that it's worth to create/destroy them on demand. (View data is the exception e.g. model data for big tables. I usually discard such data when resp. parts of GUI become hidden due to closing a dialog.) This is how I do it in Qt. I did this as well before in gtkmm, and as well before in OSF/Motif. (I cannot remember how I did it when I started in GDI of Win3.1, probably wrong.) ;-)
    – Scheff
    Nov 13 at 9:43











  • For a standard way, you may consult the numerous examples in Qt doc. They probably illustrate how they (the Qt developers) think it should be used.
    – Scheff
    Nov 13 at 9:50






  • 1




    @Scheff Ok, so in my case I could do that with most dialogues and hide the creation / hiding of the dialogues at program start with the splash screen. I do have some dialogues that use mvc, for which I will probably destroy the data when closing it to save on memory. I would still love to know why the try: ... except: ... approach doesn't work as I expected!?
    – Sacha Viquerat
    Nov 13 at 10:00











  • Saving the memory is only the half of the intention. I don't know how you couple the data with model and view. I'm a big fan of signal driven things. I.e. I often have signals in my data which notify about changes. UI classes just connect to these signals and update them-selves automatically. This is especially maintenance-friendly concerning multiple (different) views onto the same data. However, Qt updates are in certain cases expensive (i.e. terrible slow) especially concerning MVC widgets. Hence, I try to limit the updates to the absolute necessary amount (by clearing models of hidden UI).
    – Scheff
    Nov 13 at 10:08










  • Concerning the try: ... except: ...: Could you extend your sample to a Minimal, Complete, and Verifiable example?
    – Scheff
    Nov 13 at 10:11














-1












-1








-1







I have encountered a theoretical question. I'm using pyqt5, but this is probably are very generalistic and framework independent question. I have a QMainwindow sitting around waiting for the user to do stuff. The user can show / hide dialogues (subclasses of QDockwidgets) as he chooses using the QMenu and the associated shortcuts (it's a checkable QAction for each individual dialogue). I have been struggling with showing / hiding the dialogues efficiently. Currently, I'm just initiating them all at start up, hiding those that I don't want to show up in the beginning. This makes triggering the dialogues easy, since I can just dialogue.show() /dialogue.hide() depending on the dialogues current visibility.
But I cannot believe that this is best practice and very efficient.



I have tried (I currently do not have my pyqt environment set up on this computer, so I had to strip down my actual code without being able to test if this runs):



from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class InfoPanel(QDockWidget):
def __init__(self, title='Tool Box'):
QDockWidget.__init__(self, title)
self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

frame = QFrame()
layout = QGridLayout()
self.canvas = QGraphicsView()
self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
layout.addWidget(self.canvas)
frame.setLayout(layout)
self.setWidget(frame)


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)
self.setDockOptions(QMainWindow.AnimatedDocks)

def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
dialogueExists = True
try: self.infoPanel
#except NameError: #does not catch the error
except:
dialogueExists = False
if dialogueExists:
print('destroy')
self.infoPanel.destroy()
else:
print('create')
self.infoPanel = InfoPanel() #init
self.infoPanel.show()

if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()


Which works the first time, but after that, it only seems to trigger the destruction of the dialogue (which, surprisingly, does not crash anything it just keeps on going).
Why is that and is there a standard way to approach the showing hiding of dialogues?



Cheers, Sacha










share|improve this question















I have encountered a theoretical question. I'm using pyqt5, but this is probably are very generalistic and framework independent question. I have a QMainwindow sitting around waiting for the user to do stuff. The user can show / hide dialogues (subclasses of QDockwidgets) as he chooses using the QMenu and the associated shortcuts (it's a checkable QAction for each individual dialogue). I have been struggling with showing / hiding the dialogues efficiently. Currently, I'm just initiating them all at start up, hiding those that I don't want to show up in the beginning. This makes triggering the dialogues easy, since I can just dialogue.show() /dialogue.hide() depending on the dialogues current visibility.
But I cannot believe that this is best practice and very efficient.



I have tried (I currently do not have my pyqt environment set up on this computer, so I had to strip down my actual code without being able to test if this runs):



from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class InfoPanel(QDockWidget):
def __init__(self, title='Tool Box'):
QDockWidget.__init__(self, title)
self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

frame = QFrame()
layout = QGridLayout()
self.canvas = QGraphicsView()
self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
layout.addWidget(self.canvas)
frame.setLayout(layout)
self.setWidget(frame)


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)
self.setDockOptions(QMainWindow.AnimatedDocks)

def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
dialogueExists = True
try: self.infoPanel
#except NameError: #does not catch the error
except:
dialogueExists = False
if dialogueExists:
print('destroy')
self.infoPanel.destroy()
else:
print('create')
self.infoPanel = InfoPanel() #init
self.infoPanel.show()

if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()


Which works the first time, but after that, it only seems to trigger the destruction of the dialogue (which, surprisingly, does not crash anything it just keeps on going).
Why is that and is there a standard way to approach the showing hiding of dialogues?



Cheers, Sacha







qt user-interface pyqt5






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 at 11:17

























asked Nov 12 at 11:11









Sacha Viquerat

7019




7019







  • 1




    IMHO, it's usual to setup any GUI stuff (like e.g. dialogs) at program start, show/hide it as needed by user's interaction, and destroy it at program end. I cannot imagine that GUI objects consume that much memory that it's worth to create/destroy them on demand. (View data is the exception e.g. model data for big tables. I usually discard such data when resp. parts of GUI become hidden due to closing a dialog.) This is how I do it in Qt. I did this as well before in gtkmm, and as well before in OSF/Motif. (I cannot remember how I did it when I started in GDI of Win3.1, probably wrong.) ;-)
    – Scheff
    Nov 13 at 9:43











  • For a standard way, you may consult the numerous examples in Qt doc. They probably illustrate how they (the Qt developers) think it should be used.
    – Scheff
    Nov 13 at 9:50






  • 1




    @Scheff Ok, so in my case I could do that with most dialogues and hide the creation / hiding of the dialogues at program start with the splash screen. I do have some dialogues that use mvc, for which I will probably destroy the data when closing it to save on memory. I would still love to know why the try: ... except: ... approach doesn't work as I expected!?
    – Sacha Viquerat
    Nov 13 at 10:00











  • Saving the memory is only the half of the intention. I don't know how you couple the data with model and view. I'm a big fan of signal driven things. I.e. I often have signals in my data which notify about changes. UI classes just connect to these signals and update them-selves automatically. This is especially maintenance-friendly concerning multiple (different) views onto the same data. However, Qt updates are in certain cases expensive (i.e. terrible slow) especially concerning MVC widgets. Hence, I try to limit the updates to the absolute necessary amount (by clearing models of hidden UI).
    – Scheff
    Nov 13 at 10:08










  • Concerning the try: ... except: ...: Could you extend your sample to a Minimal, Complete, and Verifiable example?
    – Scheff
    Nov 13 at 10:11













  • 1




    IMHO, it's usual to setup any GUI stuff (like e.g. dialogs) at program start, show/hide it as needed by user's interaction, and destroy it at program end. I cannot imagine that GUI objects consume that much memory that it's worth to create/destroy them on demand. (View data is the exception e.g. model data for big tables. I usually discard such data when resp. parts of GUI become hidden due to closing a dialog.) This is how I do it in Qt. I did this as well before in gtkmm, and as well before in OSF/Motif. (I cannot remember how I did it when I started in GDI of Win3.1, probably wrong.) ;-)
    – Scheff
    Nov 13 at 9:43











  • For a standard way, you may consult the numerous examples in Qt doc. They probably illustrate how they (the Qt developers) think it should be used.
    – Scheff
    Nov 13 at 9:50






  • 1




    @Scheff Ok, so in my case I could do that with most dialogues and hide the creation / hiding of the dialogues at program start with the splash screen. I do have some dialogues that use mvc, for which I will probably destroy the data when closing it to save on memory. I would still love to know why the try: ... except: ... approach doesn't work as I expected!?
    – Sacha Viquerat
    Nov 13 at 10:00











  • Saving the memory is only the half of the intention. I don't know how you couple the data with model and view. I'm a big fan of signal driven things. I.e. I often have signals in my data which notify about changes. UI classes just connect to these signals and update them-selves automatically. This is especially maintenance-friendly concerning multiple (different) views onto the same data. However, Qt updates are in certain cases expensive (i.e. terrible slow) especially concerning MVC widgets. Hence, I try to limit the updates to the absolute necessary amount (by clearing models of hidden UI).
    – Scheff
    Nov 13 at 10:08










  • Concerning the try: ... except: ...: Could you extend your sample to a Minimal, Complete, and Verifiable example?
    – Scheff
    Nov 13 at 10:11








1




1




IMHO, it's usual to setup any GUI stuff (like e.g. dialogs) at program start, show/hide it as needed by user's interaction, and destroy it at program end. I cannot imagine that GUI objects consume that much memory that it's worth to create/destroy them on demand. (View data is the exception e.g. model data for big tables. I usually discard such data when resp. parts of GUI become hidden due to closing a dialog.) This is how I do it in Qt. I did this as well before in gtkmm, and as well before in OSF/Motif. (I cannot remember how I did it when I started in GDI of Win3.1, probably wrong.) ;-)
– Scheff
Nov 13 at 9:43





IMHO, it's usual to setup any GUI stuff (like e.g. dialogs) at program start, show/hide it as needed by user's interaction, and destroy it at program end. I cannot imagine that GUI objects consume that much memory that it's worth to create/destroy them on demand. (View data is the exception e.g. model data for big tables. I usually discard such data when resp. parts of GUI become hidden due to closing a dialog.) This is how I do it in Qt. I did this as well before in gtkmm, and as well before in OSF/Motif. (I cannot remember how I did it when I started in GDI of Win3.1, probably wrong.) ;-)
– Scheff
Nov 13 at 9:43













For a standard way, you may consult the numerous examples in Qt doc. They probably illustrate how they (the Qt developers) think it should be used.
– Scheff
Nov 13 at 9:50




For a standard way, you may consult the numerous examples in Qt doc. They probably illustrate how they (the Qt developers) think it should be used.
– Scheff
Nov 13 at 9:50




1




1




@Scheff Ok, so in my case I could do that with most dialogues and hide the creation / hiding of the dialogues at program start with the splash screen. I do have some dialogues that use mvc, for which I will probably destroy the data when closing it to save on memory. I would still love to know why the try: ... except: ... approach doesn't work as I expected!?
– Sacha Viquerat
Nov 13 at 10:00





@Scheff Ok, so in my case I could do that with most dialogues and hide the creation / hiding of the dialogues at program start with the splash screen. I do have some dialogues that use mvc, for which I will probably destroy the data when closing it to save on memory. I would still love to know why the try: ... except: ... approach doesn't work as I expected!?
– Sacha Viquerat
Nov 13 at 10:00













Saving the memory is only the half of the intention. I don't know how you couple the data with model and view. I'm a big fan of signal driven things. I.e. I often have signals in my data which notify about changes. UI classes just connect to these signals and update them-selves automatically. This is especially maintenance-friendly concerning multiple (different) views onto the same data. However, Qt updates are in certain cases expensive (i.e. terrible slow) especially concerning MVC widgets. Hence, I try to limit the updates to the absolute necessary amount (by clearing models of hidden UI).
– Scheff
Nov 13 at 10:08




Saving the memory is only the half of the intention. I don't know how you couple the data with model and view. I'm a big fan of signal driven things. I.e. I often have signals in my data which notify about changes. UI classes just connect to these signals and update them-selves automatically. This is especially maintenance-friendly concerning multiple (different) views onto the same data. However, Qt updates are in certain cases expensive (i.e. terrible slow) especially concerning MVC widgets. Hence, I try to limit the updates to the absolute necessary amount (by clearing models of hidden UI).
– Scheff
Nov 13 at 10:08












Concerning the try: ... except: ...: Could you extend your sample to a Minimal, Complete, and Verifiable example?
– Scheff
Nov 13 at 10:11





Concerning the try: ... except: ...: Could you extend your sample to a Minimal, Complete, and Verifiable example?
– Scheff
Nov 13 at 10:11













2 Answers
2






active

oldest

votes


















0














I took the exposed MCVE of OP and tried to make it running in my cygwin64 on Windows 10.



At first I had to apply little fixes. (OP stated that he was not able to test it at the time of publishing.)



First, I inserted a “hut” at first line for convenient start in bash:



#!/usr/bin/python3


Second, the self.viewMenu didn't appear. Hence, I inserted a line after



 self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)


to add the viewMenu to main menu bar:



 self.menuBar().addMenu(self.viewMenu)


which fixed it.



Third, when clicking the menu item I got:



Traceback (most recent call last):
File "./testQDockPanelShowHide.py", line 27, in <lambda>
self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
File "./testQDockPanelShowHide.py", line 45, in showPanel
self.infoPanel = InfoPanel() #init
File "./testQDockPanelShowHide.py", line 17, in __init__
self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
NameError: name 'QtGui' is not defined
Aborted (core dumped)


I must admit that my Python knowledge is very limited. (I'm the guy who writes the Python bindings in C++ for the colleagues. So, my colleagues are the actual experts. At most, I play a little bit in Python when I test whether new implemented bindings do what's expected.) However, I modified



 self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))


to:



 self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))


which fixed this issue.



After this, I got the behavior described by OP and did a closer look where I (and OP) suspected the error:



 def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
dialogueExists = True
try: self.infoPanel
#except NameError: #does not catch the error
except:
dialogueExists = False
if dialogueExists:
print('destroy')
self.infoPanel.destroy()
else:
print('create')
self.infoPanel = InfoPanel() #init
self.infoPanel.show()


I strongly believe that try: self.infoPanel doesn't do what OP thinks it would.



It tries to access self.infoPanel which isn't existing until the first call of this method. (Please, be aware, the member variable self.infoPanel isn't existing.) So, the except: branch is executed and sets dialogueExists = False which a few lines later causes self.infoPanel = InfoPanel() #init. Now, the member variable self.infoPanel is existing, and the try: self.infoPanel will never fail again until destruction of this MainWindow.



Out of curiosity, I had a look at QWidget.destroy() (to be sure not to tell something wrong):




QWidget.destroy (self, bool destroyWindow = True, bool destroySubWindows = True)



Frees up window system resources. Destroys the widget window if destroyWindow is true.



destroy() calls itself recursively for all the child widgets, passing destroySubWindows for the destroyWindow parameter. To have more control over destruction of subwidgets, destroy subwidgets selectively first.



This function is usually called from the QWidget destructor.




It definitely doesn't destroy the member variable self.infoPanel.



After having understood this, a fix was easy and obvious:



 def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
try: self.infoPanel
#except NameError: #does not catch the error
except:
print('create')
self.infoPanel = InfoPanel() #init
if self.infoPanel.isVisible():
self.infoPanel.hide()
else:
self.infoPanel.show()


Btw. I replaced destroy() by hide() which makes a re-creation of the InfoPanel() obsolete.



I tested this by toggling the menu item multiple times – it works as expected now (at least, it looks like).



The complete sample finally:



#!/usr/bin/python3

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class InfoPanel(QDockWidget):
def __init__(self, title='Tool Box'):
QDockWidget.__init__(self, title)
self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

frame = QFrame()
layout = QGridLayout()
self.canvas = QGraphicsView()
# self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
layout.addWidget(self.canvas)
frame.setLayout(layout)
self.setWidget(frame)


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)
self.menuBar().addMenu(self.viewMenu)
self.setDockOptions(QMainWindow.AnimatedDocks)

def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
if i == 0: #infopanel
try: self.infoPanel
#except NameError: #does not catch the error
except:
print('create')
self.infoPanel = InfoPanel() #init
if self.infoPanel.isVisible():
self.infoPanel.hide()
else:
self.infoPanel.show()

if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()


Snapshot of MCVE






share|improve this answer




















  • Thanks a lot. I will check this when I get home!
    – Sacha Viquerat
    Nov 13 at 12:43


















0














After taking a break from coding the solution to my problem was very obvious. Going back to my original code (which did not produce the expected output of creating / destroying the dialogue self.infoPanel on demand):



dialogueExists = True
try: self.infoPanel
#except NameError: #does not catch the error
except:
dialogueExists = False
if dialogueExists:
print('destroy')
self.infoPanel.destroy()
else:
print('create')
self.infoPanel = InfoPanel() #init
self.infoPanel.show()


My main problem was that I confused two separate things. Qt destroyed the widget contained in the object self.infoPanel when I called self.infoPanel.destroy(). But that doesn't mean the object self.infoPanel does not exist (that's exactly what I use try: ... for, to see if the object exists). The simple and obvious way to create and destroy dialogues on demand obviously involves deleting the object from the environment (del self.infoPanel).
The working code is:



dialogueExists = True
try:
self.infoPanel.destroy() #not sure this is needed, but I guess it doesn't hurt
del self.infoPanel #this is the deletion of the actual object
except:
dialogueExists = False
if not dialogueExists :
self.infoPanel = InfoPanel()


Cheers and many thanks for the helpful advice on deciding whether to show / hide dialogues or to create / destroy them!






share|improve this answer




















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53260922%2fbest-approach-to-show-hide-dialogs%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    I took the exposed MCVE of OP and tried to make it running in my cygwin64 on Windows 10.



    At first I had to apply little fixes. (OP stated that he was not able to test it at the time of publishing.)



    First, I inserted a “hut” at first line for convenient start in bash:



    #!/usr/bin/python3


    Second, the self.viewMenu didn't appear. Hence, I inserted a line after



     self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)


    to add the viewMenu to main menu bar:



     self.menuBar().addMenu(self.viewMenu)


    which fixed it.



    Third, when clicking the menu item I got:



    Traceback (most recent call last):
    File "./testQDockPanelShowHide.py", line 27, in <lambda>
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    File "./testQDockPanelShowHide.py", line 45, in showPanel
    self.infoPanel = InfoPanel() #init
    File "./testQDockPanelShowHide.py", line 17, in __init__
    self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    NameError: name 'QtGui' is not defined
    Aborted (core dumped)


    I must admit that my Python knowledge is very limited. (I'm the guy who writes the Python bindings in C++ for the colleagues. So, my colleagues are the actual experts. At most, I play a little bit in Python when I test whether new implemented bindings do what's expected.) However, I modified



     self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))


    to:



     self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))


    which fixed this issue.



    After this, I got the behavior described by OP and did a closer look where I (and OP) suspected the error:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    dialogueExists = True
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    dialogueExists = False
    if dialogueExists:
    print('destroy')
    self.infoPanel.destroy()
    else:
    print('create')
    self.infoPanel = InfoPanel() #init
    self.infoPanel.show()


    I strongly believe that try: self.infoPanel doesn't do what OP thinks it would.



    It tries to access self.infoPanel which isn't existing until the first call of this method. (Please, be aware, the member variable self.infoPanel isn't existing.) So, the except: branch is executed and sets dialogueExists = False which a few lines later causes self.infoPanel = InfoPanel() #init. Now, the member variable self.infoPanel is existing, and the try: self.infoPanel will never fail again until destruction of this MainWindow.



    Out of curiosity, I had a look at QWidget.destroy() (to be sure not to tell something wrong):




    QWidget.destroy (self, bool destroyWindow = True, bool destroySubWindows = True)



    Frees up window system resources. Destroys the widget window if destroyWindow is true.



    destroy() calls itself recursively for all the child widgets, passing destroySubWindows for the destroyWindow parameter. To have more control over destruction of subwidgets, destroy subwidgets selectively first.



    This function is usually called from the QWidget destructor.




    It definitely doesn't destroy the member variable self.infoPanel.



    After having understood this, a fix was easy and obvious:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()


    Btw. I replaced destroy() by hide() which makes a re-creation of the InfoPanel() obsolete.



    I tested this by toggling the menu item multiple times – it works as expected now (at least, it looks like).



    The complete sample finally:



    #!/usr/bin/python3

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *


    class InfoPanel(QDockWidget):
    def __init__(self, title='Tool Box'):
    QDockWidget.__init__(self, title)
    self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
    self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

    frame = QFrame()
    layout = QGridLayout()
    self.canvas = QGraphicsView()
    # self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
    layout.addWidget(self.canvas)
    frame.setLayout(layout)
    self.setWidget(frame)


    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()
    self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)
    self.menuBar().addMenu(self.viewMenu)
    self.setDockOptions(QMainWindow.AnimatedDocks)

    def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()

    if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()


    Snapshot of MCVE






    share|improve this answer




















    • Thanks a lot. I will check this when I get home!
      – Sacha Viquerat
      Nov 13 at 12:43















    0














    I took the exposed MCVE of OP and tried to make it running in my cygwin64 on Windows 10.



    At first I had to apply little fixes. (OP stated that he was not able to test it at the time of publishing.)



    First, I inserted a “hut” at first line for convenient start in bash:



    #!/usr/bin/python3


    Second, the self.viewMenu didn't appear. Hence, I inserted a line after



     self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)


    to add the viewMenu to main menu bar:



     self.menuBar().addMenu(self.viewMenu)


    which fixed it.



    Third, when clicking the menu item I got:



    Traceback (most recent call last):
    File "./testQDockPanelShowHide.py", line 27, in <lambda>
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    File "./testQDockPanelShowHide.py", line 45, in showPanel
    self.infoPanel = InfoPanel() #init
    File "./testQDockPanelShowHide.py", line 17, in __init__
    self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    NameError: name 'QtGui' is not defined
    Aborted (core dumped)


    I must admit that my Python knowledge is very limited. (I'm the guy who writes the Python bindings in C++ for the colleagues. So, my colleagues are the actual experts. At most, I play a little bit in Python when I test whether new implemented bindings do what's expected.) However, I modified



     self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))


    to:



     self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))


    which fixed this issue.



    After this, I got the behavior described by OP and did a closer look where I (and OP) suspected the error:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    dialogueExists = True
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    dialogueExists = False
    if dialogueExists:
    print('destroy')
    self.infoPanel.destroy()
    else:
    print('create')
    self.infoPanel = InfoPanel() #init
    self.infoPanel.show()


    I strongly believe that try: self.infoPanel doesn't do what OP thinks it would.



    It tries to access self.infoPanel which isn't existing until the first call of this method. (Please, be aware, the member variable self.infoPanel isn't existing.) So, the except: branch is executed and sets dialogueExists = False which a few lines later causes self.infoPanel = InfoPanel() #init. Now, the member variable self.infoPanel is existing, and the try: self.infoPanel will never fail again until destruction of this MainWindow.



    Out of curiosity, I had a look at QWidget.destroy() (to be sure not to tell something wrong):




    QWidget.destroy (self, bool destroyWindow = True, bool destroySubWindows = True)



    Frees up window system resources. Destroys the widget window if destroyWindow is true.



    destroy() calls itself recursively for all the child widgets, passing destroySubWindows for the destroyWindow parameter. To have more control over destruction of subwidgets, destroy subwidgets selectively first.



    This function is usually called from the QWidget destructor.




    It definitely doesn't destroy the member variable self.infoPanel.



    After having understood this, a fix was easy and obvious:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()


    Btw. I replaced destroy() by hide() which makes a re-creation of the InfoPanel() obsolete.



    I tested this by toggling the menu item multiple times – it works as expected now (at least, it looks like).



    The complete sample finally:



    #!/usr/bin/python3

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *


    class InfoPanel(QDockWidget):
    def __init__(self, title='Tool Box'):
    QDockWidget.__init__(self, title)
    self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
    self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

    frame = QFrame()
    layout = QGridLayout()
    self.canvas = QGraphicsView()
    # self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
    layout.addWidget(self.canvas)
    frame.setLayout(layout)
    self.setWidget(frame)


    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()
    self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)
    self.menuBar().addMenu(self.viewMenu)
    self.setDockOptions(QMainWindow.AnimatedDocks)

    def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()

    if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()


    Snapshot of MCVE






    share|improve this answer




















    • Thanks a lot. I will check this when I get home!
      – Sacha Viquerat
      Nov 13 at 12:43













    0












    0








    0






    I took the exposed MCVE of OP and tried to make it running in my cygwin64 on Windows 10.



    At first I had to apply little fixes. (OP stated that he was not able to test it at the time of publishing.)



    First, I inserted a “hut” at first line for convenient start in bash:



    #!/usr/bin/python3


    Second, the self.viewMenu didn't appear. Hence, I inserted a line after



     self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)


    to add the viewMenu to main menu bar:



     self.menuBar().addMenu(self.viewMenu)


    which fixed it.



    Third, when clicking the menu item I got:



    Traceback (most recent call last):
    File "./testQDockPanelShowHide.py", line 27, in <lambda>
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    File "./testQDockPanelShowHide.py", line 45, in showPanel
    self.infoPanel = InfoPanel() #init
    File "./testQDockPanelShowHide.py", line 17, in __init__
    self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    NameError: name 'QtGui' is not defined
    Aborted (core dumped)


    I must admit that my Python knowledge is very limited. (I'm the guy who writes the Python bindings in C++ for the colleagues. So, my colleagues are the actual experts. At most, I play a little bit in Python when I test whether new implemented bindings do what's expected.) However, I modified



     self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))


    to:



     self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))


    which fixed this issue.



    After this, I got the behavior described by OP and did a closer look where I (and OP) suspected the error:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    dialogueExists = True
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    dialogueExists = False
    if dialogueExists:
    print('destroy')
    self.infoPanel.destroy()
    else:
    print('create')
    self.infoPanel = InfoPanel() #init
    self.infoPanel.show()


    I strongly believe that try: self.infoPanel doesn't do what OP thinks it would.



    It tries to access self.infoPanel which isn't existing until the first call of this method. (Please, be aware, the member variable self.infoPanel isn't existing.) So, the except: branch is executed and sets dialogueExists = False which a few lines later causes self.infoPanel = InfoPanel() #init. Now, the member variable self.infoPanel is existing, and the try: self.infoPanel will never fail again until destruction of this MainWindow.



    Out of curiosity, I had a look at QWidget.destroy() (to be sure not to tell something wrong):




    QWidget.destroy (self, bool destroyWindow = True, bool destroySubWindows = True)



    Frees up window system resources. Destroys the widget window if destroyWindow is true.



    destroy() calls itself recursively for all the child widgets, passing destroySubWindows for the destroyWindow parameter. To have more control over destruction of subwidgets, destroy subwidgets selectively first.



    This function is usually called from the QWidget destructor.




    It definitely doesn't destroy the member variable self.infoPanel.



    After having understood this, a fix was easy and obvious:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()


    Btw. I replaced destroy() by hide() which makes a re-creation of the InfoPanel() obsolete.



    I tested this by toggling the menu item multiple times – it works as expected now (at least, it looks like).



    The complete sample finally:



    #!/usr/bin/python3

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *


    class InfoPanel(QDockWidget):
    def __init__(self, title='Tool Box'):
    QDockWidget.__init__(self, title)
    self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
    self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

    frame = QFrame()
    layout = QGridLayout()
    self.canvas = QGraphicsView()
    # self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
    layout.addWidget(self.canvas)
    frame.setLayout(layout)
    self.setWidget(frame)


    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()
    self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)
    self.menuBar().addMenu(self.viewMenu)
    self.setDockOptions(QMainWindow.AnimatedDocks)

    def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()

    if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()


    Snapshot of MCVE






    share|improve this answer












    I took the exposed MCVE of OP and tried to make it running in my cygwin64 on Windows 10.



    At first I had to apply little fixes. (OP stated that he was not able to test it at the time of publishing.)



    First, I inserted a “hut” at first line for convenient start in bash:



    #!/usr/bin/python3


    Second, the self.viewMenu didn't appear. Hence, I inserted a line after



     self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)


    to add the viewMenu to main menu bar:



     self.menuBar().addMenu(self.viewMenu)


    which fixed it.



    Third, when clicking the menu item I got:



    Traceback (most recent call last):
    File "./testQDockPanelShowHide.py", line 27, in <lambda>
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    File "./testQDockPanelShowHide.py", line 45, in showPanel
    self.infoPanel = InfoPanel() #init
    File "./testQDockPanelShowHide.py", line 17, in __init__
    self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    NameError: name 'QtGui' is not defined
    Aborted (core dumped)


    I must admit that my Python knowledge is very limited. (I'm the guy who writes the Python bindings in C++ for the colleagues. So, my colleagues are the actual experts. At most, I play a little bit in Python when I test whether new implemented bindings do what's expected.) However, I modified



     self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))


    to:



     self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))


    which fixed this issue.



    After this, I got the behavior described by OP and did a closer look where I (and OP) suspected the error:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    dialogueExists = True
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    dialogueExists = False
    if dialogueExists:
    print('destroy')
    self.infoPanel.destroy()
    else:
    print('create')
    self.infoPanel = InfoPanel() #init
    self.infoPanel.show()


    I strongly believe that try: self.infoPanel doesn't do what OP thinks it would.



    It tries to access self.infoPanel which isn't existing until the first call of this method. (Please, be aware, the member variable self.infoPanel isn't existing.) So, the except: branch is executed and sets dialogueExists = False which a few lines later causes self.infoPanel = InfoPanel() #init. Now, the member variable self.infoPanel is existing, and the try: self.infoPanel will never fail again until destruction of this MainWindow.



    Out of curiosity, I had a look at QWidget.destroy() (to be sure not to tell something wrong):




    QWidget.destroy (self, bool destroyWindow = True, bool destroySubWindows = True)



    Frees up window system resources. Destroys the widget window if destroyWindow is true.



    destroy() calls itself recursively for all the child widgets, passing destroySubWindows for the destroyWindow parameter. To have more control over destruction of subwidgets, destroy subwidgets selectively first.



    This function is usually called from the QWidget destructor.




    It definitely doesn't destroy the member variable self.infoPanel.



    After having understood this, a fix was easy and obvious:



     def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()


    Btw. I replaced destroy() by hide() which makes a re-creation of the InfoPanel() obsolete.



    I tested this by toggling the menu item multiple times – it works as expected now (at least, it looks like).



    The complete sample finally:



    #!/usr/bin/python3

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *


    class InfoPanel(QDockWidget):
    def __init__(self, title='Tool Box'):
    QDockWidget.__init__(self, title)
    self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable)
    self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

    frame = QFrame()
    layout = QGridLayout()
    self.canvas = QGraphicsView()
    # self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
    self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
    layout.addWidget(self.canvas)
    frame.setLayout(layout)
    self.setWidget(frame)


    class MainWindow(QMainWindow):
    def __init__(self):
    super().__init__()
    self.showpanelAct = QAction("&Show Panel", self, enabled=True,checkable=True, shortcut="F10")
    self.showpanelAct.triggered.connect(lambda: self.showPanel(0))
    self.viewMenu = QMenu("&View", self)
    self.viewMenu.addAction(self.showpanelAct)
    self.menuBar().addMenu(self.viewMenu)
    self.setDockOptions(QMainWindow.AnimatedDocks)

    def showPanel(self,i:int = 0): # this is not so smart - should construct and deconstuct to save memory!?
    if i == 0: #infopanel
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    print('create')
    self.infoPanel = InfoPanel() #init
    if self.infoPanel.isVisible():
    self.infoPanel.hide()
    else:
    self.infoPanel.show()

    if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()


    Snapshot of MCVE







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 13 at 12:27









    Scheff

    7,48521125




    7,48521125











    • Thanks a lot. I will check this when I get home!
      – Sacha Viquerat
      Nov 13 at 12:43
















    • Thanks a lot. I will check this when I get home!
      – Sacha Viquerat
      Nov 13 at 12:43















    Thanks a lot. I will check this when I get home!
    – Sacha Viquerat
    Nov 13 at 12:43




    Thanks a lot. I will check this when I get home!
    – Sacha Viquerat
    Nov 13 at 12:43













    0














    After taking a break from coding the solution to my problem was very obvious. Going back to my original code (which did not produce the expected output of creating / destroying the dialogue self.infoPanel on demand):



    dialogueExists = True
    try: self.infoPanel
    #except NameError: #does not catch the error
    except:
    dialogueExists = False
    if dialogueExists:
    print('destroy')
    self.infoPanel.destroy()
    else:
    print('create')
    self.infoPanel = InfoPanel() #init
    self.infoPanel.show()


    My main problem was that I confused two separate things. Qt destroyed the widget contained in the object self.infoPanel when I called self.infoPanel.destroy(). But that doesn't mean the object self.infoPanel does not exist (that's exactly what I use try: ... for, to see if the object exists). The simple and obvious way to create and destroy dialogues on demand obviously involves deleting the object from the environment (del self.infoPanel).
    The working code is:



    dialogueExists = True
    try:
    self.infoPanel.destroy() #not sure this is needed, but I guess it doesn't hurt
    del self.infoPanel #this is the deletion of the actual object
    except:
    dialogueExists = False
    if not dialogueExists :
    self.infoPanel = InfoPanel()


    Cheers and many thanks for the helpful advice on deciding whether to show / hide dialogues or to create / destroy them!






    share|improve this answer

























      0














      After taking a break from coding the solution to my problem was very obvious. Going back to my original code (which did not produce the expected output of creating / destroying the dialogue self.infoPanel on demand):



      dialogueExists = True
      try: self.infoPanel
      #except NameError: #does not catch the error
      except:
      dialogueExists = False
      if dialogueExists:
      print('destroy')
      self.infoPanel.destroy()
      else:
      print('create')
      self.infoPanel = InfoPanel() #init
      self.infoPanel.show()


      My main problem was that I confused two separate things. Qt destroyed the widget contained in the object self.infoPanel when I called self.infoPanel.destroy(). But that doesn't mean the object self.infoPanel does not exist (that's exactly what I use try: ... for, to see if the object exists). The simple and obvious way to create and destroy dialogues on demand obviously involves deleting the object from the environment (del self.infoPanel).
      The working code is:



      dialogueExists = True
      try:
      self.infoPanel.destroy() #not sure this is needed, but I guess it doesn't hurt
      del self.infoPanel #this is the deletion of the actual object
      except:
      dialogueExists = False
      if not dialogueExists :
      self.infoPanel = InfoPanel()


      Cheers and many thanks for the helpful advice on deciding whether to show / hide dialogues or to create / destroy them!






      share|improve this answer























        0












        0








        0






        After taking a break from coding the solution to my problem was very obvious. Going back to my original code (which did not produce the expected output of creating / destroying the dialogue self.infoPanel on demand):



        dialogueExists = True
        try: self.infoPanel
        #except NameError: #does not catch the error
        except:
        dialogueExists = False
        if dialogueExists:
        print('destroy')
        self.infoPanel.destroy()
        else:
        print('create')
        self.infoPanel = InfoPanel() #init
        self.infoPanel.show()


        My main problem was that I confused two separate things. Qt destroyed the widget contained in the object self.infoPanel when I called self.infoPanel.destroy(). But that doesn't mean the object self.infoPanel does not exist (that's exactly what I use try: ... for, to see if the object exists). The simple and obvious way to create and destroy dialogues on demand obviously involves deleting the object from the environment (del self.infoPanel).
        The working code is:



        dialogueExists = True
        try:
        self.infoPanel.destroy() #not sure this is needed, but I guess it doesn't hurt
        del self.infoPanel #this is the deletion of the actual object
        except:
        dialogueExists = False
        if not dialogueExists :
        self.infoPanel = InfoPanel()


        Cheers and many thanks for the helpful advice on deciding whether to show / hide dialogues or to create / destroy them!






        share|improve this answer












        After taking a break from coding the solution to my problem was very obvious. Going back to my original code (which did not produce the expected output of creating / destroying the dialogue self.infoPanel on demand):



        dialogueExists = True
        try: self.infoPanel
        #except NameError: #does not catch the error
        except:
        dialogueExists = False
        if dialogueExists:
        print('destroy')
        self.infoPanel.destroy()
        else:
        print('create')
        self.infoPanel = InfoPanel() #init
        self.infoPanel.show()


        My main problem was that I confused two separate things. Qt destroyed the widget contained in the object self.infoPanel when I called self.infoPanel.destroy(). But that doesn't mean the object self.infoPanel does not exist (that's exactly what I use try: ... for, to see if the object exists). The simple and obvious way to create and destroy dialogues on demand obviously involves deleting the object from the environment (del self.infoPanel).
        The working code is:



        dialogueExists = True
        try:
        self.infoPanel.destroy() #not sure this is needed, but I guess it doesn't hurt
        del self.infoPanel #this is the deletion of the actual object
        except:
        dialogueExists = False
        if not dialogueExists :
        self.infoPanel = InfoPanel()


        Cheers and many thanks for the helpful advice on deciding whether to show / hide dialogues or to create / destroy them!







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 17 at 13:43









        Sacha Viquerat

        7019




        7019



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53260922%2fbest-approach-to-show-hide-dialogs%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            How to read a connectionString WITH PROVIDER in .NET Core?

            Node.js Script on GitHub Pages or Amazon S3

            Museum of Modern and Contemporary Art of Trento and Rovereto