Я взял MCVE OP и попытался запустить его в моем cygwin64 в Windows 10.
Сначала я должен был применить небольшие исправления. (О.П. заявил, что он не смог проверить его на момент публикации.)
Сначала я вставил & ldquo; хижину & rdquo; на первой строке для удобного запуска в bash
:
#!/usr/bin/python3
Во-вторых, self.viewMenu
не появился. Следовательно, я вставил строку после
self.viewMenu = QMenu("&View", self)
self.viewMenu.addAction(self.showpanelAct)
для добавления viewMenu
к строке главного меню:
self.menuBar().addMenu(self.viewMenu)
который это исправил.
В-третьих, при нажатии на пункт меню я получил:
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)
Я должен признать, что мои знания Python очень ограничены. (Я - парень, который пишет привязки Python на C ++ для коллег. Итак, мои коллеги - настоящие эксперты. В большинстве случаев я немного играю в Python, когда проверяю, выполняют ли новые реализованные привязки то, что ожидается.) Однако Я модифицировал
self.canvas.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(40, 40, 40)))
до:
self.canvas.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
которая исправила эту проблему.
После этого я понял поведение, описанное OP, и внимательно посмотрел, где я (и OP) заподозрил ошибку:
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()
Я твердо верю, что try: self.infoPanel
не делает то, что думает OP.
Он пытается получить доступ к self.infoPanel
, который не существует до первого вызова этого метода. (Пожалуйста, имейте в виду, что переменная-член self.infoPanel
не существует.) Таким образом, ветвь except:
выполняется и устанавливает dialogueExists = False
, что через несколько строк вызывает self.infoPanel = InfoPanel() #init
. Теперь переменная-член self.infoPanel
существует, и try: self.infoPanel
никогда не будет повторяться до тех пор, пока не будет уничтожено это MainWindow
.
Из любопытства я взглянул на QWidget.destroy()
(чтобы не сказать что-то не так):
QWidget.destroy (self, bool destroyWindow = True, bool destroySubWindows = True)
Освобождает системные ресурсы окна. Уничтожает окно виджета, если destroyWindow имеет значение true.
destroy () вызывает себя рекурсивно для всех дочерних виджетов, передавая destroySubWindows для параметра destroyWindow. Чтобы лучше контролировать уничтожение подвиджетов, сначала выборочно уничтожайте подвиджеты.
Эта функция обычно вызывается из деструктора QWidget.
Это определенно не уничтожает переменную-член self.infoPanel
.
Поняв это, исправить было легко и очевидно:
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. Я заменил destroy()
на hide()
, что делает воссоздание InfoPanel()
устаревшим.
Я проверил это, переключая пункт меню несколько раз & ndash; теперь он работает как положено (по крайней мере, похоже).
Полный образец наконец:
#!/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_()