Added a demo showing how to use wxPostEvent
Added an MVCTree contribution Some final tweaks for this release git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4536 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
3739399733
commit
e19b716460
@ -45,6 +45,7 @@ Or you can send mail directly to the list using this address:
|
|||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
What's new in 2.1.11
|
What's new in 2.1.11
|
||||||
--------------------
|
--------------------
|
||||||
Skipped a few version numbers so wxMSW, wxGTK and wxPython are all
|
Skipped a few version numbers so wxMSW, wxGTK and wxPython are all
|
||||||
@ -88,13 +89,12 @@ Many updates to wxMenu, wxMenuBar.
|
|||||||
wxPyEvent and wxPyCommandEvent derived classes now give you the actual
|
wxPyEvent and wxPyCommandEvent derived classes now give you the actual
|
||||||
Python object in the event handler instead of a new shadow.
|
Python object in the event handler instead of a new shadow.
|
||||||
|
|
||||||
Added a Calendar widget from Lorne White.
|
Added a Calendar widget from Lorne White to the library.
|
||||||
|
|
||||||
Made some fixes to the wxFloatbar.
|
|
||||||
|
|
||||||
Added the HTML printing classes.
|
|
||||||
|
|
||||||
|
Made some fixes to the wxFloatbar. It still has some troubles on
|
||||||
|
wxGTK...
|
||||||
|
|
||||||
|
Added an MVC tree control from Bryn Keller to the library.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +42,8 @@ _treeList = [
|
|||||||
|
|
||||||
('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'FontEnumerator',
|
('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'FontEnumerator',
|
||||||
'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
|
'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
|
||||||
'wxImage', 'PrintFramework', 'wxOGL', 'PythonEvents']),
|
'wxImage', 'PrintFramework', 'wxOGL', 'PythonEvents',
|
||||||
|
'Threads']),
|
||||||
|
|
||||||
('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
|
('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
|
||||||
'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
|
'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
|
||||||
|
216
utils/wxPython/demo/Threads.py
Normal file
216
utils/wxPython/demo/Threads.py
Normal file
@ -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.
|
||||||
|
|
||||||
|
"""
|
1111
utils/wxPython/lib/mvctree.py
Normal file
1111
utils/wxPython/lib/mvctree.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -450,20 +450,20 @@ PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) {
|
|||||||
// themselves and some special case handling in wxPyCallback::EventThunker.
|
// themselves and some special case handling in wxPyCallback::EventThunker.
|
||||||
|
|
||||||
|
|
||||||
wxPySelfRef::wxPySelfRef() {
|
wxPyEvtSelfRef::wxPyEvtSelfRef() {
|
||||||
//m_self = Py_None; // **** We don't do normal ref counting to prevent
|
//m_self = Py_None; // **** We don't do normal ref counting to prevent
|
||||||
//Py_INCREF(m_self); // circular loops...
|
//Py_INCREF(m_self); // circular loops...
|
||||||
m_cloned = false;
|
m_cloned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxPySelfRef::~wxPySelfRef() {
|
wxPyEvtSelfRef::~wxPyEvtSelfRef() {
|
||||||
bool doSave = wxPyRestoreThread();
|
bool doSave = wxPyRestoreThread();
|
||||||
if (m_cloned)
|
if (m_cloned)
|
||||||
Py_DECREF(m_self);
|
Py_DECREF(m_self);
|
||||||
wxPySaveThread(doSave);
|
wxPySaveThread(doSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxPySelfRef::SetSelf(PyObject* self, bool clone) {
|
void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) {
|
||||||
bool doSave = wxPyRestoreThread();
|
bool doSave = wxPyRestoreThread();
|
||||||
if (m_cloned)
|
if (m_cloned)
|
||||||
Py_DECREF(m_self);
|
Py_DECREF(m_self);
|
||||||
@ -475,7 +475,7 @@ void wxPySelfRef::SetSelf(PyObject* self, bool clone) {
|
|||||||
wxPySaveThread(doSave);
|
wxPySaveThread(doSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* wxPySelfRef::GetSelf() const {
|
PyObject* wxPyEvtSelfRef::GetSelf() const {
|
||||||
Py_INCREF(m_self);
|
Py_INCREF(m_self);
|
||||||
return m_self;
|
return m_self;
|
||||||
}
|
}
|
||||||
|
@ -189,10 +189,10 @@ private:
|
|||||||
// themselves and some special case handling in wxPyCallback::EventThunker.
|
// themselves and some special case handling in wxPyCallback::EventThunker.
|
||||||
|
|
||||||
|
|
||||||
class wxPySelfRef {
|
class wxPyEvtSelfRef {
|
||||||
public:
|
public:
|
||||||
wxPySelfRef();
|
wxPyEvtSelfRef();
|
||||||
~wxPySelfRef();
|
~wxPyEvtSelfRef();
|
||||||
|
|
||||||
void SetSelf(PyObject* self, bool clone=FALSE);
|
void SetSelf(PyObject* self, bool clone=FALSE);
|
||||||
PyObject* GetSelf() const;
|
PyObject* GetSelf() const;
|
||||||
@ -203,7 +203,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class wxPyEvent : public wxEvent, public wxPySelfRef {
|
class wxPyEvent : public wxEvent, public wxPyEvtSelfRef {
|
||||||
DECLARE_DYNAMIC_CLASS(wxPyEvent)
|
DECLARE_DYNAMIC_CLASS(wxPyEvent)
|
||||||
public:
|
public:
|
||||||
wxPyEvent(int id=0);
|
wxPyEvent(int id=0);
|
||||||
@ -213,7 +213,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class wxPyCommandEvent : public wxCommandEvent, public wxPySelfRef {
|
class wxPyCommandEvent : public wxCommandEvent, public wxPyEvtSelfRef {
|
||||||
DECLARE_DYNAMIC_CLASS(wxPyCommandEvent)
|
DECLARE_DYNAMIC_CLASS(wxPyCommandEvent)
|
||||||
public:
|
public:
|
||||||
wxPyCommandEvent(wxEventType commandType = wxEVT_NULL, int id=0);
|
wxPyCommandEvent(wxEventType commandType = wxEVT_NULL, int id=0);
|
||||||
|
Loading…
Reference in New Issue
Block a user