Python PYserial WxPython Threading - python

Can any one please tell me whats wrong with this piece of code.
When I press button 1 - everything is good. I want to press button2 - to stop the process started by button 1 and do an another process. I am unable to do it - MY GUI is going irresponsive.
You are welcome to edit the serial communication with PRINT statements if you like in doit and doit2 functions.
Please dont comment about how I made the GUI - it is just a quick example. Please comment on why I am unable to pass the pill2kill - when I press the button 2. And why my GUI is going to irresponsive state.
import threading
import time
import numpy as np
import serial
from Transmit import Write
from Receive import Read
import struct
import time
import serial.tools.list_ports
import wx
class windowClass(wx.Frame):
def __init__(self, parent, title):
appSize_x = 1100
appSize_y = 800
super(windowClass, self).__init__(parent, title = title, style = wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CLOSE_BOX |wx.CAPTION, size = (appSize_x, appSize_y))
self.basicGUI()
self.Centre()
self.Show()
def basicGUI(self):
# Main Panel
panel1 = wx.Panel(self)
panel1.SetBackgroundColour('#D3D3D3')
firmware_version = wx.StaticText(panel1, -1, "RANDOM1", pos = (70, 10) )
firmware_version_text_control = wx.TextCtrl(panel1, -1, size = (70,25), pos = (105,40))
pump_model_serial_number = wx.StaticText(panel1, -1, "RANDOM2", pos=(25, 75))
pump_model_serial_number.SetBackgroundColour('yellow')
model = wx.StaticText(panel1, -1, "RANDOM3", pos=(110, 100))
self.listbox = wx.ListBox(panel1, -1, size = (300,250), pos = (20,135))
clear_history = wx.Button(panel1, -1, 'BUTTON1', size = (225,30), pos = (40, 400))
clear_history.SetBackgroundColour('RED')
clear_history.Bind(wx.EVT_BUTTON, self.OnClearHistory)
clear_history2 = wx.Button(panel1, -1, 'BUTTON2', size=(225, 30), pos=(40, 500))
clear_history2.SetBackgroundColour('GREEN')
clear_history2.Bind(wx.EVT_BUTTON, self.OnClearHistory2)
def OnClearHistory(self, event):
self.pill2kill = threading.Event()
self.t = threading.Thread(target=self.doit, args=(self.pill2kill, "task"))
self.t.start()
self.t.join()
def OnClearHistory2(self, event):
self.pill2kill.set()
self.t1 = threading.Thread(target=self.doit2)
self.t1.start()
time.sleep(5)
self.t1.join()
def doit(self, stop_event, arg):
while not stop_event.wait(1):
print ("working on %s" % arg)
ser = serial.Serial(3, 115200)
c = ser.write('\x5A\x03\x02\x02\x02\x09')
print c
d = ser.read(7)
print d.encode('hex')
ser.close()
print("Stopping as you wish.")
def doit2(self):
#print ("working on %s" % arg)
ser = serial.Serial(3, 115200)
c = ser.write('\x5A\x03\x02\x08\x02\x0F') # Writing to an MCU
print c
d = ser.read(7)
print d.encode('hex')
ser.close()
def random():
app = wx.App()
windowClass(None, title='random')
app.MainLoop()
random()

Don't use the .join commands. They are blocking the main thread.
See this SO question for an in depth description:
what is the use of join() in python threading

Thread.join will block until the thread terminates. If your GUI's event handlers are blocked and unable to return to the MainLoop then other events can not be received and dispatched, and so the application appears to be frozen.

Related

Good approach for updating the GUI continuously in wxPython using threads?

