Best approach to show / hide dialogs
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
|
show 13 more comments
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
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 '18 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 '18 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 thetry: ... except: ...
approach doesn't work as I expected!?
– Sacha Viquerat
Nov 13 '18 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 '18 at 10:08
Concerning thetry: ... except: ...
: Could you extend your sample to a Minimal, Complete, and Verifiable example?
– Scheff
Nov 13 '18 at 10:11
|
show 13 more comments
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
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
qt user-interface pyqt5
edited Nov 13 '18 at 11:17
Sacha Viquerat
asked Nov 12 '18 at 11:11
Sacha ViqueratSacha 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 '18 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 '18 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 thetry: ... except: ...
approach doesn't work as I expected!?
– Sacha Viquerat
Nov 13 '18 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 '18 at 10:08
Concerning thetry: ... except: ...
: Could you extend your sample to a Minimal, Complete, and Verifiable example?
– Scheff
Nov 13 '18 at 10:11
|
show 13 more comments
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 '18 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 '18 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 thetry: ... except: ...
approach doesn't work as I expected!?
– Sacha Viquerat
Nov 13 '18 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 '18 at 10:08
Concerning thetry: ... except: ...
: Could you extend your sample to a Minimal, Complete, and Verifiable example?
– Scheff
Nov 13 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 10:08
Concerning the
try: ... except: ...
: Could you extend your sample to a Minimal, Complete, and Verifiable example?– Scheff
Nov 13 '18 at 10:11
Concerning the
try: ... except: ...
: Could you extend your sample to a Minimal, Complete, and Verifiable example?– Scheff
Nov 13 '18 at 10:11
|
show 13 more comments
2 Answers
2
active
oldest
votes
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_()
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
add a comment |
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!
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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_()
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
add a comment |
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_()
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
add a comment |
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_()
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_()
answered Nov 13 '18 at 12:27
ScheffScheff
7,96821325
7,96821325
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
add a comment |
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
Thanks a lot. I will check this when I get home!
– Sacha Viquerat
Nov 13 '18 at 12:43
add a comment |
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!
add a comment |
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!
add a comment |
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!
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!
answered Nov 17 '18 at 13:43
Sacha ViqueratSacha Viquerat
7019
7019
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 '18 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 '18 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 '18 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 '18 at 10:08
Concerning the
try: ... except: ...
: Could you extend your sample to a Minimal, Complete, and Verifiable example?– Scheff
Nov 13 '18 at 10:11