]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/DelayedResult.py
new wxRect and wxPlatformInformation methods
[wxWidgets.git] / wxPython / demo / DelayedResult.py
CommitLineData
8bbd1bbf
RD
1"""
2This demonstrates a simple use of delayedresult: get/compute
3something that takes a long time, without hanging the GUI while this
4is taking place.
5
6The top button runs a small GUI that uses wx.lib.delayedresult.startWorker
7to wrap a long-running function into a separate thread. Just click
8Get, and move the slider, and click Get and Abort a few times, and
9observe that GUI responds. The key functions to look for in the code
10are startWorker() and __handleResult().
11
12The second button runs the same GUI, but without delayedresult. Click
13Get: now the get/compute is taking place in main thread, so the GUI
14does not respond to user actions until worker function returns, it's
15not even possible to Abort.
16"""
17
18import wx
19from wx.lib.delayedresult import startWorker
20
21class FrameSimpleDelayedGlade(wx.Frame):
22 def __init__(self, *args, **kwds):
23 # begin wxGlade: FrameSimpleDelayed.__init__
24 kwds["style"] = wx.DEFAULT_FRAME_STYLE
25 wx.Frame.__init__(self, *args, **kwds)
26 self.checkboxUseDelayed = wx.CheckBox(self, -1, "Use delayedresult")
27 self.buttonGet = wx.Button(self, -1, "Get")
28 self.buttonAbort = wx.Button(self, -1, "Abort")
29 self.slider = wx.Slider(self, -1, 0, 0, 10, size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
30 self.textCtrlResult = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
31
32 self.__set_properties()
33 self.__do_layout()
34
35 self.Bind(wx.EVT_BUTTON, self.handleGet, self.buttonGet)
36 self.Bind(wx.EVT_BUTTON, self.handleAbort, self.buttonAbort)
37 # end wxGlade
38
39 def __set_properties(self):
40 # begin wxGlade: FrameSimpleDelayed.__set_properties
41 self.SetTitle("Simple Examle of Delayed Result")
42 self.checkboxUseDelayed.SetValue(1)
43 self.checkboxUseDelayed.Enable(False)
44 self.buttonAbort.Enable(False)
45 # end wxGlade
46
47 def __do_layout(self):
48 # begin wxGlade: FrameSimpleDelayed.__do_layout
49 sizerFrame = wx.BoxSizer(wx.VERTICAL)
50 sizerGetResult = wx.BoxSizer(wx.HORIZONTAL)
51 sizerUseDelayed = wx.BoxSizer(wx.HORIZONTAL)
52 sizerUseDelayed.Add(self.checkboxUseDelayed, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
53 sizerFrame.Add(sizerUseDelayed, 1, wx.EXPAND, 0)
54 sizerGetResult.Add(self.buttonGet, 0, wx.ADJUST_MINSIZE, 0)
55 sizerGetResult.Add(self.buttonAbort, 0, wx.ADJUST_MINSIZE, 0)
56 sizerGetResult.Add(self.slider, 0, wx.ADJUST_MINSIZE, 0)
57 sizerGetResult.Add(self.textCtrlResult, 0, wx.ADJUST_MINSIZE, 0)
58 sizerFrame.Add(sizerGetResult, 1, wx.ALL|wx.EXPAND, 5)
59 self.SetAutoLayout(True)
60 self.SetSizer(sizerFrame)
61 sizerFrame.Fit(self)
62 sizerFrame.SetSizeHints(self)
63 self.Layout()
64 # end wxGlade
65
66
67class FrameSimpleDelayed(FrameSimpleDelayedGlade):
68 """This demos simplistic use of delayedresult module."""
69
70 def __init__(self, *args, **kwargs):
71 self.jobID = 1
72 FrameSimpleDelayedGlade.__init__(self, *args, **kwargs)
73 self.Bind(wx.EVT_CLOSE, self.handleClose)
74
75 def setLog(self, log):
76 self.log = log
77
78 def handleClose(self, event):
79 """Only needed because in demo, closing the window does not kill the
80 app, so worker thread continues and sends result to dead frame; normally
81 your app would exit so this would not happen."""
82 if self.buttonAbort.IsEnabled():
83 self.Hide()
84 import time
85 time.sleep(5)
86 self.Destroy()
87
88 def handleGet(self, event):
89 """Compute result in separate thread, doesn't affect GUI response."""
90 self.buttonGet.Enable(False)
91 self.buttonAbort.Enable(True)
92
93 self.log( "Starting job %s in producer thread: GUI remains responsive" % self.jobID )
94 startWorker(self.__handleResult, self.__resultCreator,
95 wargs=(self.jobID,), jobID=self.jobID)
96
97 def __resultCreator(self, jobID):
98 """Pretend to be a complex worker function or something that takes
99 long time to run due to network access etc. GUI will freeze if this
100 method is not called in separate thread."""
101 import time
102 time.sleep(5)
103 return jobID
104
105 def handleAbort(self, event):
106 """Abort actually just means 'ignore the result when it gets to
107 handler, it is no longer relevant'. We just increase the job ID,
108 this will let handler know that the result has been cancelled."""
109 self.log( "Aborting result for job %s" % self.jobID )
110 self.buttonGet.Enable(True)
111 self.buttonAbort.Enable(False)
112 self.jobID += 1
113
114 def __handleResult(self, delayedResult):
115 # See if we still want the result for last job started
116 jobID = delayedResult.getJobID()
117 if jobID != self.jobID:
118 self.log( "Got obsolete result for job %s, ignored" % jobID )
119 return
120
121 # we do, get result:
122 try:
123 result = delayedResult.get()
124 except Exception, exc:
125 self.log( "Result for job %s raised exception: %s" % (jobID, exc) )
126 self.jobID += 1
127 return
128
129 # output result
130 self.log( "Got result for job %s: %s" % (jobID, result) )
131 self.textCtrlResult.SetValue(str(result))
132
133 # get ready for next job:
134 self.buttonGet.Enable(True)
135 self.buttonAbort.Enable(False)
136 self.jobID += 1
137
138
139class FrameSimpleDirect(FrameSimpleDelayedGlade):
140 """This does not use delayedresult so the GUI will freeze while
141 the GET is taking place."""
142
143 def __init__(self, *args, **kwargs):
144 self.jobID = 1
145 FrameSimpleDelayedGlade.__init__(self, *args, **kwargs)
146 self.checkboxUseDelayed.SetValue(False)
147
148 def setLog(self, log):
149 self.log = log
150
151 def handleGet(self, event):
152 """Use delayedresult, this will compute
153 result in separate thread, and won't affect GUI response. """
154 self.buttonGet.Enable(False)
155 self.buttonAbort.Enable(True)
156
157 self.log( "Doing job %s without delayedresult (same as GUI thread): GUI hangs (for a while)" % self.jobID )
158 result = self.__resultCreator(self.jobID)
159 self.__handleResult( result )
160
161 def __resultCreator(self, jobID):
162 """Pretend to be a complex worker function or something that takes
163 long time to run due to network access etc. GUI will freeze if this
164 method is not called in separate thread."""
165 import time
166 time.sleep(5)
167 return jobID
168
169 def handleAbort(self, event):
170 """can never be called"""
171 pass
172
173 def __handleResult(self, result):
174 # output result
175 self.log( "Got result for job %s: %s" % (self.jobID, result) )
176 self.textCtrlResult.SetValue(str(result))
177
178 # get ready for next job:
179 self.buttonGet.Enable(True)
180 self.buttonAbort.Enable(False)
181 self.jobID += 1
182
183
184#---------------------------------------------------------------------------
185#---------------------------------------------------------------------------
186
187class TestPanel(wx.Panel):
188 def __init__(self, parent, log):
189 self.log = log
190 wx.Panel.__init__(self, parent, -1)
191
192 vsizer = wx.BoxSizer(wx.VERTICAL)
193 b = wx.Button(self, -1, "Long-running function in separate thread")
194 vsizer.Add(b, 0, wx.ALL, 5)
195 self.Bind(wx.EVT_BUTTON, self.OnButton1, b)
196
197 b = wx.Button(self, -1, "Long-running function in GUI thread")
198 vsizer.Add(b, 0, wx.ALL, 5)
199 self.Bind(wx.EVT_BUTTON, self.OnButton2, b)
200
201 bdr = wx.BoxSizer()
202 bdr.Add(vsizer, 0, wx.ALL, 50)
203 self.SetSizer(bdr)
204 self.Layout()
205
206 def OnButton1(self, evt):
207 frame = FrameSimpleDelayed(self, title="Long-running function in separate thread")
208 frame.setLog(self.log.WriteText)
209 frame.Show()
210
211 def OnButton2(self, evt):
212 frame = FrameSimpleDirect(self, title="Long-running function in GUI thread")
213 frame.setLog(self.log.WriteText)
214 frame.Show()
215
216
217#---------------------------------------------------------------------------
218
219
220def runTest(frame, nb, log):
221 win = TestPanel(nb, log)
222 return win
223
224
225#---------------------------------------------------------------------------
226
227
228overview = __doc__
229
230
231if __name__ == '__main__':
232 import sys,os
233 import run
234 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
235
236