Pyqt5實現model/View,解決tableView出現空白行問題。


 項目中表格需要顯示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()

  ... ...

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM