通过循环不断更新QTableView

Posted

技术标签:

【中文标题】通过循环不断更新QTableView【英文标题】:constantly update QTableView via loop 【发布时间】:2020-03-19 07:09:00 【问题描述】:

我一直在创建一个通过任务的应用程序。该应用程序不断向我抛出数据并将其显示在表格中,但是,由于信息量如此之大,该应用程序有时会为我挂起。我在网上搜索,发现了这个问题:

Update QTableWidget rows with each iteration of loop

实际上我使用的是 QTableWidget 我只是使用了 QTableView 但它不起作用。我想要在我的桌子上的效果类似于这个脚本

import time

for i in range(100000):
    print(i)
    time.sleep(0.3)

我留下我的 PyQT5 代码:

table.py

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(492, 403)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        self.txt_quantity = QtWidgets.QLineEdit(self.centralwidget)
        self.txt_quantity.setObjectName("txt_quantity")
        self.horizontalLayout.addWidget(self.txt_quantity)
        self.btn_run = QtWidgets.QPushButton(self.centralwidget)
        self.btn_run.setObjectName("btn_run")
        self.horizontalLayout.addWidget(self.btn_run)
        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
        self.table = QtWidgets.QTableView(self.centralwidget)
        self.table.setObjectName("table")
        self.gridLayout.addWidget(self.table, 1, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 492, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "quantity: "))
        self.btn_run.setText(_translate("MainWindow", "run"))

ma​​in.py

import sys
import time
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from table import Ui_MainWindow

class main(QMainWindow):
    def __init__(self):
        super(main, self).__init__()
        self.ui = Ui_MainWindow()        
        self.ui.setupUi(self)        
        self.table()
        self.ui.txt_quantity.setText("100000")
        self.ui.btn_run.clicked.connect(self.run)


    def run(self):       

        for i in range(int(self.ui.txt_quantity.text())):           
            item1 = QStandardItem("item" + str(i))
            item1.setTextAlignment(Qt.AlignCenter)
            item2 = QStandardItem("item" + str(i))
            item2.setTextAlignment(Qt.AlignCenter)
            item3 = QStandardItem("item" + str(i))
            item3.setTextAlignment(Qt.AlignCenter)
            item4 = QStandardItem("item" + str(i))
            item4.setTextAlignment(Qt.AlignCenter)
            item5 = QStandardItem("item" + str(i))
            item5.setTextAlignment(Qt.AlignCenter)
            self.model.appendRow([item1, item2, item3, item4, item5])
            self.ui.table.setModel(self.model)
            # optional the effect I want
            time.sleep(0.3)       



    def table(self):
        self.model = QStandardItemModel()
        self.model.setColumnCount(5)
        self.model.setRowCount(0)
        self.model.setHorizontalHeaderLabels(['header1', 'header2', 'header3', 'header4', 'header5'])
        self.ui.table.setModel(self.model)
        self.ui.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.ui.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.ui.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.ui.table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        self.ui.table.horizontalHeader().setSectionResizeMode(4, QHeaderView.Stretch) 



if __name__ == '__main__':
    app = QApplication([])
    application = main()
    application.show()
    sys.exit(app.exec())

非常感谢社区 :)

【问题讨论】:

【参考方案1】:

你不应该使用 time.sleep() 因为它阻塞了事件循环,在这种情况下你可以用迭代器 + QTimer 替换 for-loop + time.sleep()。

class main(QMainWindow):
    def __init__(self):
        super(main, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.table()
        self.ui.txt_quantity.setText("100000")
        self.ui.btn_run.clicked.connect(self.run)
        self.iter = None
        self.timer = QTimer(interval=300, timeout=self.add_row)

    def run(self):
        try:
            rows = int(self.ui.txt_quantity.text())
        except ValueError:
            print("The value entered must be a integer")
        else:
            if rows > 0:
                self.iter = iter(range(rows))
                self.add_row()
                self.timer.start()
            else:
                print("The value entered must be a positive integer")

    def add_row(self):
        try:
            i = next(self.iter)
        except StopIteration:
            self.iter = None
            self.timer.stop()
        else:
            item1 = QStandardItem("item" + str(i))
            item1.setTextAlignment(Qt.AlignCenter)
            item2 = QStandardItem("item" + str(i))
            item2.setTextAlignment(Qt.AlignCenter)
            item3 = QStandardItem("item" + str(i))
            item3.setTextAlignment(Qt.AlignCenter)
            item4 = QStandardItem("item" + str(i))
            item4.setTextAlignment(Qt.AlignCenter)
            item5 = QStandardItem("item" + str(i))
            item5.setTextAlignment(Qt.AlignCenter)
            self.model.appendRow([item1, item2, item3, item4, item5])

    def table(self):
        # ...

【讨论】:

感谢您的回复,非常好。但是计时器就是一个例子。发生的情况是我的应用程序有很多数据并且应用程序冻结了一段时间。我希望您在没有 qtimer 的情况下出现的信息。例如在 main.py 中,数量为 100000 或 20000,它在桌子上打印而不会冻结 @AbelJM 可以将定时器间隔设置为0。 @alec mmm,如果您想要更详细的答案,请提供更好的 MRE @eyllanesc 非常感谢您的及时回答。你的帮助会对我有很大帮助。我会用你在这个问题中给出的答案来补充它。 https://***.com/questions/52308937

以上是关于通过循环不断更新QTableView的主要内容,如果未能解决你的问题,请参考以下文章

通过 for 循环执行立即更新

通过应用程序不断更新数据库,效率不高?

php 通过循环更新

循环通过 IP 地址时 UI 未更新

vue中 数组通过循环添加新属性页面不更新

循环更新查询 pdo where id