当在循环中调用QtWidget.grab()时,它会逐渐消耗内存



我有PyQt5 GUI,在那里我加载一些数据,然后将其绘制成图形

为了不上传整个应用程序,我只创建了一个使用崩溃的示例。。。

一次,我需要保存";GUI可见";图形作为图片(供以后使用(,所以我称之为:

grabbed = some_graphically_visible_widget.grab()

grabbed.save("My_name.png")

在循环中调用这两个方法多达350次循环,python保存被抓取的";对象";因为作为memory_profiler显示,我发现,每个.grab((循环内存消耗增加~1.5MB

此外,我尝试了多种使用变体:

del grabbed

在循环结束时,或玩

gc.collect()

但没有任何帮助,称这种循环总是吃";这是一部分;。

下面是完整的示例应用程序,它只运行一次PyQt5和pyqtgraph模块被提供为";导入":

import sys
import os
from random import randint
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QShortcut, QMessageBox
from PyQt5.QtGui import QKeySequence
import pyqtgraph
app = QtWidgets.QApplication(sys.argv)
class Ui_MainWindow(object):
def __init__(self):
self.graph_list = []
def setupUi(self, MainWindow):
MainWindow.setObjectName("Example")
MainWindow.resize(750, 750)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget.setGeometry(QtCore.QRect(5, 5, 740, 740))
self.tabWidget.setObjectName("tabWidget")
self.shortcut_CtrlL = QShortcut(QKeySequence('Ctrl+E'),self.centralwidget)
self.shortcut_CtrlL.activated.connect(self.doExport)
progress = QtWidgets.QProgressDialog("Creating enough graphs to simulate my case ... (350) ", None, 0, 350, self.centralwidget)
progress.setWindowTitle("...")
progress.show()
"Typical amount of graphs in application"
for tab_idx in range(350):
font = QtGui.QFont()
font.setPixelSize(15)
tab = QtWidgets.QWidget()
graph = pyqtgraph.PlotWidget(tab)
self.graph_list.append(graph)
graph.setGeometry(QtCore.QRect(5, 5, 740, 740))
graph.addLegend(size=None, offset=(370, 35))
x = []
y = []
min = []
max = []
for num in range(10):
x.append(num)
y.append(randint(0, 10))
min.append(0)
max.append(10)
graph.plot(x, y, symbol='o', symbolPen='b', symbolBrush='b', name = "List of randomized values")
graph.plot(x, min, pen=pyqtgraph.mkPen('r', width=3, style=QtCore.Qt.DashLine))
graph.plot(x, max, pen=pyqtgraph.mkPen('r', width=3, style=QtCore.Qt.DashLine))
graph.showGrid(x=True)
graph.showGrid(y=True)
graph.setTitle(str(graph))
self.tabWidget.addTab(tab, str(tab_idx))
progress.setValue(tab_idx)
app.processEvents()
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Information)
str_to_show = "Once you see GUI, press CTRL+E and watch memory consumption in task manager"
msgBox.setText(str_to_show)
msgBox.setWindowTitle("Information")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
progress.close()

def doExport(self):
iterations = 0
progress = QtWidgets.QProgressDialog("Doing .grab() and .save() iterations nnow you may watch increase RAM consumption - you must open taskmgr", None, 0, 350, self.centralwidget)
progress.setWindowTitle("...")
progress.show()
for graph in self.graph_list:
iterations += 1
grabbed = graph.grab()
grabbed.save("Dont_worry_I_will_be_multiple_times_rewritten.png")
progress.setValue(iterations)
app.processEvents()
progress.close()
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Information)
str_to_show = str(iterations) + ' graphs was grabbed and converted into .png and n python's RAM consumption had to increase ...'
msgBox.setText(str_to_show)
msgBox.setWindowTitle("Information")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()

if __name__ == "__main__":
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

这与grab无关(至少不是直接(,而是与QGraphicsView缓存有关(pyqtgraph PlotWidgets实际上是QGraphicsView子类(。

事实上,如果您对整个抓取进行注释并使用self.tabWidget.setCurrentIndex(iterations),您无论如何都会看到内存峰值,这是因为grab()显然会导致小部件被绘制,从而创建图形视图缓存。

问题的解决方案是禁用每个图的缓存:

def setupUi(self, MainWindow):
# ...
for tab_idx in range(350):
# ...
graph = pyqtgraph.PlotWidget(tab)
self.graph_list.append(graph)
graph.setCacheMode(graph.CacheNone)

真正的问题是:你真的需要添加这么多图吗?如果您只需要抓取每个图形,请使用单个绘图小部件,并在for循环中设置每个绘图/抓取。老实说,我不明白同时显示这么多图形的好处是什么:350个QGraphicsViews非常,我真诚地怀疑你是否真的需要用户一次访问所有图形,尤其是考虑到使用QTabWidget会使它们难以访问。

还有:

  1. 您正在为每个选项卡创建一个tabQWidget,但您只是添加了一个图形视图,而没有任何布局管理器;这会导致调整主窗口大小时出现问题(绘图小部件不会调整其大小(,而且无论如何都是不必要的:只需将绘图小部件添加到QTabWidget:self.tabWidget.addTab(graph, str(tab_idx))
  2. NEVER修改pyuic生成的文件,也不要试图模仿它们的行为;如果您是从代码构建UI,只需对将充当容器/窗口的小部件(在您的情况下为QMainWindow(进行子类化,向其添加子小部件(使用主窗口的中心小部件(,并实现该类中的所有方法,否则请遵循有关使用Designer的官方指南

相关内容

  • 没有找到相关文章

最新更新