QItemDelegate中重写方法绘制中的奇怪内存泄漏

时间:2016-07-22 11:33:48

标签: python python-3.x pyqt pyqt5

我有一个相当大的项目,用Python 3.4和PyQt5 5.5.1编写。从PyQt5版本5.4.1更新到PyQt5版本5.5.1后,我有奇怪的内存泄漏,5.4.1版本没有任何泄漏。我在项目中使用自定义QAbstractTableModel和自定义QTableView以及数据类型的委托。这是示例代码,它在第98行和第117行中有内存泄漏(可以使用tracemalloc找到它)。在表中选择单元格时会发生内存泄漏。

为什么会这样?

#!/usr/bin/python3 
import tracemalloc 

tracemalloc.start() 

import sys 
from PyQt5.QtCore import * 
from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 

RW = (Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled) 

my_array = [['00','01','02'], 
            ['10','11','12'], 
            ['20','21','22']] 

class MyWindow(QWidget): 
    def __init__(self, *args): 
        QWidget.__init__(self, *args) 

        tablemodel = MyTableModel(my_array, self) 
        tableview = QTableView() 
        tableview.setModel(tablemodel) 

        self.cdelegates = [] 
        for i in range(3): 
            d = RSpinDelegate(self) 
            self.cdelegates.append(d) 
            tableview.setItemDelegateForColumn(i, d) 

        layout = QVBoxLayout(self) 
        layout.addWidget(tableview) 
        self.setLayout(layout) 
        self.startTimer(5000) 

    def timerEvent(self, e): 
        snapshot = tracemalloc.take_snapshot() 
        top_stats = snapshot.statistics('lineno') 

        print("[ Top 10 ]") 
        for stat in top_stats[:10]: 
            print(stat) 

class RSpinDelegate(QItemDelegate): 
    def __init__(self, parent=None, decimals=0, step=1, range_=(0, 1e9), edit=RW, suffix='', colorfill=None, stepFilter=None): 
        super(RSpinDelegate, self).__init__(parent) 
        self.decimals = decimals 
        self.step = step 
        self.range_ = range_ 
        self.edit = edit 
        self.suffix = suffix 
        self.colorfill = colorfill 
        self.stepFilter = stepFilter 

    def setDecimals(self, decimals): 
        self.decimals = decimals 

    def createEditor(self, parent, option, index): 
        if self.edit == RW: 
            if self.decimals: 
                decimals = self.decimals 
                dec = int(index.model().data(index, RBaseTableModel.DECIMALS_ROLE)) 
                decimals = dec 
                d = 10 ** (-decimals) 
                editor = RDoubleSpinBox(parent) 
                if self.stepFilter != None: 
                    editor.installEventFilter(self.stepFilter) 
                editor.setSingleStep(d) 
                editor.setDecimals(decimals) 
                editor.setRange(self.range_[0], self.range_[1]) 
                editor.setSuffix(self.suffix) 
                self._editor = editor 
                return editor 
            else: 
                editor = RSpinBox(parent) 
                if self.stepFilter != None: 
                    editor.installEventFilter(self.stepFilter) 
                editor.setSingleStep(self.step) 
                editor.setRange(self.range_[0], self.range_[1]) 
                editor.setSuffix(self.suffix) 
                self._editor = editor 
                return editor 
            return None 
        return None 

    def setEditorData(self, editor, index): 
        val = index.model().data(index, Qt.EditRole) 
        try: 
            editor.setValue(float(val.replace(' ', '')) if self.decimals != 0 else int(val.replace(' ', '')))
        except: 
            editor.setValue(editor.minimum()) 

    def setModelData(self, editor, model, index): 
        model.setData(index, editor.value(), Qt.EditRole) 

    def getBrush(self, option): 
        brush = option.palette.base() 
        if option.state & QStyle.State_Selected:# memory leak is here!
            if option.state & QStyle.State_Active: 
                brush = option.palette.highlight() 
            else: 
                brush = option.palette.light() 
        return brush 

    def updateEditorGeometry(self, editor, option, index): 
        editor.setGeometry(option.rect) 

    def paint(self, painter, option, index): 
        opt = QStyleOptionViewItem(option) 
        if self.colorfill: 
            brush = self.colorfill(index.model().data(index, RBaseTableModel.INDEX_ROLE), option) 
            if not(option.state & QStyle.State_Selected): 
                painter.fillRect(option.rect, brush) 
            opt.palette.setBrush(QPalette.Highlight, brush) 
        else: 
            brush = self.getBrush(option) 
            painter.fillRect(option.rect, brush)# memory leak is here!
        super(RSpinDelegate, self).paint(painter, opt, index) 

# création du modèle 
class MyTableModel(QAbstractTableModel): 
    refreshTable = pyqtSignal() 

    def __init__(self, datain, parent = None, *args): 
        QAbstractTableModel.__init__(self, parent, *args) 
        self.arraydata = datain 
        self.timer = self.startTimer(300) 

    def timerEvent(self, e): 
        if self.timer == e.timerId(): 
            self.refreshTable.emit() 
        else: 
            super(RBaseTableView, self).timerEvent(e) 

    def refreshTableSlot(self): 
        self.layoutAboutToBeChanged.emit() 
        self.layoutChanged.emit() 

    def rowCount(self, parent): 
        return len(self.arraydata) 

    def columnCount(self, parent): 
        return len(self.arraydata[0]) 

    def data(self, index, role): 
        if not index.isValid(): 
            return None 
        elif role != Qt.DisplayRole: 
            return None 
        return (self.arraydata[index.row()][index.column()]) 

if __name__ == "__main__": 
    app = QApplication(sys.argv) 
    w = MyWindow() 
    w.show() 
    sys.exit(app.exec_())

0 个答案:

没有答案