I am working on a GUI app using python v2.7 and wxPython v3.0 on windows 7 OS.
I have to update my GUI continuously which contains lots of panels. Each panels contains a wx.StaticText. I have to update these wx.StaticTexts continuously. I thought of using threads. Also I am using pubsub module for communicating with the GUI to update these wx.StaticTexts. Every thing works as intended.
I have created a short demo below of my real problem.
Problem: In my code below, two threads are created. Both the threads are able to update the GUI using wx.CallAfter(). What if I have 100 panels to update? Do I need to create 100 classes for each of the thread which updates a particular panel? I want the threads to work independently of the other threads.
What will possibly be the better approach than this one?
Code: Please find the sample code below to play around:
import wx
from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
import time
from threading import Thread
import threading
class GUI(wx.Frame):
def __init__(self, parent, id, title):
screenWidth = 500
screenHeight = 400
screenSize = (screenWidth,screenHeight)
wx.Frame.__init__(self, None, id, title, size=screenSize)
self.locationFont = locationFont = wx.Font(12, wx.MODERN, wx.NORMAL, wx.BOLD)
mainSizer = wx.BoxSizer(wx.VERTICAL)
myPanelA = wx.Panel(self, style=wx.SIMPLE_BORDER)
myPanelA.SetBackgroundColour('#C0FAE0')
self.myTextA = wx.StaticText(myPanelA, -1, "I have a problem :( ")
myPanelB = wx.Panel(self, style=wx.SIMPLE_BORDER)
myPanelB.SetBackgroundColour('#C0FAFF')
self.myTextB = wx.StaticText(myPanelB, -1, "Me too :( ")
mainSizer.Add(myPanelA, 1, wx.EXPAND, 5)
mainSizer.Add(myPanelB, 1, wx.EXPAND, 5)
self.SetSizer(mainSizer)
pub.subscribe(self.updatePanelA, 'Update-panelA')
pub.subscribe(self.updatePanelB, 'Update-panelB')
def updatePanelA(self, message):
self.myTextA.SetLabel(message)
def updatePanelB(self, message):
self.myTextB.SetLabel(message)
class threadA(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
ObjA = updateGUI()
ObjA.methodA()
class threadB(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
ObjB = updateGUI()
ObjB.methodB()
class updateGUI():
def methodA(self):
while True:
time.sleep(3)
wx.CallAfter(pub.sendMessage, 'Update-panelA', message='Problem solved')
def methodB(self):
while True:
time.sleep(5)
wx.CallAfter(pub.sendMessage, 'Update-panelB', message='Mine too')
if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Problem Demo")
frame.Show()
threadA()
threadB()
app.MainLoop()
Thank you for your time!
You can define your private "selfUpdatePanel" to launch its own thread to update its own text field. The code would be easy maintain in this way.
Check following code modified based on your code:
import wx
from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
import time
from threading import Thread
import threading
class selfUpdatePanel(wx.Panel):
def __init__(self, parent, mystyle, interval, topic, message):
wx.Panel.__init__(self, parent, style = mystyle)
pub.subscribe(self.updatePanel, topic)
self.updateMsg = message
self.textCtrl = None
self.interval = interval
self.topic = topic
pub.subscribe(self.updatePanel, self.topic)
def setTextCtrl(self,text):
self.textCtrl = text
def updatePanel(self):
self.textCtrl.SetLabel(self.updateMsg)
def threadMethod(self):
while True:
print "threadMethod"
time.sleep(self.interval)
wx.CallAfter(pub.sendMessage, self.topic)
def startThread(self):
self.thread = Thread(target=self.threadMethod)
self.thread.start()
class GUI(wx.Frame):
def __init__(self, parent, id, title):
screenWidth = 500
screenHeight = 400
screenSize = (screenWidth,screenHeight)
wx.Frame.__init__(self, None, id, title, size=screenSize)
self.locationFont = locationFont = wx.Font(12, wx.MODERN, wx.NORMAL, wx.BOLD)
mainSizer = wx.BoxSizer(wx.VERTICAL)
#myPanelA = wx.Panel(self, style=wx.SIMPLE_BORDER)
myPanelA = selfUpdatePanel(self, wx.SIMPLE_BORDER, 3, 'Update-panelA', 'Problem solved')
myPanelA.SetBackgroundColour('#C0FAE0')
self.myTextA = wx.StaticText(myPanelA, -1, "I have a problem :( ")
myPanelA.setTextCtrl(self.myTextA)
#myPanelB = wx.Panel(self, style=wx.SIMPLE_BORDER)
myPanelB = selfUpdatePanel(self, wx.SIMPLE_BORDER, 5, 'Update-panelB', 'Mine too')
myPanelB.SetBackgroundColour('#C0FAFF')
self.myTextB = wx.StaticText(myPanelB, -1, "Me too :( ")
myPanelB.setTextCtrl(self.myTextB)
mainSizer.Add(myPanelA, 1, wx.EXPAND, 5)
mainSizer.Add(myPanelB, 1, wx.EXPAND, 5)
self.SetSizer(mainSizer)
myPanelB.startThread()
myPanelA.startThread()
if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Problem Demo")
frame.Show()
app.MainLoop()

Python thread runs even after closing WxPython application

the following code takes screenshots and logs keystrokes and mouse movements. It uses wxpython as GUI framework. I'm using python threads for screenshot and logging service. But whenever I close the GUI application. Threads are still running. How to stop those threads after closing the application?
import wx
import threading
import sys
import subprocess
import time
from pymouse import PyMouse
from pymouse import PyMouseEvent
from pykeyboard import PyKeyboard
from pykeyboard import PyKeyboardEvent
import pyscreenshot as ImageGrab
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import gtk.gdk
import urllib2, urllib
import Cookie
MouseMovesCount = 0
MouseClicksCount = 0
KeyStrokesCount = 0
class OD_App(wx.App):
def OnInit(self):
frame = OD_MainFrame ("Login", (0, 0), (350, 200))
self.SetTopWindow(frame)
loginPanel = OD_LoginPanel (frame)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
frame.Show()
return True
def OnCloseWindow (self, event):
self.Destroy()
class OD_MainFrame(wx.Frame):
def __init__(self, title, pos, size):
wx.Frame.__init__(self, None, -1, title, pos, size)
self.CreateStatusBar()
class OD_LoginPanel(wx.Panel):
def __init__(self, frame):
self.panel = wx.Panel(frame)
self.frame = frame
self.frame.SetStatusText("Authentication required!")
self.showLoginBox()
def showLoginBox (self):
# Create the sizer
sizer = wx.FlexGridSizer(rows=3, cols=2, hgap=5, vgap=15)
# Username
self.txt_Username = wx.TextCtrl(self.panel, 1, size=(150, -1))
lbl_Username = wx.StaticText(self.panel, -1, "Username:")
sizer.Add(lbl_Username,0, wx.LEFT|wx.TOP| wx.RIGHT, 50)
sizer.Add(self.txt_Username,0, wx.TOP| wx.RIGHT, 50)
# Password
self.txt_Password = wx.TextCtrl(self.panel, 1, size=(150, -1), style=wx.TE_PASSWORD)
lbl_Password = wx.StaticText(self.panel, -1, "Password:")
sizer.Add(lbl_Password,0, wx.LEFT|wx.RIGHT, 50)
sizer.Add(self.txt_Password,0, wx.RIGHT, 50)
# Submit button
btn_Process = wx.Button(self.panel, -1, "&Login")
self.panel.Bind(wx.EVT_BUTTON, self.OnSubmit, btn_Process)
sizer.Add(btn_Process,0, wx.LEFT, 50)
self.panel.SetSizer(sizer)
def OnSubmit(self, event):
username = self.txt_Username.GetValue()
password = self.txt_Password.GetValue()
mydata = [('username',username),('password',password)]
mydata = urllib.urlencode(mydata)
path = 'http://xyz/logincheck.php' #temporary db for testing
req = urllib2.Request(path, mydata)
req.add_header("Content-type", "application/x-www-form-urlencoded")
page = urllib2.urlopen(req).read()
if page == "true":
self.frame.SetStatusText("Authentication Success!")
self.show_other(username)
else:
self.frame.SetStatusText("Authentication Failed!")
def OnCloseWindow (self, event):
self.Destroy()
def show_other(self,username):
self.frame.Destroy()
userpanel = OD_UserPanel()
return True
class OD_UserPanel(wx.App):
def OnInit(self):
userpanel = wx.Frame(None,-1)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
#user_greeting = 'Welcome ' + username + '!'
#username = wx.StaticText(userpanel, -1, user_greeting , style=wx.ALIGN_CENTRE)
userpanel.Show()
mouse_eventer = mouse_event()
mouse_eventer.start()
keyboard_eventer = key_event()
keyboard_eventer.start()
screenshot_eventer = screenshot_thread()
screenshot_eventer.start()
return True
def OnCloseWindow (self, event):
quit()
event.Skip()
raise SystemExit
class mouse_event(PyMouseEvent):
def move(self, x, y):
global MouseMovesCount
MouseMovesCount = MouseMovesCount + 1
print MouseMovesCount
def click(self, x, y, button, press):
global MouseClicksCount
if press:
MouseClicksCount = MouseClicksCount + 1
print MouseClicksCount
else:
MouseClicksCount = MouseClicksCount + 1
print MouseClicksCount
class key_event(PyKeyboardEvent):
global screenshot_eventer
def key_press(self, key):
global KeyStrokesCount
KeyStrokesCount = KeyStrokesCount + 1
print KeyStrokesCount
def key_release(self, key):
global KeyStrokesCount
KeyStrokesCount = KeyStrokesCount + 1
print KeyStrokesCount
class screenshot_thread(threading.Thread):
def __init__(self):
super(screenshot_thread, self).__init__()
self.state = True
# Attributes
def run(self):
self.take_shot()
def stop(self):
self.state = False
threading.Thread._Thread__stop()
def take_shot(self):
while self.state==True:
time.sleep(10)
subprocess.call(['scrot'])
if __name__ == '__main__':
app = OD_App()
app.MainLoop()
Don't call threading.Thread._Thread__stop! The leading underscore is a sign that this is internal api, it's not guaranteed to even exist (in fact, in python3 it's gone).
If you wish the thead to be destroyed automatically, set it to be daemonic:
def __init__(self):
super(screenshot_thread, self).__init__()
self.daemon = True
That will cause it to be automatically destroyed when the last non-daemonic thread has stopped. Or, in your case, just setting the state to False should make the thread exit after 10 seconds.
You defined a stop method in your screenshot_thread class but you does not use it. Calling it in the method OnCloseWindow should do the job.

How to capture output of a shell script running in a separate process, in a wxPython TextCtrl?

A long running shell script produces stdout and stderr, which I would like to show on a textctrl in a GUI. This is possible using threading and separating the GUI thread from the shell script's thread. However when I implement multiprocessing, I hit a roadblock. Here's my -stripped down- code:
#!/usr/bin/env python
import wx
import sys, subprocess
from multiprocessing import Process, Queue
from Queue import Empty
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.button = wx.Button(self, -1 , "Run")
self.output = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE|\
wx.TE_READONLY|wx.HSCROLL)
self.Bind(wx.EVT_BUTTON, self.OnButton, self.button)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.output, -1, wx.EXPAND, 0)
sizer.Add(self.button)
self.SetSizerAndFit(sizer)
self.Centre()
def OnButton(self, event):
numtasks = 4 # total number of tasks to run
numprocs = 2 # number of processors = number of parallel tasks
work_queue = Queue()
for i in xrange(numtasks):
work_queue.put(i)
processes = [Process(target=self.doWork, args=(work_queue, ))
for i in range(numprocs)]
for p in processes:
p.daemon = True
p.start()
def doWork(self, work_queue):
while True:
try:
x = work_queue.get(block=False)
self.runScript(x)
except Empty:
print "Queue Empty"
break
def runScript(self, taskno):
print '## Now Running: ', taskno
command = ['./script.sh']
proc = subprocess.Popen(command, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while True:
stdout = proc.stdout.readline()
if not stdout:
break
#sys.stdout.flush() #no need for flush, apparently it is embedded in the multiprocessing module
self.output.AppendText(stdout.rstrip()) #this is the part that doesn't work.
if __name__ == "__main__":
app = wx.App(0)
frame = MyFrame(None, title="shell2textctrl", size=(500,500))
frame.Show(True)
app.MainLoop()
I've tried many solutions upon others' suggestions. Among these are: using wx.CallAfter or wx.lib.delayedresult to make the GUI responsive; several threading recipes (eg. wxApplication Development Cookbook, threadpool, others...) and have the multiprocess() run from a separate thread; redefining sys.stdout.write to write to the textctrl; and whatnot. None of them were successfull. Can anyone please provide a solution together with working code? You can use this script written somewhere here by I forgot who:
#!/bin/tcsh -f
# i = 1
while ($i <= 20)
echo $i
# i += 1
sleep 0.2
end
I don't know if this will help you or not, but I have an example of something like this using subprocess here:
http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/
See the pingIP and tracertIP methods. If your shell script is written in Python, you can probably add some kind of generator to it like the ones I am using in that article to post back to the GUI. You probably already read the LongRunningProcess wiki article, but I took that and made my own tutorial here:
http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
I found a solution which implements a modified output Queue on top of Roger Stuckey's Simpler wxPython Multiprocessing Example framework. The code below is even Simpler than his; it could also be cleaned out a little. Hope it helps someone else. I still have a nagging feeling that there should be a more straightforward way of doing this though.
import getopt, math, random, sys, time, types, wx, subprocess
from multiprocessing import Process, Queue, cpu_count, current_process, freeze_support
from Queue import Empty
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, wx.Point(700, 500), wx.Size(300, 200))
self.panel = wx.Panel(self, wx.ID_ANY)
#widgets
self.start_bt = wx.Button(self.panel, wx.ID_ANY, "Start")
self.Bind(wx.EVT_BUTTON, self.OnButton, self.start_bt)
self.output_tc = wx.TextCtrl(self.panel, wx.ID_ANY, style=wx.TE_MULTILINE|wx.TE_READONLY)
# sizer
self.sizer = wx.GridBagSizer(5, 5)
self.sizer.Add(self.start_bt, (0, 0), flag=wx.ALIGN_CENTER|wx.LEFT|wx.TOP|wx.RIGHT, border=5)
self.sizer.Add(self.output_tc, (1, 0), flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=5)
self.sizer.AddGrowableCol(0)
self.sizer.AddGrowableRow(1)
self.panel.SetSizer(self.sizer)
# Set some program flags
self.keepgoing = True
self.i = 0
self.j = 0
def OnButton(self, event):
self.start_bt.Enable(False)
self.numtasks = 4
self.numproc = 2
#self.numproc = cpu_count()
self.output_tc.AppendText('Number of processes = %d\n' % self.numproc)
# Create the queues
self.taskQueue = Queue()
self.outputQueue = Queue()
# Create the task list
self.Tasks = range(self.numtasks)
# The worker processes...
for n in range(self.numproc):
process = Process(target=self.worker, args=(self.taskQueue, self.outputQueue))
process.start()
# Start processing tasks
self.processTasks(self.update)
if (self.keepgoing):
self.start_bt.Enable(True)
def processTasks(self, resfunc=None):
self.keepgoing = True
# Submit first set of tasks
numprocstart = min(self.numproc, self.numtasks)
for self.i in range(numprocstart):
self.taskQueue.put(self.Tasks[self.i])
self.j = -1 # done queue index
self.i = numprocstart - 1 # task queue index
while (self.j < self.i):
# Get and print results
self.j += 1
output = None
while output != 'STOP!':
try:
output = self.outputQueue.get()
if output != 'STOP!':
resfunc(output)
except Empty:
break
if ((self.keepgoing) and (self.i + 1 < self.numtasks)):
# Submit another task
self.i += 1
self.taskQueue.put(self.Tasks[self.i])
def update(self, output):
self.output_tc.AppendText('%s PID=%d Task=%d : %s\n' % output)
wx.YieldIfNeeded()
def worker(self, inputq, outputq):
while True:
try:
tasknum = inputq.get()
print '## Now Running: ', tasknum #this goes to terminal/console. Add it to outputq if you'd like it on the TextCtrl.
command = ['./script.sh']
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
r = p.stdout.readline()
if not r:
outputq.put('STOP!')
break
outputq.put(( current_process().name, current_process().pid, tasknum, r.rstrip()))
except Empty:
break
# The worker must not require any existing object for execution!
worker = classmethod(worker)
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, -1, 'stdout to GUI using multiprocessing')
self.frame.Show(True)
self.frame.Center()
return True
if __name__ == '__main__':
freeze_support()
app = MyApp(0)
app.MainLoop()

