Prev: Problem changing Paper Size when using HtmlEasyPrinting
Next: Re[2]: wxChoice or wxComboBox in wxHTMLWindow, winXP, wxPython 2.8.4
From: Volker Bartheld on 5 Jun 2007 07:55 Hi! I just stumbled over this section in the wxW-docu: "[...] However there is no built in method to send messages to the worker threads and you will need to use the available synchronization classes to implement the solution which suits your needs yourself. In particular, please note that it is not enough to derive your class from wxThread and wxEvtHandler to send messages to it: in fact, this does not work at all. [...]" (http://www.wxwidgets.org/manuals/stable/wx_wxthreadoverview.html#wxthreadoverview) Hmmm. Strange that I didn't spot this earlier... And even stranger that the sample below which does exactly this (deriving a class WorkerThread : public wxEvtHandler, public wxThread) seems to happily update its counter m_uiCount through OnReset(), On Thread() and the wxEVT_THREAD event it receives - at least with the wxW versions (2.7x and 2.8x) and platforms I have tested. So what's the background behind this statement "does not work at all" and how am I meant to do it right? While we are at it: Suppose I want to send some data from a worker to the main thread that is neither int nor wxString. Probably a struct or a void* to some dynamically allocated memory. What's the recommended way to announce where the data can be found? struct tFOO { /* ... */ }; wxCommandEvent evt(wxEVT_THREAD, wxID_ANY); tFOO* pFoo=new tFOO; evt.SetInt((int)pFoo); m_pParent->AddPendingEvent(evt); Or rather some fancy string formatting and wxCommandEvent::SetString()? Or abusing Set/GetClientData() even if the docu states the this "Returns [the] client data pointer for a listbox or choice selection event"? Thanks in advance for any help! Volker <threadsample.cpp> #include "wx/wx.h" #include <wx/thread.h> #include <wx/event.h> #include <wx/statusbr.h> #include <wx/frame.h> #include <wx/string.h> #include <wx/utils.h> enum { Minimal_Quit=wxID_EXIT, Minimal_Stop_Thread=wxID_HIGHEST+1, Minimal_Reset_Thread }; DECLARE_EVENT_TYPE(wxEVT_THREAD, -1) DEFINE_EVENT_TYPE(wxEVT_THREAD) class WorkerThread : public wxEvtHandler, public wxThread { public: WorkerThread(wxFrame* pParent) : m_pParent(pParent) { Create(); } virtual ExitCode Entry() { wxThread::ExitCode exitcode=0; wxCommandEvent evt(wxEVT_THREAD, wxID_ANY); try { for(m_uiCount=100; m_uiCount; --m_uiCount) { if(TestDestroy()) throw (int)0; // the 0 will make it into the event's int and inform the main thread about successfully processing wxThread::Delete() evt.SetInt(m_uiCount); m_pParent->AddPendingEvent(evt); // send updated counter value to main thread wxSleep(1); } // for(unsigned int uiCount=3600; uiCount; --uiCount) } // try catch(int i) { evt.SetInt(i); m_pParent->AddPendingEvent(evt); } wxSleep(5); return (wxThread::ExitCode)0; } // virtual wxThread::ExitCode Entry() void OnThread(wxCommandEvent& event) { m_uiCount=event.GetInt(); } private: DECLARE_EVENT_TABLE() unsigned int m_uiCount; wxFrame* m_pParent; }; BEGIN_EVENT_TABLE(WorkerThread, wxEvtHandler) EVT_COMMAND(wxID_ANY, wxEVT_THREAD, WorkerThread::OnThread) END_EVENT_TABLE() class MyFrame : public wxFrame { public: MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title), m_pThread(NULL) { wxMenu *fileMenu=new wxMenu; fileMenu->Append(Minimal_Reset_Thread, _T("&Reset thread\tAlt-N"), _T("Resets the worker thread")); fileMenu->Append(Minimal_Stop_Thread, _T("&Stop thread\tAlt-S"), _T("Stops the worker thread")); fileMenu->Append(Minimal_Quit, _T("E&xit\tAlt-X"), _T("Exit this program")); wxMenuBar *menuBar=new wxMenuBar(); menuBar->Append(fileMenu, _T("&File")); SetMenuBar(menuBar); CreateStatusBar(); SetStatusText(_T("Welcome to wxWidgets!")); m_pThread=new WorkerThread(this); m_pThread->Run(); } void OnStop(wxCommandEvent& WXUNUSED(event)) { if(m_pThread) { wxMenu* pMenu=GetMenuBar()->GetMenu(0); pMenu->FindItem(Minimal_Reset_Thread)->Enable(false); pMenu->FindItem(Minimal_Stop_Thread)->Enable(false); SetStatusText(_T("Stopping thread...")); m_pThread->Delete(); m_pThread=NULL; // Delete() blocks until worker thread calls TestDestroy() } } void OnReset(wxCommandEvent& WXUNUSED(event)) { wxCommandEvent evt(wxEVT_THREAD, wxID_ANY); evt.SetInt(42); m_pThread->AddPendingEvent(evt); } void OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(); } void OnThread(wxCommandEvent& event) { if(!event.GetInt()) { SetStatusText(_T("Thread stopped.")); m_pThread=NULL; Close(); return; } SetStatusText(wxString::Format(_T("Counting %i..."), event.GetInt())); } void OnClose(wxCloseEvent& WXUNUSED(event)) { wxCommandEvent e; OnStop(e); Destroy(); } private: WorkerThread* m_pThread; DECLARE_EVENT_TABLE() }; // class MyFrame : public wxFrame BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Minimal_Quit, MyFrame::OnQuit) EVT_MENU(Minimal_Reset_Thread, MyFrame::OnReset) EVT_MENU(Minimal_Stop_Thread, MyFrame::OnStop) EVT_COMMAND(wxID_ANY, wxEVT_THREAD, MyFrame::OnThread) EVT_CLOSE(MyFrame::OnClose) END_EVENT_TABLE() class MyApp : public wxApp { public: virtual bool OnInit() { if(!wxApp::OnInit()) return false; MyFrame *frame=new MyFrame(_T("Minimal wxWidgets App")); frame->Show(true); return true; } }; // class MyApp : public wxApp IMPLEMENT_APP(MyApp) </threadsample.cpp> -- mailto: V B A R T H E L D at G M X dot D E
From: Vadim Zeitlin on 5 Jun 2007 08:14
On Tue, 5 Jun 2007 13:55:04 +0200 Volker Bartheld <dr_versaeg(a)freenet.de> wrote: VB> I just stumbled over this section in the wxW-docu: "[...] However there is VB> no built in method to send messages to the worker threads and you will VB> need to use the available synchronization classes to implement the VB> solution which suits your needs yourself. In particular, please note that VB> it is not enough to derive your class from wxThread and wxEvtHandler to VB> send messages to it: in fact, this does not work at all. VB> [...]" VB> (http://www.wxwidgets.org/manuals/stable/wx_wxthreadoverview.html#wxthreadoverview) VB> VB> Hmmm. Strange that I didn't spot this earlier... And even stranger that the VB> sample below which does exactly this (deriving a class WorkerThread : VB> public wxEvtHandler, public wxThread) seems to happily update its counter VB> m_uiCount through OnReset(), On Thread() and the wxEVT_THREAD event it VB> receives - at least with the wxW versions (2.7x and 2.8x) and platforms I VB> have tested. VB> VB> So what's the background behind this statement "does not work at all" and VB> how am I meant to do it right? At the very least by protecting m_uiCount from concurrent access. Your OnThread() is currently called in the main thread context so it's not surprising that it works -- the fact that it's in wxThread-derived class doesn't mean anything. Regards, VZ -- TT-Solutions: wxWidgets consultancy and technical support http://www.tt-solutions.com/ --------------------------------------------------------------------- To unsubscribe, e-mail: wx-users-unsubscribe(a)lists.wxwidgets.org For additional commands, e-mail: wx-users-help(a)lists.wxwidgets.org |