Python的子线程与主线程之间的通信并通知主线程更新UI

news/2025/2/24 20:25:17

新建PLC类 PLC.py

python">import json
import time
from threading import Thread

from HslCommunication import SiemensS7Net, SiemensPLCS
from PySide6.QtCore import QThread, Signal, QObject

from tdm.MsgType import MSG_TYPE_LOG, MSG_TYPE_MSGBOX


# 自定义信号类,用于与主线程进行交互
class WorkSingle(QObject):
    msg = Signal(str)


class PLC(QThread):
    def __init__(self, address, port):
        super().__init__()
        self.siemens = None  # 西门子对象
        self.connected_plc = None  # 是否连接上了PLC
        self.signal = WorkSingle() # 信道,与主线程通信
        self.address = address # PLC IP地址
        self.port = port # PLC 连接端口

    # 发送日志消息
    def send_log_msg(self, msg):
        data = {
            "type": MSG_TYPE_LOG,
            "msg": msg,
        }
        self.signal.msg.emit(json.dumps(data))

    # 发送弹窗类消息
    def send_dialog_msg(self, msg):
        data = {
            "type": MSG_TYPE_MSGBOX,
            "msg": msg,
        }
        self.signal.msg.emit(json.dumps(data))

    def init_plc_connect(self):
        self.siemens = SiemensS7Net(SiemensPLCS.S1200, self.address)
        self.siemens.port = int(self.port)
        connect = self.siemens.ConnectServer()
        if not connect.IsSuccess:
            self.connected_plc = False
            # print('初始化 PLC 连接失败: ' + connect.ToMessageShowString())
            self.send_log_msg('初始化 PLC 连接失败: ' + connect.ToMessageShowString())
        else:
            self.connected_plc = True
            print("初始化 PLC 连接成功!")
            self.send_log_msg("初始化 PLC 连接成功!")

    def run(self):
        self.init_plc_connect()  # 初始化PLC连接
        if not self.connected_plc:
            print("PLC连接失败,不能连续读取")
            self.send_log_msg("PLC连接失败,不能连续读取")
            return
        print("TODO 开始连续读取PLC值")
        self.send_dialog_msg("AAAAA")
        Thread(target=self.read_plc_value).start()
        print("即将执行耗时操作,读取完毕1")
        self.send_log_msg("即将执行耗时操作,开启新的线程去执行")
        self.send_dialog_msg("CCCCC")

    def read_plc_value(self):
        time.sleep(10)
        print(self.port)
        self.send_dialog_msg("BBBBBBBB")
        print("耗时操作,读取完毕")
        self.send_log_msg("耗时操作,读取完毕")

创建 TDMSocketClient.py

python">import asyncio
import json
import time
import traceback
from threading import Thread

import websockets
from PyQt6.QtCore import QThread
from PySide6.QtCore import QObject, Signal

from tdm.MsgType import MSG_TYPE_LOG


# 自定义信号类,用于与主线程进行交互
class WorkSingle(QObject):
    msg = Signal(str)


class TDMSocketClient(QThread):
    def __init__(self, ip, port):
        QThread.__init__(self)
        self.ip = ip
        self.port = port
        self.signal = WorkSingle()

    def run(self):
        # 启动 WebSocket 客户端连接服务器,用于接受服务器发来的试验通知
        Thread(target=self.runWSClient).start()

    def send_log_msg(self, msg):
        data = {
            "type": MSG_TYPE_LOG,
            "msg": msg,
        }
        self.signal.msg.emit(json.dumps(data))

    def runWSClient(self):
        # 下面的语句替换上面这一句,就不会报错啦,成功率高
        new_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(new_loop)
        loop = asyncio.get_event_loop()
        task = asyncio.ensure_future(self.ws_client())
        loop.run_until_complete(asyncio.wait([task]))
        st = task.result()

    async def ws_client(self):
        try:
            uri = 'ws://' + self.ip + ':' + self.port + '/tdm/websocket/JZ076'
            async with websockets.connect(uri) as websocket:
                # localClient.setSuccessStatus("websocket 连接成功!")
                print('Connected to ' + self.ip + ':' + self.port + "success")
                self.send_log_msg('Connected to ' + self.ip + ':' + self.port + "success")
                while True:
                    result = await websocket.recv()
                    msg = json.loads(result)
                    try:
                        if msg["cmd"] == "startTest":
                            print("开始试验")
                            # 开始试验
                            # localClient.startTest(msg['testInsId'])
                        elif msg["cmd"] == "pauseTest":
                            # 暂停试验
                            # localClient.testPause()
                            print("暂停试验")
                        elif msg["cmd"] == "stopTest":
                            print("停止试验")
                            # 停止试验
                            # localClient.testStop()
                    except:
                        # 报错的话自动重连
                        traceback.print_exc()

        except:
            # 报错的话自动重连
            traceback.print_exc()
            time.sleep(1)
            await self.ws_client()

主类 TDMClient.py

python">'''
TDM 客户端
'''
import json
from typing import Final

from PyQt6.QtWidgets import QMessageBox
from PySide6.QtCore import QFile
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication

from tdm.MsgType import MSG_TYPE_LOG, MSG_TYPE_MSGBOX
from tdm.PLC import PLC
from tdm.TDMSocketClient import TDMSocketClient


PLC_ADDRESS: Final = "192.168.1.83"
PLC_PORT: Final = "102"

WS_SERVICE_ADDRESS: Final = "localhost"
WS_SERVICE_PORT: Final = "8080"

# 显示弹窗
def show_msg_box(msg):
    mb = QMessageBox()
    mb.setText(msg)
    mb.exec()


class TDMClient:
    def __init__(self):
        # 获取设计文件
        qf = QFile('ui/TDMLocalClient.ui')
        qf.open(QFile.ReadOnly)
        qf.close()
        # 将设计文件加载为窗口
        self.ui = QUiLoader().load(qf)

        # PLC 读取相关
        self.plc = PLC(PLC_ADDRESS, PLC_PORT)
        self.plc.signal.msg.connect(self.receive_signal)

        self.ws = TDMSocketClient(WS_SERVICE_ADDRESS, WS_SERVICE_PORT)
        self.ws.signal.msg.connect(self.receive_signal)

    def run(self):
        self.ui.show()  # 显示客户端
        self.plc.run()  # 获取试验器的点位列表,并连续读取
        self.ws.run()  # 启动 WebSocket 客户端服务,用于接收服务器发来的 试验开始、试验暂停、试验停止等信息

    # 收到子线程信号是触发(唯一方法入口)
    def receive_signal(self, msg):
        msg_obj = json.loads(msg)
        if msg_obj['type'] == MSG_TYPE_LOG:
            self.ui.retView.appendPlainText(str(msg_obj['msg']))
        elif msg_obj['type'] == MSG_TYPE_MSGBOX:
            show_msg_box(str(msg_obj['msg']))


app = QApplication([])
tdmClient = TDMClient()
tdmClient.run()
app.exec()

http://www.niftyadmin.cn/n/5864790.html

相关文章

ElasticSearch查询指南:从青铜到王者的骚操作

ElasticSearch查询指南:从青铜到王者的骚操作 本文来源于笔者的CSDN原创,由于掘金>已经去掉了转载功能,所以只好重新上传,以下图片依然保持最初发布的水印(如CSDN水印)。(以后属于本人原创均…

vue-fastapi-admin 部署心得

vue-fastapi-admin 部署心得 这两天需要搭建一个后台管理系统,找来找去 vue-fastapi-admin 这个开源后台管理框架刚好和我的技术栈所契合。于是就浅浅的研究了一下。 主要是记录如何基于原项目提供的Dockerfile进行调整,那项目文件放在容器外部&#xf…

基于Spring Boot的公司资产网站设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…

从零实现机器人自主避障

1. 编译工具安装 sudo apt update sudo apt install python3-catkin-pkg python3-rosdep python3-rosinstall-generator python3-wstool python3-rosinstall build-essential sudo rosdep init rosdep update2. 构建节点 mkdir -p ~/ros2_ws/src cd ~/ros2_ws ros2 pkg creat…

mysql之B+ 树索引 (InnoDB 存储引擎)机制

b树索引机制 B 树索引 (InnoDB 存储引擎)机制**引言:****1. 数据页结构与查找**2. 索引的引入**3. InnoDB 的 B 树索引****4. InnoDB B 树索引的注意事项****5. MyISAM 的索引方案 (选读,与 InnoDB 做对比)****6. MySQL 中创建和删除索引的语句** **B 树…

使用Socket编写超牛的http服务器和客户端(二)

客户端 动态扩展连接池、线程池优雅关闭、超时机制、健康检查等功能,并将代码模块化: 文件结构 HTTPClientProject/ ├── ConnectionPool.h ├── ConnectionPool.cpp ├── TaskQueue.h ├── ThreadPool.h ├── main.cpp 工程代码主要分为以下几个模块: Connectio…

go执行java -jar 完成DSA私钥解析并签名

起因,最近使用go对接百度联盟api需要使用到DSA私钥完成签名过程,在百度提供的代码示例里面没有go代码的支持,示例中仅有php、python2和3、java的代码,网上找了半天发现go中对DSA私钥解析支持不友好,然后决定使用在java…

微信小程序页面导航与路由:实现多页面跳转与数据传递

在上一篇中,我们学习了微信小程序的数据绑定和事件处理,实现了动态交互功能。然而,一个完整的小程序通常由多个页面组成,用户需要在不同页面之间进行跳转。本文将深入探讨微信小程序的页面导航与路由机制,帮助你实现多…