QTableWidget 对于大表变得很慢 [英] QTableWidget becomes slow for large tables

查看:86
本文介绍了QTableWidget 对于大表变得很慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个 Qt 表小部件,它每秒添加大约 20 行新行(最大为 10000).旧行永远不会改变.

I want to create a Qt table widget which adds about 20 new rows per second (maxed at 10000). Old rows are never changed.

我首先使用 QTableWidget,但我看到 CPU% 随着表大小的增加而增加,并且在总共约 1000 行时达到 100%.

Ar first I used QTableWidget, but I see the CPU% increases as the table size increases, and gets to 100% at around 1000 rows total.

所以我尝试创建自己的模型,它每 5 秒只执行一次 beginInsertRowsendInsertRows.我希望 CPU% 会保持不变,因为我只发出行,但我看到它仍然上升到 100%.

So I tried to create my own model, which only does beginInsertRows and endInsertRows every 5 seconds. I hoped that the CPU% will become constant since I only emit the new rows, but I see that it still climbs up to 100%.

所以我检查了发出之间的 data() 调用的数量,我看到它大约等于 240 * total_num_rows.

So I checked the number of data() calls I'm getting between emits, and I saw that is equal to about 240 * total_num_rows.

  1. 为什么视图查询所有的行,而不仅仅是新的行?
  2. 为什么是 240?我每行总共有 10 列.有 24 个角色吗?
  3. 我能否以某种方式控制视图以减少查询(常量)?
  1. Why does the view query all of the rows and not just the new ones?
  2. Why 240? I have 10 columns total per row. Are there 24 Roles?
  3. Can I control the view somehow to do less queries (constant)?

编辑

项目视图:

''' How to display each item '''
class BindedItemView(object):
    def __init__(self, item):
        self._data = item
    
    #--------------------------------------------------------------------#
    
    def _text(self, index):
        return QVariant()
    
    #--------------------------------------------------------------------#
    
    def _font(self, index):
        return QVariant()

    #--------------------------------------------------------------------#
    
    def _background(self, index):
        return QVariant()
    
    #--------------------------------------------------------------------#
    
    def _foreground(self, index):
        return QVariant()
    
    #--------------------------------------------------------------------#
        
    def get(self, role, col):
        if role == Qt.DisplayRole:
            return self._text(col)
        if role == Qt.FontRole:
            return self._font(col)
        if role == Qt.ForegroundRole:
            return self._foreground(col)
        if role == Qt.BackgroundRole:
            return self._background(col)             
        return QVariant()

型号:

class BindedTableModel(QAbstractTableModel):
    
    end_of_process_signal = pyqtSignal()
    
    #--------------------------------------------------------------------#
    
    def __init__(self, headers, item_view):
        super(BindedTableModel, self).__init__()
        self._headers = headers
        self._item_view = item_view
        self._items = []
        self._last_row_count = 0
        self._num_data_requests = 0
        
    #--------------------------------------------------------------------#

    def _index(self, item):
        return self._items.index(item)
    
    #--------------------------------------------------------------------#
    
    def _indexSorted(self, item):
        return bisect.bisect(self._items, item)
   
    #--------------------------------------------------------------------#
    
    def _refreshView(self):
        row_count = len(self._items)
        print "DATA REQUESTS: %u" % self._num_data_requests
        self._num_data_requests = 0
        if self._last_row_count < row_count:
            print "INSERT ROWS: %u %u" % (self._last_row_count, row_count - 1)
            self.beginInsertRows(QModelIndex(), self._last_row_count, row_count - 1)
            self.endInsertRows()
#         elif self._last_row_count > row_count:
#             self.beginRemoveRows(QModelIndex(), row_count, self._last_row_count - 1)
#             self.endRemoveRows()
#         else:
#             top_left = self.createIndex(0, 0)
#             bottom_right = self.createIndex(row_count - 1, self.columnCount() - 1)
#             self.dataChanged.emit(top_left, bottom_right)
        self._last_row_count = row_count
        
    #--------------------------------------------------------------------#
    
    def _onUpdate(self):
        pass 
        
    #--------------------------------------------------------------------#
    
    def _addItem(self, item, pos):
        self._items.insert(pos, item)
        self._onUpdate()
            
    #--------------------------------------------------------------------#
        
    def _removeItem(self, pos):
        self._items.pop(pos)
        self._onUpdate()
        
    #--------------------------------------------------------------------#
    
    def appendItem(self, item):
        self._addItem(item, len(self._items))

    #--------------------------------------------------------------------#
    
    def addItemSorted(self, item):
        self._addItem(item, self._indexSorted(item))

    #--------------------------------------------------------------------#
        
    def removeItem(self, item):
        self._removeItem(self._index(item))
    
    #--------------------------------------------------------------------#
        
    def clear(self):
        self._items = []
        
    #--------------------------------------------------------------------#
    
    def refreshView(self):
        self._refreshView()
    
    #--------------------------------------------------------------------#
    
    '''
    Override 
    '''
    def rowCount(self, parent = None):
        return len(self._items)

    #--------------------------------------------------------------------#

    '''
    Override 
    '''
    def columnCount(self, parent = None):
        return len(self._headers)

    #--------------------------------------------------------------------#
    
    '''
    Override 
    '''
    def data(self, index, role):
        self._num_data_requests += 1
        item = self._items[index.row()]
        view = self._item_view(item)
        return view.get(role, index.column())
                
    #--------------------------------------------------------------------#
            
    '''
    Override 
    '''            
    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return self._headers[section] 
        return QVariant()
    
    #--------------------------------------------------------------------#

    '''
    Override 
    '''    
    def setData(self, index, value, role):
        if role == Qt.DisplayRole:
            pass

    #--------------------------------------------------------------------#
    
    def __iter__(self):
        return self._items.__iter__()
    
    #--------------------------------------------------------------------#
    
    def __contains__(self, item):
        return item in self._items

推荐答案

这是一种解决方法,但将模型限制为 行数 <1000 给出了一个恒定的 CPU%.

This is a workaround, but limiting the model to row count < 1000 gives a constant CPU%.

所以对我来说一个优雅的解决方案是创建一个分页"表格视图,它一次只显示 N 行(并且用户可以控制当前显示的窗口).

So an elegant solution for me will be to create a "paged" table view, which only shows N rows at a time (and the user can control the currently displayed window).

这产生了出色的 CPU 以及更好的可用性,所以我认为最初的问题不相关.

This yields excellent CPU as well as better usability, so I think the original question is not relevant.

这篇关于QTableWidget 对于大表变得很慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