How come this way of ending a thread is not working?

I just came out with my noob way of ending a thread, but I don't know why it's not working. Would somebody please help me out?
Here's my sample code:
import wx
import thread
import time
import threading
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent = None, id = -1, title = "Testing", pos=(350, 110), size=(490, 200), style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX)
self.panel = wx.Panel(self)
self.stop = False
self.StartButton = wx.Button(parent = self.panel, id = -1, label = "Start", pos = (110, 17), size = (50, 20))
self.MultiLine = wx.TextCtrl(parent = self.panel, id = -1, pos = (38, 70), size = (410, 90), style = wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_AUTO_URL)
self.Bind(wx.EVT_BUTTON, self.OnStart, self.StartButton)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnStart(self, event):
self.StartButton.Disable()
self.NewThread = threading.Thread(target = self.LongRunning)
self.NewThread.start()
def OnClose(self, event):
self.stop = True
BusyBox = wx.BusyInfo("Just a moment please!", self)
wx.Yield()
while True:
try:
if not self.NewThread.isAlive():
self.Destroy()
break
time.sleep(0.5)
except:
self.Destroy()
break
def LongRunning(self):
Counter = 1
while True:
time.sleep(2)
print "Hello, ", Counter
self.MultiLine.AppendText("hello, " + str(Counter) + "\n") #If you comment out this line, everything works fine. Why can't I update the fame after I hit the close button?
Counter = Counter + 1
if self.stop:
break
class TestApp(wx.App):
def OnInit(self):
self.TestFrame = TestFrame()
self.TestFrame.Show()
self.SetTopWindow(self.TestFrame)
return True
def main():
App = TestApp(redirect = False)
App.MainLoop()
if __name__ == "__main__":
main()
As you can see in my code, there's a infinite loop in the thread, what I tell the thread to do is break out of the loop once I click the close button. But the problem is, every time when I hit the close button, it seems the code stuck at self.MultiLine.AppendText("hello, " + str(Counter) + "\n") line, I don't know why. Anybody can help?
Try using a thread safe method such as wx.CallAfter when updating your multiline.
def LongRunning(self):
Counter = 1
while True:
time.sleep(2)
print "Hello, ", Counter
wx.CallAfter(self.updateMultiLine, "hello, " + str(Counter) + "\n")
Counter = Counter + 1
if self.stop:
break
def updateMultiLine(self, data):
self.MultiLine.AppendText(data)
In general with GUI toolkits, only one thread should access GUI functions. An exception is wx.CallAfter
As you (should) know, software defects can be classified into three groups:
Your bugs.
Their bugs.
Threads.
;)

