项目中表格需要显示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() ... ...