]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/wxPython/demo/Threads.py
Added a demo showing how to use wxPostEvent
[wxWidgets.git] / utils / wxPython / demo / Threads.py
diff --git a/utils/wxPython/demo/Threads.py b/utils/wxPython/demo/Threads.py
new file mode 100644 (file)
index 0000000..75a96e7
--- /dev/null
@@ -0,0 +1,216 @@
+
+from wxPython.wx import *
+
+import thread
+import time
+from   whrandom import random
+
+#----------------------------------------------------------------------
+
+wxEVT_UPDATE_BARGRAPH = 25015
+
+def EVT_UPDATE_BARGRAPH(win, func):
+    win.Connect(-1, -1, wxEVT_UPDATE_BARGRAPH, func)
+
+
+class UpdateBarEvent(wxPyEvent):
+    def __init__(self, barNum, value):
+        wxPyEvent.__init__(self)
+        self.SetEventType(wxEVT_UPDATE_BARGRAPH)
+        self.barNum = barNum
+        self.value = value
+
+
+#----------------------------------------------------------------------
+
+class CalcBarThread:
+    def __init__(self, win, barNum, val):
+        self.win = win
+        self.barNum = barNum
+        self.val = val
+
+    def Start(self):
+        self.keepGoing = self.running = true
+        thread.start_new_thread(self.Run, ())
+
+    def Stop(self):
+        self.keepGoing = false
+
+    def IsRunning(self):
+        return self.running
+
+    def Run(self):
+        while self.keepGoing:
+            evt = UpdateBarEvent(self.barNum, int(self.val))
+            wxPostEvent(self.win, evt)
+            del evt
+
+            sleeptime = (random() * 2) + 0.5
+            #print self.barNum, 'sleeping for', sleeptime
+            time.sleep(sleeptime)
+
+            sleeptime = sleeptime * 5
+            if int(random() * 2):
+                self.val = self.val + sleeptime
+            else:
+                self.val = self.val - sleeptime
+
+            if self.val < 0: self.val = 0
+            if self.val > 300: self.val = 300
+
+        self.running = false
+
+#----------------------------------------------------------------------
+
+
+class GraphWindow(wxWindow):
+    def __init__(self, parent, labels):
+        wxWindow.__init__(self, parent, -1)
+
+        self.values = []
+        for label in labels:
+            self.values.append((label, 0))
+
+        self.font = wxFont(12, wxSWISS, wxNORMAL, wxBOLD)
+        self.SetFont(self.font)
+
+        self.colors = [ wxRED, wxGREEN, wxBLUE, wxCYAN] #, wxNamedColour("Yellow") ]
+
+
+    def SetValue(self, index, value):
+        assert index < len(self.values)
+        cur = self.values[index]
+        self.values[index:index+1] = [(cur[0], value)]
+
+
+    def SetFont(self, font):
+        wxWindow.SetFont(self, font)
+        wmax = hmax = 0
+        for label, val in self.values:
+            w,h = self.GetTextExtent(label)
+            if w > wmax: wmax = w
+            if h > hmax: hmax = h
+        self.linePos = wmax + 10
+        self.barHeight = hmax
+
+
+    def OnPaint(self, evt):
+        size = self.GetSize()
+        dc = wxPaintDC(self)
+        dc.BeginDrawing()
+        dc.SetFont(self.font)
+        dc.SetTextForeground(wxBLUE)
+        dc.SetPen(wxPen(wxBLACK, 3, wxSOLID))
+        dc.DrawLine(self.linePos, 0, self.linePos, size.height-10)
+
+        bh = ypos = self.barHeight
+        for x in range(len(self.values)):
+            label, val = self.values[x]
+            dc.DrawText(label, 5, ypos)
+
+            if val:
+                color = self.colors[ x % len(self.colors) ]
+                dc.SetPen(wxPen(color))
+                dc.SetBrush(wxBrush(color))
+                dc.DrawRectangle(self.linePos+3, ypos, val, bh)
+
+            ypos = ypos + 2*bh
+            if ypos > size.height-10:
+                break
+
+        dc.EndDrawing()
+
+
+#----------------------------------------------------------------------
+
+class TestFrame(wxFrame):
+    def __init__(self, parent, log):
+        wxFrame.__init__(self, parent, -1, "Thread Test", size=(450,300))
+        self.log = log
+
+        #self.CenterOnParent()
+
+        panel = wxPanel(self, -1)
+        panel.SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD))
+        wxStaticText(panel, -1,
+                     "This demo shows multiple threads interacting with this\n"
+                     "window by sending events to it.", wxPoint(5,5))
+        panel.Fit()
+
+        self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three'])
+
+        sizer = wxBoxSizer(wxVERTICAL)
+        sizer.Add(panel, 0, wxEXPAND)
+        sizer.Add(self.graph, 1, wxEXPAND)
+
+        self.SetSizer(sizer)
+        self.SetAutoLayout(true)
+
+        #self.graph.SetValue(0, 25)
+        #self.graph.SetValue(1, 50)
+        #self.graph.SetValue(2, 75)
+        #self.graph.SetValue(3, 100)
+
+        EVT_UPDATE_BARGRAPH(self, self.OnUpdate)
+        self.threads = []
+        self.threads.append(CalcBarThread(self, 0, 25))
+        self.threads.append(CalcBarThread(self, 1, 50))
+        self.threads.append(CalcBarThread(self, 2, 75))
+        self.threads.append(CalcBarThread(self, 3, 100))
+
+        for t in self.threads:
+            t.Start()
+
+
+
+    def OnUpdate(self, evt):
+        self.graph.SetValue(evt.barNum, evt.value)
+        self.graph.Refresh()
+
+
+    def OnCloseWindow(self, evt):
+        busy = wxBusyInfo("One moment please, waiting for threads to die...")
+        for t in self.threads:
+            t.Stop()
+        running = 1
+        while running:
+            running = 0
+            for t in self.threads:
+                running = running + t.IsRunning()
+            time.sleep(0.1)
+        self.Destroy()
+
+
+
+#----------------------------------------------------------------------
+
+def runTest(frame, nb, log):
+    win = TestFrame(frame, log)
+    frame.otherWin = win
+    win.Show(true)
+    return None
+
+#----------------------------------------------------------------------
+
+
+
+
+overview = """\
+The main issue with multi-threaded GUI programming is the thread safty
+of the GUI itself.  On most platforms the GUI is not thread safe and
+so any cross platform GUI Toolkit and applications written with it
+need to take that into account.
+
+The solution is to only allow interaction with the GUI from a single
+thread, but this often severly limits what can be done in an
+application and makes it difficult to use additional threads at all.
+
+Since wxPython already makes extensive use of event handlers, it is a
+logical extension to allow events to be sent to GUI objects from
+alternate threads.  A function called wxPostEvent allows you to do
+this.  It accepts an event and an event handler (window) and instead
+of sending the event immediately in the current context like
+ProcessEvent does, it processes it later from the context of the GUI
+thread.
+
+"""