详解pyqt5 动画在QThread线程中无法运行问题


Posted in Python onMay 05, 2018

自己做了一个tcp工具,在学习动画的时候踩了坑,需求是根据上线变绿色,离线变灰色,如果连接断开了,则变为灰色

问题现象:

详解pyqt5 动画在QThread线程中无法运行问题

可以看到点击“连接”,“离线”的时候动画是正常的,但是当tcp超时断开后,虽然离线按钮变为连接了,却没有执行离线动画

关键源代码如下

class BSJTcpThread(QtCore.QThread):
  recv_signal = QtCore.pyqtSignal(str)
  send_signal = QtCore.pyqtSignal(str)

  def __init__(self, socketcp, onBtn, heartcheck, senBtn, scene):
    super().__init__()
    self.s = socketcp
    self.yqtool = Bianlifunction()
    self.onBtn = onBtn
    self.heartcheck = heartcheck
    self.sendBtn = senBtn
    self.scene1 = scene

  def run(self):
    """线程"""
    global stopsingle
    stopsingle = 0
    while 1:
      btcpreceive = self.s.recv(1024)
      tcpreceive1 = str(binascii.b2a_hex(btcpreceive), encoding="utf-8")

      tcpreceive = ""
      i = 0
      while i < len(tcpreceive1) - 1: # 十六进制数据处理,两个字节隔开
        if i == len(tcpreceive1) - 2:
          tcpreceive += tcpreceive1[i:i + 2]
          i += 2
        else:
          tcpreceive += tcpreceive1[i:i + 2] + " "
          i += 2

      if tcpreceive == "":
        stopsingle = 1
        self.s.shutdown(2)
        self.s.close()
        self.onBtn.setText("连接")
        self.scene1.offlineCol.start() # 启动离线动画
        self.heartcheck.setChecked(False)
        self.heartcheck.setVisible(False)
        self.sendBtn.setDisabled(True)
      else:
        self.recv_signal.emit(tcpreceive)
      if stopsingle == 1:
        break

然后再启动线程

self.tcpth = BSJTcpThread(self.s, self.onBtn, self.heartcheck, self.sendBtn, self.scene)
      self.tcpth.recv_signal.connect(self.fillrecvmsg)
      self.tcpth.send_signal.connect(self.fillsendmsg)
      self.tcpth.start()

问题点:

经过谷爹搜索,终于找到了问题原因详见https://stackoverflow.com/questions/44328750/pyqt-qgraphicscene-move-item-in-background-thread

大致原因就是QGraphics Scene 不是一个安全的线程对象,我们不能直接在线程中去改变主程序的状态,我们必须通过信号的方式去更新QGraphics

解决方法:

首先,我们编辑一个信号方法

def threadAnimate(self, message):
    if message == "1":
      self.scene.offlineCol.start()

然后添加相关信号槽

self.tcpth = BSJTcpThread(self.s, self.onBtn, self.heartcheck, self.sendBtn)
      self.tcpth.recv_signal.connect(self.fillrecvmsg)
      self.tcpth.send_signal.connect(self.fillsendmsg)
      self.tcpth.animate_signal.connect(self.threadAnimate) # 添加一个动画信号
      self.tcpth.start()

在线程中发出离线动画的信号

class BSJTcpThread(QtCore.QThread):
  recv_signal = QtCore.pyqtSignal(str)
  send_signal = QtCore.pyqtSignal(str)
  animate_signal = QtCore.pyqtSignal(str)

  def __init__(self, socketcp, onBtn, heartcheck, senBtn):
    super().__init__()
    self.s = socketcp
    self.yqtool = Bianlifunction()
    self.onBtn = onBtn
    self.heartcheck = heartcheck
    self.sendBtn = senBtn

  def run(self):
    """线程"""
    global stopsingle
    stopsingle = 0
    while 1:
      btcpreceive = self.s.recv(1024)
      tcpreceive1 = str(binascii.b2a_hex(btcpreceive), encoding="utf-8")

      tcpreceive = ""
      i = 0
      while i < len(tcpreceive1) - 1: # 十六进制数据处理,两个字节隔开
        if i == len(tcpreceive1) - 2:
          tcpreceive += tcpreceive1[i:i + 2]
          i += 2
        else:
          tcpreceive += tcpreceive1[i:i + 2] + " "
          i += 2

      if tcpreceive == "":
        stopsingle = 1
        self.s.shutdown(2)
        self.s.close()
        self.onBtn.setText("连接")
        self.animate_signal.emit("1")
        self.heartcheck.setChecked(False)
        self.heartcheck.setVisible(False)
        self.sendBtn.setDisabled(True)
      else:
        self.recv_signal.emit(tcpreceive)
      if stopsingle == 1:
        break

然后就可以了,这个和QThread多线程收发消息原理一样

详解pyqt5 动画在QThread线程中无法运行问题

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现文件快照加密保护的方法
Jun 30 Python
浅谈python类属性的访问、设置和删除方法
Jul 25 Python
Python判断对象是否相等及eq函数的讲解
Feb 25 Python
python调用动态链接库的基本过程详解
Jun 19 Python
使用Python画股票的K线图的方法步骤
Jun 28 Python
python爬取盘搜的有效链接实现代码
Jul 20 Python
Numpy数组array和矩阵matrix转换方法
Aug 05 Python
Python猴子补丁知识点总结
Jan 05 Python
Python pip安装第三方库实现过程解析
Jul 09 Python
Python爬虫之爬取淘女郎照片示例详解
Jul 28 Python
python画图时设置分辨率和画布大小的实现(plt.figure())
Jan 08 Python
Pygame Time时间控制的具体使用详解
Nov 17 Python
python中in在list和dict中查找效率的对比分析
May 04 #Python
Django如何配置mysql数据库
May 04 #Python
Python实现求一个集合所有子集的示例
May 04 #Python
python list是否包含另一个list所有元素的实例
May 04 #Python
Python判断两个list是否是父子集关系的实例
May 04 #Python
python判断一个集合是否为另一个集合的子集方法
May 04 #Python
python3 判断列表是一个空列表的方法
May 04 #Python
You might like
德生PL330的评价与改造
2021/03/02 无线电
PHP UTF8中文字符截断函数代码
2012/09/11 PHP
PHP使用array_multisort对多个数组或多维数组进行排序
2014/12/16 PHP
从刷票了解获得客户端IP的方法
2015/09/21 PHP
PHP时间相关常用函数用法示例
2020/06/03 PHP
js 图片缩放(按比例)控制代码
2009/05/27 Javascript
js加载之使用DOM方法动态加载Javascript文件
2013/11/08 Javascript
createTextRange()的使用示例含文本框选中部分文字内容
2014/02/24 Javascript
JS实现的不规则TAB选项卡效果代码
2015/09/18 Javascript
js和jquery分别验证单选框、复选框、下拉框
2015/12/17 Javascript
javascript中JSON.parse()与eval()解析json的区别
2016/05/19 Javascript
JavaScript中自带的 reduce()方法使用示例详解
2016/08/10 Javascript
NodeJS远程代码执行
2016/08/28 NodeJs
总结AngularJS开发者最常犯的十个错误
2016/08/31 Javascript
Vue2.0实现1.0的搜索过滤器功能实例代码
2017/03/20 Javascript
Javascript ES6中数据类型Symbol的使用详解
2017/05/02 Javascript
Angular实现预加载延迟模块的示例
2017/10/12 Javascript
Vue render渲染时间戳转时间,时间转时间戳及渲染进度条效果
2018/07/27 Javascript
解决Vue2.0中使用less给元素添加背景图片出现的问题
2018/09/03 Javascript
小程序云开发如何实现图片上传及发表文字
2019/05/17 Javascript
vue监听用户输入和点击功能
2019/09/27 Javascript
vue+elementUI组件table实现前端分页功能
2020/11/15 Javascript
VSCode写vue项目一键生成.vue模版,修改定义其他模板的方法
2020/04/17 Javascript
小程序实现多个选项卡切换
2020/06/19 Javascript
python二叉树遍历的实现方法
2013/11/21 Python
整理Python最基本的操作字典的方法
2015/04/24 Python
numpy自动生成数组详解
2017/12/15 Python
Python爬虫获取整个站点中的所有外部链接代码示例
2017/12/26 Python
python中的协程深入理解
2019/06/10 Python
Python八皇后问题解答过程详解
2019/07/29 Python
超实用的 30 段 Python 案例
2019/10/10 Python
python利用tkinter实现图片格式转换的示例
2020/09/28 Python
美国咖啡批发网站:Coffee.org
2017/06/29 全球购物
安全教育心得体会
2013/12/29 职场文书
通用自荐信范文
2014/03/14 职场文书
如何vue使用el-table遍历循环表头和表体数据
2022/04/26 Vue.js