PyQtGraph PlotWidget 在关闭时使应用程序崩溃 window
PyQtGraph PlotWidget crashes application on closing window
我正在尝试构建一个桌面应用程序,它会在一些流数据到达时绘制图表。我希望能够打开多个 windows 来监控不同的流。
在我开始关闭图表之前,它工作得很好 windows。
我遇到的问题是,关闭我的一个图表 windows 经常会导致所有 windows 关闭并退出应用程序。终端中没有错误消息出现,所有 windows 都关闭并且程序终止。关闭图表 window 应该 只关闭图表 window.
我在 Windows 10 上使用 PyQt5、PyQtGraph 0.10.0 和 Python 3.6.1。
下面的代码显示了我的应用程序的结构。
- App class 跟踪打开的 windows 并存储图表数据。 (实际上这个 class 收集流数据并为相关打开 windows 调用更新例程。)
- ButtonWindow class 可用于制作新图表windows。 (实际上,有很多按钮取决于用户希望图表的内容。)
ChartWindowclass显示数据。
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 个左右的图表 window 关闭后,它仍然会发生。
我还尝试将所有小部件设为它们所在的 window 的子级,但这没有效果。
有什么想法吗?我无法相信像打开和关闭包含情节的 window 这样简单的事情足以炸毁 PyQt 所以我假设我在我的结构中做了一些愚蠢的事情。
而不是从 closeEvent 调用一个 close_window 来消除自身,换句话说,你试图在同一个 window 中消除 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()
我正在尝试构建一个桌面应用程序,它会在一些流数据到达时绘制图表。我希望能够打开多个 windows 来监控不同的流。
在我开始关闭图表之前,它工作得很好 windows。
我遇到的问题是,关闭我的一个图表 windows 经常会导致所有 windows 关闭并退出应用程序。终端中没有错误消息出现,所有 windows 都关闭并且程序终止。关闭图表 window 应该 只关闭图表 window.
我在 Windows 10 上使用 PyQt5、PyQtGraph 0.10.0 和 Python 3.6.1。
下面的代码显示了我的应用程序的结构。
- App class 跟踪打开的 windows 并存储图表数据。 (实际上这个 class 收集流数据并为相关打开 windows 调用更新例程。)
- ButtonWindow class 可用于制作新图表windows。 (实际上,有很多按钮取决于用户希望图表的内容。)
ChartWindowclass显示数据。
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 个左右的图表 window 关闭后,它仍然会发生。
我还尝试将所有小部件设为它们所在的 window 的子级,但这没有效果。
有什么想法吗?我无法相信像打开和关闭包含情节的 window 这样简单的事情足以炸毁 PyQt 所以我假设我在我的结构中做了一些愚蠢的事情。
而不是从 closeEvent 调用一个 close_window 来消除自身,换句话说,你试图在同一个 window 中消除 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()