我正在尝试构建一个桌面应用程序,该应用程序会在到达时绘制一些流数据的图表。我希望能够打开多个窗口以监视不同的流。
在我开始关闭图表窗口之前,它工作得很好。
我的问题是关闭我的一个图表窗口经常会导致所有窗口关闭并退出应用程序。终端中没有错误消息出现,所有窗口仅关闭并且程序终止。关闭图表窗口应该仅关闭图表窗口。
我在Windows 10上使用PyQt5,PyQtGraph 0.10.0和Python 3.6.1。
下面的代码显示了我的应用程序的结构。
ChartWindow 类显示数据。
import PyQt5.QtWidgets as qt
import pyqtgraph as pg
class App(qt.QApplication):
def __init__(self,args):
qt.QApplication.__init__(self,args)
#window tracking
self.last_idx = 0
self.windows = {}
#chart data
self.x = [1,2,3,4,5]
self.y = [1,2,3,4,5]
#create button window
self.button_window = ButtonWindow(self)
#enter event loop
self.exec_()
def new_window(cls):
cls.windows[cls.last_idx] = ChartWindow(cls, cls.last_idx)
cls.last_idx += 1
def close_window(cls, window_id):
cls.windows[window_id].destroy()
del cls.windows[window_id]
class ButtonWindow(qt.QWidget):
def __init__(self, app):
qt.QWidget.__init__(self)
self.grid = qt.QGridLayout()
self.app = app
#add a button
self.btn = qt.QPushButton('+1 Chart Window')
self.btn.clicked.connect(self.app.new_window)
self.grid.addWidget(self.btn,0,0)
self.setLayout(self.grid)
#show window
self.show()
class ChartWindow(qt.QWidget):
def __init__(self, app, window_id):
qt.QWidget.__init__(self)
self.grid = qt.QGridLayout()
self.app = app
self.window_id = window_id
self.setWindowTitle('Chart Window '+str(self.window_id))
#add a chart
self.chart = pg.PlotWidget()
self.chart.plot(app.x,app.y)
self.grid.addWidget(self.chart,0,0)
self.setLayout(self.grid)
#show window
self.show()
def closeEvent(cls,event):
#cls.chart.close()
cls.app.close_window(cls.window_id)
def main():
app = App([])
if __name__ == '__main__':
main()
看完之后,我认为这是由于Python垃圾收集器与尚存的对基础c ++对象的引用之间存在一些冲突。
该问题肯定与PlotWidget有关。如果将绘图小部件交换为按钮,则不会观察到崩溃。
我想到了在1的closeEvent覆盖中添加'cls.chart.close()'行的想法。这会有所帮助。崩溃的频率降低了,但关闭20个左右的图表窗口后,它仍然会发生。
我也尝试过使所有小部件成为其所在窗口的子级,但这没有效果。
有什么想法吗?我不敢相信像打开和关闭包含图的窗口那样简单的事情足以炸毁PyQt,所以我认为我在结构中做的很愚蠢。
答案 0 :(得分:1)
代替从closeEvent调用一个消除自身的close_window,换句话说,您试图消除同一窗口中的窗口,这就是问题所在,在Qt中,您必须使用信号来通知更改,在在这种情况下,请执行带有已关闭索引的关闭信号。
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
class App(QtWidgets.QApplication):
def __init__(self, args):
super(App, self).__init__(args)
#window tracking
self.last_idx = 0
self.windows = {}
#chart data
self.x = [1,2,3,4,5]
self.y = [1,2,3,4,5]
#create button window
self.button_window = ButtonWindow()
#enter event loop
self.exec_()
@QtCore.pyqtSlot()
def new_window(self):
window = ChartWindow(self, self.last_idx)
window.closed.connect(self.remove_window)
self.windows[self.last_idx] = window
self.last_idx += 1
@QtCore.pyqtSlot(int)
def remove_window(self, idx):
w = self.windows[idx]
w.deleteLater()
del self.windows[idx]
print(self.windows)
class ButtonWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ButtonWindow, self).__init__(parent)
grid = QtWidgets.QGridLayout(self)
self.btn = QtWidgets.QPushButton('+1 Chart Window')
self.btn.clicked.connect(QtWidgets.QApplication.instance().new_window)
grid.addWidget(self.btn, 0, 0)
self.show()
class ChartWindow(QtWidgets.QWidget):
closed = QtCore.pyqtSignal(int)
def __init__(self, app, window_id):
super(ChartWindow, self).__init__()
grid = QtWidgets.QGridLayout(self)
self.window_id = window_id
self.setWindowTitle('Chart Window '+str(self.window_id))
#add a chart
self.chart = pg.PlotWidget()
self.chart.plot(app.x,app.y)
grid.addWidget(self.chart,0,0)
#show window
self.show()
def closeEvent(self, event):
self.closed.emit(self.window_id)
super(ChartWindow, self).closeEvent(event)
def main():
app = App([])
if __name__ == '__main__':
main()