一、测试程序界面
二、不使用多线程代码如下(当点击开启日志的时候,直接导致界面卡死)
#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()