Python Threading, loading one thread after another

I'm working on a media player and am able to load in a single .wav and play it. As seen in the code below.
foo = wx.FileDialog(self, message="Open a .wav file...", defaultDir=os.getcwd(), defaultFile="", style=wx.FD_MULTIPLE)
foo.ShowModal()
queue = foo.GetPaths()
self.playing_thread = threading.Thread(target=self.playFile, args=(queue[0], 'msg'))
self.playing_thread.start()
But the problem is, when I try to make the above code into a loop for multiple .wav files. Such that while playing_thread.isActive == True, create and .start() the thread. Then if .isActive == False, pop queue[0] and load the next .wav file. Problem is, my UI will lock up and I'll have to terminate the program. Any ideas would be appreciated.
Since is using wx.python, use a Delayedresult, look at wx demos for a complete example.
Full minimal example:
import wx
import wx.lib.delayedresult as inbg
import time
class Player(wx.Frame):
def __init__(self):
self.titulo = "Music Player"
wx.Frame.__init__(self, None, -1, self.titulo,)
self.jobID = 0
self.Vb = wx.BoxSizer(wx.VERTICAL)
self.panel = wx.Panel(self,-1)
self.playlist = ['one','two']
self.abortEvent = inbg.AbortEvent()
self.msg = wx.StaticText(self.panel, -1, "...",pos=(30,-1))
self.msg.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD))
self.action = wx.Button(self.panel, -1,"Play Playlist")
self.Bind(wx.EVT_BUTTON, self.StartPlaying,self.action)
self.Vb.Add(self.msg, 0, wx.EXPAND|wx.ALL, 3)
self.Vb.Add(self.action, 0, wx.EXPAND|wx.ALL, 3)
self.panel.SetSizer(self.Vb)
self.Show()
def StartPlaying(self,evt):
self.BgProcess(self.Playme)
def Playme(self,jobID, abortEvent):
print "in bg"
list = self.getPlayList()
print list
for music in list:
self.msg.SetLabel('Playing: %s' % music)
stop = 100
while stop > 0:
print stop
stop -=1
self.msg.SetLabel('Playing: %s [%s ]' % (music,stop))
def _resultConsumer(self, inbg):
jobID = inbg.getJobID()
try:
result = inbg.get()
return result
except Exception, exc:
return False
def getPlayList(self):
return self.playlist
def setPlayList(self,music):
self.playlist.appdend(music)
def BgProcess(self,executar):
self.abortEvent.clear()
self.jobID += 1
inbg.startWorker(self._resultConsumer, executar, wargs=(self.jobID,self.abortEvent), jobID=self.jobID)
app = wx.App(False)
demo = Player()
app.MainLoop()

Categories