blocking gui program with multiprocessing.

I write blocking gui program with multiprocessing.

I can’t write text on textctrl and push button while it execute.

This code do “witetext” throgh “queue” with EVT_BUTTON and EVT_IDLE.

I want it to non-blocking program.

I read http://wiki.wxpython.org/Non-Blocking%20Gui, but I can’t modify…

Please advice me.

coding: UTF-8

import wx

import multiprocessing

import time

class MyFrame(wx.Frame):

def init(self, parent, id, title, queue):

wx.Frame.init(self, parent, id, title=title, size=(400, 400))

self.queue = queue

panel = wx.Panel(self, -1)

vbox = wx.BoxSizer(wx.VERTICAL)

hbox1 = wx.BoxSizer(wx.HORIZONTAL)

self.tc1 = wx.TextCtrl(panel, -1)

hbox1.Add(self.tc1, 1)

vbox.Add(hbox1, 0, wx.EXPAND)

hbox2 = wx.BoxSizer(wx.HORIZONTAL)

ok_button = wx.Button(panel, -1, “OK”, size=(70, 30))

cancel_button = wx.Button(panel, -1, “Cancel”, size=(70, 30))

ok_button.Bind(wx.EVT_BUTTON, self.click_okbutton)

cancel_button.Bind(wx.EVT_BUTTON, self.click_cancelbutton)

hbox2.Add(ok_button, 0)

hbox2.Add(cancel_button, 0)

vbox.Add(hbox2, 0, wx.ALIGN_RIGHT)

hbox3 = wx.BoxSizer(wx.HORIZONTAL)

self.tc2 = wx.TextCtrl(panel, -1, style=wx.TE_READONLY)

hbox3.Add(self.tc2, 1, wx.EXPAND)

vbox.Add(hbox3, 1, wx.EXPAND)

panel.SetSizer(vbox)

self.Bind(wx.EVT_CLOSE, self.onClose)

self.Bind (wx.EVT_IDLE, self.onIdle)

self.Show(True)

def click_okbutton(self, event):

self.queue.put(self.tc1.GetValue())

self.tc1.Clear()

def click_cancelbutton(self, event):

self.tc1.Clear()

def onIdle(self, event):

while True:

item = self.queue.get()

if item is None:

print “done!”

break

else:

self.tc2.WriteText(item)

def onClose(self, event):

self.queue.put(None)

self.tc2.WriteText(“closing”)

self.Destroy()

def start_gui(ev, queue):

app = wx.App(False)

frame = MyFrame(None, -1, “sample.py”, queue)

app.MainLoop()

ev.set()

def worker(queue):

while True:

queue.put(“on process\n”)

time.sleep(2)

if name == ‘main’:

multiprocessing.freeze_support()

queue = multiprocessing.Queue()

ev = multiprocessing.Event()

p = multiprocessing.Process(target = start_gui, args=(ev, queue,))

p.start()

p2 = multiprocessing.Process(target = worker, args=(queue,))

p2.start()

ev.wait()

p2.terminate()

hudif wrote:

I write blocking gui program with multiprocessing.
I can't write text on textctrl and push button while it execute.
This code do "witetext" throgh "queue" with EVT_BUTTON and EVT_IDLE.
I want it to non-blocking program.
I read Non-Blocking Gui - wxPyWiki, but I can't modify...
Please advice me.

OnIdle is only called when the message loop goes empty. That is, it is
called ONCE when your window transitions from "busy" to "idle". It is
not called continuously, which is what you seem to expect. My guess
here is that your worker thread is filling up the request queue so that
your button click handler can't add anything more.

Your architecture here is a little unusual. Usually, you would have the
worker thread pulling items FROM the queue and performing the tasks.
The GUI would then add items to the queue. You don't really want your
GUI thread handling the long-running tasks. My advice is to take the
code you have in your OnIdle handler and move it into your "worker"
function. You would then need to send messages from that function back
to the window in order to update GUI items like the text box, but that's
not hard.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Thanks for replay.

I try to move “onIdle()” to “worker()”,but I don’t know how to call “tc2.WriteText” out of “MyFrame” class.
I remove while loop from onIdle(), and it become little light.

2013年9月10日火曜日 3時07分29秒 UTC+9 Tim Roberts:

···

hudif wrote:

I write blocking gui program with multiprocessing.

I can’t write text on textctrl and push button while it execute.

This code do “witetext” throgh “queue” with EVT_BUTTON and EVT_IDLE.

I want it to non-blocking program.

I read http://wiki.wxpython.org/Non-Blocking%20Gui, but I can’t modify…

Please advice me.

OnIdle is only called when the message loop goes empty. That is, it is

called ONCE when your window transitions from “busy” to “idle”. It is

not called continuously, which is what you seem to expect. My guess

here is that your worker thread is filling up the request queue so that

your button click handler can’t add anything more.

Your architecture here is a little unusual. Usually, you would have the

worker thread pulling items FROM the queue and performing the tasks.
The GUI would then add items to the queue. You don’t really want your

GUI thread handling the long-running tasks. My advice is to take the

code you have in your OnIdle handler and move it into your “worker”

function. You would then need to send messages from that function back

to the window in order to update GUI items like the text box, but that’s

not hard.


Tim Roberts, ti...@probo.com

Providenza & Boekelheide, Inc.

Hello,

def onIdle(self, event):

while True:

item = self.queue.get()

if item is None:

print “done!”

break

else:

self.tc2.WriteText(item)

self.queue.get() blocks until it can get something from the queue,

so once your UI goes into onIdle,

it waits until it can pull something from the queue.

Try:

if not self.queue.emtpy()

or

item=self.queue.get(False) # does not block, returns “False” on empty queue

Plus Tim Robert’s advice.

Maybe have function with wxTimer check your queue regularly?

I use two queues:

Tasks for the worker go into one (taskqueue)

Results from the worker go into the other (resultqueue)

GUI puts into taskqueue and pulls from resultqueue.

Worker does it the other way around.

p = multiprocessing.Process(target = start_gui, args=(ev, queue,))

p.start()

p2 = multiprocessing.Process(target = worker, args=(queue,))

p2.start()

ev.wait()

p2.terminate()

I don’t think you need a seperate process for the GUI (?)

p2.start()

app.MainLoop()

p2.terminate()

?

Regards,

Michael

···

On Mon, 09 Sep 2013 19:57:20 +0200, hudif ishibe8@gmail.com wrote: