Python中WebSocket的on_message函数无法更新TableWidget数据
问题分析
你的代码存在两个核心问题导致表格无法更新:
- 主线程被阻塞:
ws.run_forever()会阻塞调用它的主线程(按钮点击事件在主线程执行),导致Qt的UI事件循环无法正常运转,界面卡死,无法刷新表格内容。 - 跨线程操作UI:WebSocket的
on_message回调在WebSocket工作线程中执行,而PySide要求所有UI操作必须在主线程中进行,跨线程直接修改UI组件会导致数据无法显示或界面异常。
解决方案
通过子线程运行WebSocket+信号槽机制传递数据解决上述问题:
- 将WebSocket的初始化和运行逻辑移到
QThread子类中,避免阻塞主线程。 - 定义自定义信号,在
on_message回调中发射信号传递行情数据。 - 在主线程中连接信号到槽函数,安全更新TableWidget。
修改后的完整代码
from PySide6.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem from PySide6.QtCore import QThread, Signal # Important: # You need to run the following command to generate the ui_form.py file # pyside6-uic form.ui -o ui_form.py, or # pyside2-uic form.ui -o ui_form.py from ui_form import Ui_Widget import websocket import json import sys class WebSocketWorker(QThread): # 自定义信号:传递资产名称与对应价格 price_update = Signal(str, str) def __init__(self): super().__init__() self.ws = None def run(self): # 在子线程中初始化并启动WebSocket self.ws = websocket.WebSocketApp( "wss://stream.binance.com:9443/stream?streams=adausdt@ticker/dotusdt@ticker/xrpusdt@ticker/roseusdt@ticker/runeusdt@ticker/avaxusdt@ticker/xlmusdt@ticker/hbarusdt@ticker/fluxusdt@ticker/qntusdt@ticker/linkusdt@ticker", on_message=self.on_message, on_error=self.on_error, on_close=self.on_close ) self.ws.run_forever() def on_message(self, ws, message): data = json.loads(message) current_asset = data['data']['s'] current_price = data['data']['c'] print(current_asset, current_price) # 发射信号,将数据传递到主线程 self.price_update.emit(current_asset, current_price) def on_error(self, ws, error): print(error) def on_close(self, ws): print("WebSocket closed") class Widget(QWidget): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_Widget() self.ui.setupUi(self) self.ui.pushButton.clicked.connect(self.start_websocket) # 初始化WebSocket工作线程 self.ws_worker = WebSocketWorker() # 连接信号到UI更新槽函数 self.ws_worker.price_update.connect(self.update_table) # 确保表格有足够的行和列(根据你的需求调整) self.ui.tableWidget.setRowCount(2) self.ui.tableWidget.setColumnCount(2) # 可以设置表头 self.ui.tableWidget.setHorizontalHeaderLabels(["资产", "价格"]) def start_websocket(self): # 启动子线程(避免重复启动) if not self.ws_worker.isRunning(): self.ws_worker.start() def update_table(self, asset, price): # 主线程中安全更新表格 if asset == 'ADAUSDT': self.ui.tableWidget.setItem(0, 0, QTableWidgetItem(asset)) self.ui.tableWidget.setItem(0, 1, QTableWidgetItem(price)) elif asset == 'DOTUSDT': self.ui.tableWidget.setItem(1, 0, QTableWidgetItem(asset)) self.ui.tableWidget.setItem(1, 1, QTableWidgetItem(price)) def closeEvent(self, event): # 窗口关闭时清理WebSocket线程 if self.ws_worker.isRunning(): self.ws_worker.ws.close() self.ws_worker.quit() self.ws_worker.wait() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) widget = Widget() widget.show() sys.exit(app.exec())
关键修改说明
- 子线程隔离WebSocket:将WebSocket逻辑放到
QThread子类中,调用start()启动子线程,避免阻塞主线程的UI事件循环。 - 信号传递数据:通过自定义信号将行情数据从WebSocket线程传递到主线程,确保UI操作在主线程执行,符合PySide的线程安全要求。
- 表格初始化:添加表格行、列初始化代码,避免因表格无足够行列导致
setItem失效。 - 资源清理:重写
closeEvent,在窗口关闭时关闭WebSocket并停止子线程,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Christian_uy
相关产品推荐
相关产品推荐

