2016-08-22 159 views
0

這是我用來填充QT Designer中繪製的表格的代碼。 設計爲通用的任何表,它工作正常,但... 當我試圖顯示一個包含18列和~12000行的數據庫時,它只會凍結30秒或更長時間。 那麼,我做錯了什麼,有沒有辦法加速,保持代碼仍然適合任何表?PyQT QTableWidget極慢

這是我的代碼:

...blablabla... 

self.connect(self, SIGNAL("set"), self.real_set) 

...blablabla... 

def set_table(self, table, data): 
    self.emit(SIGNAL('set'), table, data) 

def real_set(self, table, data): 
    """ 
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    Assuming data is list of dict and table is a QTableWidget. 

    Get first key and get len of contents 
    """ 
    for key in data: 
     rows = len(data[key]) 
     table.setRowCount(rows) 
     break 

    """ 
    Forbid resizing(speeds up) 
    """ 
    table.horizontalHeader().setResizeMode(QHeaderView.Fixed) 
    table.verticalHeader().setResizeMode(QHeaderView.Fixed) 
    table.horizontalHeader().setStretchLastSection(False) 
    table.verticalHeader().setStretchLastSection(False) 

    """ 
    Set number of columns too 
    """ 
    table.setColumnCount(len(data)) 
    table.setHorizontalHeaderLabels(sorted(data.keys())) 

    """ 
    Now fill data 
    """ 
    for n, key in enumerate(sorted(data.keys())): 
     for m, item in enumerate(data[key]): 
      newitem = QTableWidgetItem(item) 
      table.setItem(m, n, newitem) 
+0

〜12000行是一個很大的表... –

+2

你的意思是在標題中說'QTableWidget'?因爲你似乎在代碼中使用'QTableWidgetItem' ...另外,更完整的代碼會很好,因爲現在不知道例如'table'或'item'的類型是什麼。 – hyde

+0

嘗試測量完成代碼的各個部分以縮小問題所需的時間。它檢索數據嗎?它是用物品填滿桌子嗎? – cpburnz

回答

3

這裏測試腳本,其比較填充表的幾種方法實現。

自定義模型要快得多,因爲它不需要預先創建所有項目 - 但請注意它是一個非常基本的實現,因此不會實現排序,編輯等。(有關更多詳細信息,請參見Model/View Programming )。

from random import shuffle 
from PyQt4 import QtCore, QtGui 

class TableModel(QtCore.QAbstractTableModel): 
    def __init__(self, data, parent=None): 
     super(TableModel, self).__init__(parent) 
     self._data = data 

    def rowCount(self, parent=None): 
     return len(self._data) 

    def columnCount(self, parent=None): 
     return len(self._data[0]) if self.rowCount() else 0 

    def data(self, index, role=QtCore.Qt.DisplayRole): 
     if role == QtCore.Qt.DisplayRole: 
      row = index.row() 
      if 0 <= row < self.rowCount(): 
       column = index.column() 
       if 0 <= column < self.columnCount(): 
        return self._data[row][column] 

class Window(QtGui.QWidget): 
    def __init__(self): 
     super(Window, self).__init__() 
     self.table = QtGui.QTableView(self) 
     self.tablewidget = QtGui.QTableWidget(self) 
     self.tablewidget.setSortingEnabled(True) 
     self.button1 = QtGui.QPushButton('Custom Model', self) 
     self.button1.clicked.connect(
      lambda: self.populateTable('custom')) 
     self.button2 = QtGui.QPushButton('StandardItem Model', self) 
     self.button2.clicked.connect(
      lambda: self.populateTable('standard')) 
     self.button3 = QtGui.QPushButton('TableWidget', self) 
     self.button3.clicked.connect(
      lambda: self.populateTable('widget')) 
     self.spinbox = QtGui.QSpinBox(self) 
     self.spinbox.setRange(15000, 1000000) 
     self.spinbox.setSingleStep(10000) 
     layout = QtGui.QGridLayout(self) 
     layout.addWidget(self.table, 0, 0, 1, 4) 
     layout.addWidget(self.tablewidget, 1, 0, 1, 4) 
     layout.addWidget(self.button1, 2, 0) 
     layout.addWidget(self.button2, 2, 1) 
     layout.addWidget(self.button3, 2, 2) 
     layout.addWidget(self.spinbox, 2, 3) 
     self._data = [] 

    def populateTable(self, mode): 
     if mode == 'widget': 
      self.tablewidget.clear() 
      self.tablewidget.setRowCount(self.spinbox.value()) 
      self.tablewidget.setColumnCount(20) 
     else: 
      model = self.table.model() 
      if model is not None: 
       self.table.setModel(None) 
       model.deleteLater() 
     if len(self._data) != self.spinbox.value(): 
      del self._data[:] 
      rows = list(range(self.spinbox.value())) 
      shuffle(rows) 
      for row in rows: 
       items = [] 
       for column in range(20): 
        items.append('(%d, %d)' % (row, column)) 
       self._data.append(items) 
     timer = QtCore.QElapsedTimer() 
     timer.start() 
     if mode == 'widget': 
      self.tablewidget.setSortingEnabled(False) 
      for row, items in enumerate(self._data): 
       for column, text in enumerate(items): 
        item = QtGui.QTableWidgetItem(text) 
        self.tablewidget.setItem(row, column, item) 
      self.tablewidget.sortByColumn(0, QtCore.Qt.AscendingOrder) 
     else: 
      self.table.setSortingEnabled(False) 
      if mode == 'custom': 
       model = TableModel(self._data, self.table) 
      elif mode == 'standard': 
       model = QtGui.QStandardItemModel(self.table) 
       for row in self._data: 
        items = [] 
        for column in row: 
         items.append(QtGui.QStandardItem(column)) 
        model.appendRow(items) 
      self.table.setModel(model) 
      self.table.setSortingEnabled(True) 
      self.table.sortByColumn(0, QtCore.Qt.AscendingOrder) 
     print('%s: %.3g seconds' % (mode, timer.elapsed()/1000)) 

if __name__ == '__main__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(600, 50, 1200, 800) 
    window.show() 
    sys.exit(app.exec_()) 
+0

我必須承認你是一位強大的編碼員。我需要一些時間來審查和分析你的腳本! – pmus

1

在GUI應用程序的一個遇到的情況是有必要 以表格或列表格式顯示很多項目(例如 顯示大量的行在表中)。增加 GUI響應度的一種方法是在屏幕顯示 時加載一些項目,並根據用戶操作推遲加載其餘項目。 Qt 提供了一個解決方案來解決加載數據需求的這種需求。

你可以找到這個技術稱爲分頁在這個link

+2

一個潛在的解決方案的鏈接永遠是受歡迎的,但請[在鏈接周圍添加上下文](// meta.stackoverflow.com/a/8259),以便您的同行用戶可以瞭解它是什麼以及它爲什麼在那裏。如果目標網站無法訪問或永久離線,請始終引用重要鏈接中最相關的部分。考慮到_僅僅是一個鏈接到外部site_是一個可能的原因,因爲[爲什麼和如何刪除一些答案?](// stackoverflow.com/help/deleted-answers)。 – FrankerZ

+0

這是一個很好的觀點,但由於需要一次顯示錶格,所以不適合我的情況。 – pmus

+0

@pmus如果你要一次顯示所有的數據,你需要一個強大的顯示;) – hyde