如何在QWidget类的函数中使用QThread实现表格实时更新?
解决方案
核心原则:Qt 所有 GUI 控件的读写、修改操作必须在主线程执行,绝对不能在子线程中直接操作
QTableWidget等控件,否则会出现随机崩溃、渲染异常等不可预期的问题。
你的需求可以按照标准的 Worker + moveToThread 方案实现,只需要把「拉取实时数据」和「更新UI」逻辑解耦即可,不需要把主窗口绑定的控件对象传到子线程:
- 数据拉取逻辑放到子线程的
Worker类中执行,拉取到数据后通过自定义信号传递给主线程 - 主线程收到信号后,再执行表格更新逻辑
以下是修改后的完整可运行代码:
import utility from PyQt5.QtWidgets import * from PyQt5.QtCore import Qt, QThread, QObject, pyqtSignal import sys class Worker(QObject): # 定义信号,用于将拉取到的行情数据传递到主线程 data_ready = pyqtSignal(dict) finished = pyqtSignal() def __init__(self): super().__init__() # 线程运行标志位,用于控制循环启停 self.is_running = True def run(self): while self.is_running: # 子线程只负责拉取数据,不碰任何UI控件 market = utility.get_live_data() # 发送数据到主线程 self.data_ready.emit(market) # 可根据需求调整拉取间隔,示例为间隔1秒拉取一次 QThread.msleep(1000) self.finished.emit() class mainUI(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent, Qt.WindowStaysOnTopHint) self.setMinimumSize(1000, 500) self.table_live = QTableWidget() self.table_live.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_live.setColumnCount(6) self.table_live.setHorizontalHeaderLabels( ['Name', 'Quantity', 'Discount Price', 'Market Price', 'Change', 'P/L'] ) self.layout = QHBoxLayout() self.layout.addWidget(self.table_live) self.setLayout(self.layout) # 初始化Worker和线程 self.worker = Worker() self.update_thread = QThread() # 将worker迁移到子线程 self.worker.moveToThread(self.update_thread) # 绑定信号槽 self.update_thread.started.connect(self.worker.run) self.worker.data_ready.connect(self.update_table_live) # 线程退出相关信号绑定,避免内存泄漏 self.worker.finished.connect(self.update_thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.update_thread.finished.connect(self.update_thread.deleteLater) # 启动线程 self.update_thread.start() def update_table_live(self, market): """主线程中负责更新表格的槽函数,只处理UI逻辑""" self.table_live.setRowCount(0) for name, product_data in market.items(): row_count = self.table_live.rowCount() self.table_live.insertRow(row_count) item_name = QTableWidgetItem(name) item_quantity = QTableWidgetItem(product_data['quantity']) item_discount = QTableWidgetItem(product_data['discount']) item_current = QTableWidgetItem(product_data['price']) item_change = QTableWidgetItem(product_data['change']) item_pl = QTableWidgetItem(product_data['p_l']) self.table_live.setItem(row_count, 0, item_name) self.table_live.setItem(row_count, 1, item_quantity) self.table_live.setItem(row_count, 2, item_discount) self.table_live.setItem(row_count, 3, item_current) self.table_live.setItem(row_count, 4, item_change) self.table_live.setItem(row_count, 5, item_pl) def closeEvent(self, event): """重写窗口关闭事件,保证线程正常退出""" self.worker.is_running = False self.update_thread.wait() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) win = mainUI() win.show() app.exec_()
内容的提问来源于stack exchange,提问作者mehulJ
相关产品推荐
相关产品推荐

