]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/DelayedResult.py
2 This demonstrates a simple use of delayedresult: get/compute
3 something that takes a long time, without hanging the GUI while this
6 The top button runs a small GUI that uses wx.lib.delayedresult.startWorker
7 to wrap a long-running function into a separate thread. Just click
8 Get, and move the slider, and click Get and Abort a few times, and
9 observe that GUI responds. The key functions to look for in the code
10 are startWorker() and __handleResult().
12 The second button runs the same GUI, but without delayedresult. Click
13 Get: now the get/compute is taking place in main thread, so the GUI
14 does not respond to user actions until worker function returns, it's
15 not even possible to Abort.
19 import wx
.lib
.delayedresult
as delayedresult
22 class FrameSimpleDelayedBase(wx
.Frame
):
23 def __init__(self
, *args
, **kwds
):
24 wx
.Frame
.__init
__(self
, *args
, **kwds
)
26 self
.checkboxUseDelayed
= wx
.CheckBox(pnl
, -1, "Using delayedresult")
27 self
.buttonGet
= wx
.Button(pnl
, -1, "Get")
28 self
.buttonAbort
= wx
.Button(pnl
, -1, "Abort")
29 self
.slider
= wx
.Slider(pnl
, -1, 0, 0, 10, size
=(100,-1),
30 style
=wx
.SL_HORIZONTAL|wx
.SL_AUTOTICKS
)
31 self
.textCtrlResult
= wx
.TextCtrl(pnl
, -1, "", style
=wx
.TE_READONLY
)
33 self
.checkboxUseDelayed
.SetValue(1)
34 self
.checkboxUseDelayed
.Enable(False)
35 self
.buttonAbort
.Enable(False)
37 vsizer
= wx
.BoxSizer(wx
.VERTICAL
)
38 hsizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
39 vsizer
.Add(self
.checkboxUseDelayed
, 0, wx
.ALL
, 10)
40 hsizer
.Add(self
.buttonGet
, 0, wx
.ALL
, 5)
41 hsizer
.Add(self
.buttonAbort
, 0, wx
.ALL
, 5)
42 hsizer
.Add(self
.slider
, 0, wx
.ALL
, 5)
43 hsizer
.Add(self
.textCtrlResult
, 0, wx
.ALL
, 5)
44 vsizer
.Add(hsizer
, 0, wx
.ALL
, 5)
46 vsizer
.SetSizeHints(self
)
48 self
.Bind(wx
.EVT_BUTTON
, self
.handleGet
, self
.buttonGet
)
49 self
.Bind(wx
.EVT_BUTTON
, self
.handleAbort
, self
.buttonAbort
)
54 class FrameSimpleDelayed(FrameSimpleDelayedBase
):
55 """This demos simplistic use of delayedresult module."""
57 def __init__(self
, *args
, **kwargs
):
58 FrameSimpleDelayedBase
.__init
__(self
, *args
, **kwargs
)
60 self
.abortEvent
= delayedresult
.AbortEvent()
61 self
.Bind(wx
.EVT_CLOSE
, self
.handleClose
)
63 def setLog(self
, log
):
66 def handleClose(self
, event
):
67 """Only needed because in demo, closing the window does not kill the
68 app, so worker thread continues and sends result to dead frame; normally
69 your app would exit so this would not happen."""
70 if self
.buttonAbort
.IsEnabled():
71 self
.log( "Exiting: Aborting job %s" % self
.jobID
)
75 def handleGet(self
, event
):
76 """Compute result in separate thread, doesn't affect GUI response."""
77 self
.buttonGet
.Enable(False)
78 self
.buttonAbort
.Enable(True)
79 self
.abortEvent
.clear()
82 self
.log( "Starting job %s in producer thread: GUI remains responsive"
84 delayedresult
.startWorker(self
._resultConsumer
, self
._resultProducer
,
85 wargs
=(self
.jobID
,self
.abortEvent
), jobID
=self
.jobID
)
88 def _resultProducer(self
, jobID
, abortEvent
):
89 """Pretend to be a complex worker function or something that takes
90 long time to run due to network access etc. GUI will freeze if this
91 method is not called in separate thread."""
94 while not abortEvent() and count
< 50:
100 def handleAbort(self
, event
):
101 """Abort the result computation."""
102 self
.log( "Aborting result for job %s" % self
.jobID
)
103 self
.buttonGet
.Enable(True)
104 self
.buttonAbort
.Enable(False)
105 self
.abortEvent
.set()
108 def _resultConsumer(self
, delayedResult
):
109 jobID
= delayedResult
.getJobID()
110 assert jobID
== self
.jobID
112 result
= delayedResult
.get()
113 except Exception, exc
:
114 self
.log( "Result for job %s raised exception: %s" % (jobID
, exc
) )
118 self
.log( "Got result for job %s: %s" % (jobID
, result
) )
119 self
.textCtrlResult
.SetValue(str(result
))
121 # get ready for next job:
122 self
.buttonGet
.Enable(True)
123 self
.buttonAbort
.Enable(False)
126 class FrameSimpleDirect(FrameSimpleDelayedBase
):
127 """This does not use delayedresult so the GUI will freeze while
128 the GET is taking place."""
130 def __init__(self
, *args
, **kwargs
):
132 FrameSimpleDelayedBase
.__init
__(self
, *args
, **kwargs
)
133 self
.checkboxUseDelayed
.SetValue(False)
135 def setLog(self
, log
):
138 def handleGet(self
, event
):
139 """Use delayedresult, this will compute result in separate
140 thread, and will affect GUI response because a thread is not
142 self
.buttonGet
.Enable(False)
143 self
.buttonAbort
.Enable(True)
145 self
.log( "Doing job %s without delayedresult (same as GUI thread): GUI hangs (for a while)" % self
.jobID
)
146 result
= self
._resultProducer
(self
.jobID
)
147 self
._resultConsumer
( result
)
149 def _resultProducer(self
, jobID
):
150 """Pretend to be a complex worker function or something that takes
151 long time to run due to network access etc. GUI will freeze if this
152 method is not called in separate thread."""
157 def handleAbort(self
, event
):
158 """can never be called"""
161 def _resultConsumer(self
, result
):
163 self
.log( "Got result for job %s: %s" % (self
.jobID
, result
) )
164 self
.textCtrlResult
.SetValue(str(result
))
166 # get ready for next job:
167 self
.buttonGet
.Enable(True)
168 self
.buttonAbort
.Enable(False)
172 #---------------------------------------------------------------------------
173 #---------------------------------------------------------------------------
175 class TestPanel(wx
.Panel
):
176 def __init__(self
, parent
, log
):
178 wx
.Panel
.__init
__(self
, parent
, -1)
180 vsizer
= wx
.BoxSizer(wx
.VERTICAL
)
181 b
= wx
.Button(self
, -1, "Long-running function in separate thread")
182 vsizer
.Add(b
, 0, wx
.ALL
, 5)
183 self
.Bind(wx
.EVT_BUTTON
, self
.OnButton1
, b
)
185 b
= wx
.Button(self
, -1, "Long-running function in GUI thread")
186 vsizer
.Add(b
, 0, wx
.ALL
, 5)
187 self
.Bind(wx
.EVT_BUTTON
, self
.OnButton2
, b
)
190 bdr
.Add(vsizer
, 0, wx
.ALL
, 50)
194 def OnButton1(self
, evt
):
195 frame
= FrameSimpleDelayed(self
, title
="Long-running function in separate thread")
196 frame
.setLog(self
.log
.WriteText
)
199 def OnButton2(self
, evt
):
200 frame
= FrameSimpleDirect(self
, title
="Long-running function in GUI thread")
201 frame
.setLog(self
.log
.WriteText
)
205 #---------------------------------------------------------------------------
208 def runTest(frame
, nb
, log
):
209 win
= TestPanel(nb
, log
)
213 #---------------------------------------------------------------------------
219 if __name__
== '__main__':
222 run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])