wxPython多线程界面卡死或在不同平台崩溃问题

一、测试程序界面

 

二、不使用多线程代码如下(当点击开启日志的时候,直接导致界面卡死)

#coding:utf-8
import sys
import threading
import time
import wx

class MyWindow():
    def __init__(self):
        self.app = None
        self.frame = None
        self.logObj = None
        self.main()

    def main(self):
        self.app = wx.App()
        self.frame = wx.Frame(None, -1, title='线程安全测试', size=wx.Size(1100, 700))
        self.createMainPanel()

    def show(self):
        self.frame.Show()
        self.app.MainLoop()

    def createMainPanel(self):
        mainPanel = wx.Panel(self.frame)
        startButton = wx.Button(mainPanel, label="启动", pos=(5, 5))
        openLogButton = wx.Button(mainPanel, label="开启日志", pos=(95, 5))
        closeLogButton = wx.Button(mainPanel, label="关闭日志", pos=(180, 5))

        self.logTextCtr = wx.TextCtrl(mainPanel, size=wx.Size(1000, 500), pos=(5,50),style=wx.TE_MULTILINE)

        self.frame.Bind(wx.EVT_BUTTON, lambda evt, textArea=self.logTextCtr: self.startBut(evt,self.logTextCtr),
                        startButton)
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.startLog(evt),
                        openLogButton)
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.closeLog(evt),
                        closeLogButton)

    def startBut(self,evt,textArea):
        self.logObj = LogPrint(textArea)

    def startLog(self,evt):
        self.logObj.toPrint()
    def closeLog(self,evt):
        self.logObj.setIsPrint(0)


class LogPrint():
    def __init__(self,textArea):
        self.isPrint = 0
        self.textArea = textArea

    def toPrint(self):
        self.isPrint = 1
        i = 0
        while self.isPrint == 1:
            j = str(i) + " this is log!"
            self.textArea.WriteText(j + "\n")
            i = i + 1
            time.sleep(1)

    def setIsPrint(self,data):
        self.isPrint = data

if __name__ == "__main__":
    MyWindow().show()

三、使用threading多线程后,界面不会卡死,在windows下运行启动后界面可正常操作不会阻塞;但是在linux或mac下面点击开启日志后程序直接崩溃,代码如下:

#coding:utf-8
import sys
import threading
import time
import wx

class MyWindow():
    def __init__(self):
        self.app = None
        self.frame = None
        self.logObj = None
        self.main()

    def main(self):
        self.app = wx.App()
        self.frame = wx.Frame(None, -1, title='线程安全测试', size=wx.Size(1100, 700))
        self.createMainPanel()

    def show(self):
        self.frame.Show()
        self.app.MainLoop()

    def createMainPanel(self):
        mainPanel = wx.Panel(self.frame)
        startButton = wx.Button(mainPanel, label="启动", pos=(5, 5))
        openLogButton = wx.Button(mainPanel, label="开启日志", pos=(95, 5))
        closeLogButton = wx.Button(mainPanel, label="关闭日志", pos=(180, 5))

        self.logTextCtr = wx.TextCtrl(mainPanel, size=wx.Size(1000, 500), pos=(5,50),style=wx.TE_MULTILINE)

        self.frame.Bind(wx.EVT_BUTTON, lambda evt, textArea=self.logTextCtr: self.startBut(evt,self.logTextCtr),
                        startButton)
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.startLog(evt),
                        openLogButton)
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.closeLog(evt),
                        closeLogButton)

    def startBut(self,evt,textArea):
        self.logObj = LogPrint(textArea)

    def startLog(self,evt):
        threadObj = threading.Thread(target=self.dolog, args=())
        threadObj.start()
        #self.logObj.toPrint()
    def dolog(self):
        self.logObj.toPrint()
    def closeLog(self,evt):
        self.logObj.setIsPrint(0)


class LogPrint():
    def __init__(self,textArea):
        self.isPrint = 0
        self.textArea = textArea

    def toPrint(self):
        self.isPrint = 1
        i = 0
        while self.isPrint == 1:
            j = str(i) + " this is log!"
            self.textArea.WriteText(j + "\n")
            i = i + 1
            time.sleep(1)

    def setIsPrint(self,data):
        self.isPrint = data

if __name__ == "__main__":
    MyWindow().show()

四、解决卡死或不同平台崩溃问题(使用wxpython中CallAfter自带多线程,以及pubsub进行线程之间消息通讯来实现)

python3多线程threading功能强大,结合jion()和setDaemon()函数使用更灵活,使用多线程时首先想到了threading, 但wxpython是用python写的一个UI框架,其本身自带有多线程函数:

  • wx.PostEvent
  • wx.CallAfter
  • wx.CallLater

其中,wx.CallLater是最抽象的线程安全函数,其次是callAfter,最后是PostEvent。舍去这三个,直接使用threading导致UI出现卡顿,卡死等情况。结合wxpython自带的多线程函数效果很好。

pubsub模块中,pub.subscribe 可以理解为注册一个接收消息的方法;pub.sendMessage 可以理解为发送消息给上一步注册的方法

实现代码:

#coding:utf-8

import sys
import threading
import time

import wx
from wx.lib.pubsub import pub

class MyWindow():

    def __init__(self):
        self.app = None
        self.frame = None
        self.logObj = None
        self.main()

    def main(self):
        self.app = wx.App()
        self.frame = wx.Frame(None, -1, title='线程安全测试', size=wx.Size(1100, 700))
        self.createMainPanel()

    def show(self):
        self.frame.Show()
        self.app.MainLoop()

    def createMainPanel(self):
        mainPanel = wx.Panel(self.frame)
        startButton = wx.Button(mainPanel, label="启动", pos=(5, 5))
        openLogButton = wx.Button(mainPanel, label="开启日志", pos=(95, 5))
        closeLogButton = wx.Button(mainPanel, label="关闭日志", pos=(180, 5))

        self.logTextCtr = wx.TextCtrl(mainPanel, size=wx.Size(1000, 500), pos=(5,50),style=wx.TE_MULTILINE)

        self.frame.Bind(wx.EVT_BUTTON, lambda evt, textArea=self.logTextCtr: self.startBut(evt,self.logTextCtr),
                        startButton)
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.startLog(evt),
                        openLogButton)
        self.frame.Bind(wx.EVT_BUTTON, lambda evt: self.closeLog(evt),
                        closeLogButton)
        pub.subscribe(self.updateDisplay, "update")

    def startBut(self,evt,textArea):
        self.logObj = LogPrint()

    def startLog(self,evt):
        threadObj = threading.Thread(target=self.dolog, args=())
        threadObj.start()
    def dolog(self):
        self.logObj.toPrint()
    def updateDisplay(self, msg):
        t = msg
        self.logTextCtr.WriteText(t + "\n")
    def closeLog(self,evt):
        self.logObj.setIsPrint(0)


class LogPrint():
    def __init__(self):
        self.isPrint = 0

    def toPrint(self):
        self.isPrint = 1
        i = 0
        while self.isPrint == 1:
            j = str(i) + " this is log!"
            wx.CallAfter(pub.sendMessage, "update", msg=j)
            print(j)
            i = i + 1
            time.sleep(1)
            
    def setIsPrint(self,data):
        self.isPrint = data

if __name__ == "__main__":
    MyWindow().show()

 

 

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值