Pyqt5實現model/View,解決tableView出現空白行問題。
阿新 • • 發佈:2020-08-24
專案中表格需要顯示5萬條資料以上,並且實時重新整理。開始使用的tableWidget,資料量一大顯得力不從心,所以使用Qt的Model/View來重新實現。下面是更改之前編寫的小Demo。
import sys from untitled import Ui_Form from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import Qt, QAbstractTableModel, QModelIndex, QVariant, QThread, pyqtSignal class WorkThread(QThread): scrollBottomSignal = pyqtSignal() def __init__(self, model): super(WorkThread, self).__init__() self.model = model self.run_flag = True def run(self): while self.run_flag: row = self.model.rowCount() self.model.insertRows(row, 1, QModelIndex()) self.scrollBottomSignal.emit() self.usleep(1) # 不加延遲介面會卡頓。 def stop(self): self.run_flag = False class MyTableModel(QAbstractTableModel): def __init__(self): super(MyTableModel, self).__init__() self._data = [] # 要顯示的資料 self._headers = ['行號', '姓名', '年齡', '性別'] # 表頭 self.i = 0 def rowCount(self, parent=QModelIndex()): """ 返回行數量。 """ return len(self._data) def columnCount(self, parent=QModelIndex()): """ 返回列數量。 """ return len(self._headers) def insertRows(self, row, count, parent): """ 插入行。 :param row: 插入起始行。 :param count: 插入行數量。 :param parent: :return: """ self.beginInsertRows(QModelIndex(), row, row + count - 1) for i in range(count): self._data.insert(row, ['CZ', '25', '男']) self.endInsertRows() return True def removeRows(self, row, count, parent): self.beginRemoveRows(QModelIndex(), 0, row + count - 1) for i in range(count): self._data.pop(row + count - 1 - i) # 倒著刪 self.endRemoveRows() def clearView(self): self.removeRows(0, self.rowCount(), QModelIndex()) def headerData(self, section, orientation, role): """ 設定表頭。 """ if role == Qt.DisplayRole and orientation == Qt.Horizontal: # 限定只更改行表頭 return self._headers[section] def data(self, index, role=Qt.DisplayRole): if not index.isValid() or not 0 <= index.row() < self.rowCount(): return QVariant() row = index.row() col = index.column() if role == Qt.DisplayRole: if col == 0: return str(row) # 行號 else: return str(self._data[row][col-1]) # 資料 return QVariant() class MainUI(QWidget, Ui_Form): def __init__(self): super(MainUI, self).__init__() self.setupUi(self) self.workThread = None self.pushButton.clicked.connect(self.buttonClickedStart) self.pushButton_2.clicked.connect(self.buttonClickedStop) self.pushButton_3.clicked.connect(self.buttonClickedClear) self.model = MyTableModel() self.tableView.setModel(self.model) self.tableView.show() def buttonClickedStart(self): """開啟執行緒,向表中插入資料。""" self.workThread = WorkThread(self.model) self.workThread.scrollBottomSignal.connect(self.scrollBottom) self.workThread.start() def buttonClickedStop(self): """停止執行緒向表中插入資料。""" self.workThread.stop() def buttonClickedClear(self): """清空表。""" self.model.clearView() def scrollBottom(self): """右側滑動條保持在最下面。""" self.tableView.scrollToBottom() if __name__ == '__main__': app = QApplication(sys.argv) ui = MainUI() ui.show() sys.exit(app.exec_())
程式執行起來之後的樣子,速度是槓槓的:
功能:
(1)點選開始按鈕表格開始刷資料。
(2)點選暫停按鈕表格停止刷資料。
(3)點選清空按鈕清空表格中的資料。
但是在測試過程中發現問題,在表中資料重新整理時點選清空按鈕,表格中會出現很多空行,如下圖所示,這些空行不管我們怎麼點選清空都刪除不了。
這個問題卡了大概一天多,最後定位到原因,Qt中在子執行緒中不要操作介面,子執行緒中不要操作介面,子執行緒中不要操作介面,重要說三遍。
我將子執行緒更改成訊號的形式增加資料已經解決此問題,下面是更改部分程式碼:
class WorkThread(QThread): scrollBottomSignal = pyqtSignal() addDataSignal = pyqtSignal() def __init__(self, model): super(WorkThread, self).__init__() self.model = model self.run_flag = True def run(self): while self.run_flag: # row = self.model.rowCount() # self.model.insertRows(row, 1, QModelIndex()) self.addDataSignal.emit() self.scrollBottomSignal.emit() self.usleep(1) # 不加延遲介面會卡頓。 def stop(self): self.run_flag = False class MyTableModel(QAbstractTableModel): ... ... def addData(self): self.insertRows(self.rowCount(), 1, QModelIndex()) ... ... class MainUI(QWidget, Ui_Form): ... ... def buttonClickedStart(self): """開啟執行緒,向表中插入資料。""" self.workThread = WorkThread(self.model) self.workThread.addDataSignal.connect(self.model.addData) self.workThread.scrollBottomSignal.connect(self.scrollBottom) self.workThread.start() ... ...