]> git.saurik.com Git - wxWidgets.git/blame - samples/thread/thread.cpp
Added test showing problem with small grids
[wxWidgets.git] / samples / thread / thread.cpp
CommitLineData
82052aff 1/////////////////////////////////////////////////////////////////////////////
c4f02b1f 2// Name: thread.cpp
82052aff
GL
3// Purpose: wxWindows thread sample
4// Author: Julian Smart(minimal)/Guilhem Lavaux(thread test)
5// Modified by:
6// Created: 06/16/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart, Markus Holzem, Guilhem Lavaux
3222fde2 9// Licence: wxWindows license
82052aff
GL
10/////////////////////////////////////////////////////////////////////////////
11
bee503b0 12/*
98f026a6
VZ
13 TODO: use worker threads to update progress controls instead of writing
14 messages - it will be more visual
bee503b0
VZ
15 */
16
82052aff
GL
17// For compilers that support precompilation, includes "wx/wx.h".
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
3222fde2 21 #pragma hdrstop
82052aff
GL
22#endif
23
24#ifndef WX_PRECOMP
3222fde2 25 #include "wx/wx.h"
82052aff
GL
26#endif
27
3222fde2
VZ
28#if !wxUSE_THREADS
29 #error "This sample requires thread support!"
30#endif // wxUSE_THREADS
31
82052aff
GL
32#include "wx/thread.h"
33#include "wx/dynarray.h"
3222fde2 34#include "wx/time.h"
82052aff 35
b9de1315
VZ
36#include "wx/progdlg.h"
37
a4b59324
VZ
38#ifdef USE_EXECUTE
39 #define EXEC(cmd) wxExecute((cmd), wxEXEC_SYNC)
40#else
41 #define EXEC(cmd) system(cmd)
42#endif
b8b9762a 43
1bd3e1ef
GL
44class MyThread;
45WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
46
82052aff 47// Define a new application type
bf1852e1 48class MyApp : public wxApp
82052aff 49{
98f026a6
VZ
50public:
51 virtual bool OnInit();
52
53public:
54 // all the threads currently alive - as soon as the thread terminates, it's
55 // removed from the array
56 wxArrayThread m_threads;
57
58 // crit section protects access to all of the arrays below
59 wxCriticalSection m_critsect;
82052aff
GL
60};
61
1bd3e1ef 62// Create a new application object
98f026a6 63IMPLEMENT_APP(MyApp)
82052aff
GL
64
65// Define a new frame type
66class MyFrame: public wxFrame
67{
a6b0bd49
VZ
68public:
69 // ctor
bf1852e1 70 MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
3222fde2 71
a6b0bd49
VZ
72 // operations
73 void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
74
b9de1315
VZ
75 // accessors for MyWorkerThread (called in its context!)
76 bool Cancelled();
77
a6b0bd49 78 // callbacks
82052aff 79 void OnQuit(wxCommandEvent& event);
bee503b0 80 void OnClear(wxCommandEvent& event);
a6b0bd49 81
82052aff 82 void OnStartThread(wxCommandEvent& event);
7c3d7e2d 83 void OnStartThreads(wxCommandEvent& event);
82052aff
GL
84 void OnStopThread(wxCommandEvent& event);
85 void OnPauseThread(wxCommandEvent& event);
a6b0bd49 86 void OnResumeThread(wxCommandEvent& event);
b9de1315 87
ce6d2511
RR
88 void OnStartWorker(wxCommandEvent& event);
89 void OnWorkerEvent(wxCommandEvent& event);
b9de1315 90 void OnUpdateWorker(wxUpdateUIEvent& event);
a6b0bd49 91
a4b59324
VZ
92 void OnExecMain(wxCommandEvent& event);
93 void OnExecThread(wxCommandEvent& event);
94
95 void OnShowCPUs(wxCommandEvent& event);
96 void OnAbout(wxCommandEvent& event);
97
3222fde2 98 void OnIdle(wxIdleEvent &event);
3222fde2 99
a6b0bd49 100private:
7c3d7e2d
VZ
101 // helper function - creates a new thread (but doesn't run it)
102 MyThread *CreateThread();
88ac883a 103
bf1852e1
VZ
104 // just some place to put our messages in
105 wxTextCtrl *m_txtctrl;
3222fde2 106
7c3d7e2d
VZ
107 // remember the number of running threads and total number of threads
108 size_t m_nRunning, m_nCount;
109
b9de1315
VZ
110 // the progress dialog which we show while worker thread is running
111 wxProgressDialog *m_dlgProgress;
112
113 // was the worker thread cancelled by user?
114 bool m_cancelled;
115
116 // protects m_cancelled
117 wxCriticalSection m_critsectWork;
118
a6b0bd49 119 DECLARE_EVENT_TABLE()
82052aff
GL
120};
121
ce6d2511
RR
122// ID for the menu commands
123enum
124{
a4b59324
VZ
125 THREAD_QUIT = 1,
126 THREAD_TEXT = 101,
127 THREAD_CLEAR,
128 THREAD_START_THREAD = 201,
129 THREAD_START_THREADS,
130 THREAD_STOP_THREAD,
131 THREAD_PAUSE_THREAD,
132 THREAD_RESUME_THREAD,
133 THREAD_START_WORKER,
134
135 THREAD_EXEC_MAIN,
136 THREAD_EXEC_THREAD,
137
138 THREAD_SHOWCPUS,
139 THREAD_ABOUT,
140
ce6d2511
RR
141 WORKER_EVENT // this one gets sent from the worker thread
142};
143
a4b59324 144// ----------------------------------------------------------------------------
ce6d2511 145// GUI thread
a4b59324 146// ----------------------------------------------------------------------------
ce6d2511 147
bee503b0 148class MyThread : public wxThread
82052aff 149{
a6b0bd49 150public:
82052aff 151 MyThread(MyFrame *frame);
3222fde2
VZ
152
153 // thread execution starts here
154 virtual void *Entry();
155
bf1852e1
VZ
156 // called when the thread exits - whether it terminates normally or is
157 // stopped with Delete() (but not when it is Kill()ed!)
bee503b0
VZ
158 virtual void OnExit();
159
3222fde2
VZ
160 // write something to the text control
161 void WriteText(const wxString& text);
a6b0bd49
VZ
162
163public:
164 size_t m_count;
82052aff
GL
165 MyFrame *m_frame;
166};
167
168MyThread::MyThread(MyFrame *frame)
a6b0bd49 169 : wxThread()
82052aff 170{
a6b0bd49
VZ
171 m_count = 0;
172 m_frame = frame;
82052aff
GL
173}
174
3222fde2
VZ
175void MyThread::WriteText(const wxString& text)
176{
177 wxString msg;
3222fde2
VZ
178
179 // before doing any GUI calls we must ensure that this thread is the only
180 // one doing it!
88ac883a 181
7b90a8f2 182 wxMutexGuiEnter();
88ac883a 183
20e05ffb 184 msg << text;
3222fde2 185 m_frame->WriteText(msg);
b9de1315 186
7b90a8f2 187 wxMutexGuiLeave();
bee503b0
VZ
188}
189
190void MyThread::OnExit()
191{
1bd3e1ef
GL
192 wxCriticalSectionLocker locker(wxGetApp().m_critsect);
193
194 wxGetApp().m_threads.Remove(this);
3222fde2
VZ
195}
196
82052aff
GL
197void *MyThread::Entry()
198{
a6b0bd49 199 wxString text;
3222fde2 200
4693b20c 201 text.Printf(wxT("Thread 0x%x started (priority = %d).\n"),
b568d04f 202 GetId(), GetPriority());
3222fde2 203 WriteText(text);
2286341c 204 // wxLogMessage(text); -- test wxLog thread safeness
3222fde2 205
bee503b0 206 for ( m_count = 0; m_count < 10; m_count++ )
3222fde2
VZ
207 {
208 // check if we were asked to exit
209 if ( TestDestroy() )
210 break;
211
4693b20c 212 text.Printf(wxT("[%u] Thread 0x%x here.\n"), m_count, GetId());
3222fde2 213 WriteText(text);
a6b0bd49 214
bf1852e1
VZ
215 // wxSleep() can't be called from non-GUI thread!
216 wxThread::Sleep(1000);
a6b0bd49 217 }
3222fde2 218
4693b20c 219 text.Printf(wxT("Thread 0x%x finished.\n"), GetId());
3222fde2 220 WriteText(text);
2286341c 221 // wxLogMessage(text); -- test wxLog thread safeness
3222fde2 222
a6b0bd49 223 return NULL;
82052aff
GL
224}
225
a4b59324 226// ----------------------------------------------------------------------------
ce6d2511 227// worker thread
a4b59324 228// ----------------------------------------------------------------------------
ce6d2511
RR
229
230class MyWorkerThread : public wxThread
3222fde2 231{
ce6d2511
RR
232public:
233 MyWorkerThread(MyFrame *frame);
234
235 // thread execution starts here
236 virtual void *Entry();
237
238 // called when the thread exits - whether it terminates normally or is
239 // stopped with Delete() (but not when it is Kill()ed!)
240 virtual void OnExit();
241
242public:
243 MyFrame *m_frame;
244 size_t m_count;
3222fde2 245};
82052aff 246
ce6d2511
RR
247MyWorkerThread::MyWorkerThread(MyFrame *frame)
248 : wxThread()
249{
250 m_frame = frame;
251 m_count = 0;
252}
253
254void MyWorkerThread::OnExit()
255{
256}
257
258void *MyWorkerThread::Entry()
259{
b9de1315 260 for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ )
ce6d2511
RR
261 {
262 // check if we were asked to exit
263 if ( TestDestroy() )
264 break;
b9de1315 265
b9de1315 266 // create any type of command event here
ce6d2511 267 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
b9de1315 268 event.SetInt( m_count );
b9de1315 269
07f5b19a 270 // send in a thread-safe way
ce6d2511 271 wxPostEvent( m_frame, event );
b9de1315 272
07f5b19a 273 // wxSleep() can't be called from non-main thread!
b9de1315 274 wxThread::Sleep(200);
ce6d2511
RR
275 }
276
b9de1315
VZ
277 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
278 event.SetInt(-1); // that's all
279 wxPostEvent( m_frame, event );
280
ce6d2511
RR
281 return NULL;
282}
283
a4b59324
VZ
284// ----------------------------------------------------------------------------
285// a thread which simply calls wxExecute
286// ----------------------------------------------------------------------------
287
288class MyExecThread : public wxThread
289{
290public:
291 MyExecThread(const wxChar *command) : wxThread(wxTHREAD_JOINABLE),
292 m_command(command)
293 {
294 Create();
295 }
296
297 virtual ExitCode Entry()
298 {
299 return (ExitCode)EXEC(m_command);
300 }
301
302private:
303 wxString m_command;
304};
305
306// ----------------------------------------------------------------------------
307// implementation
308// ----------------------------------------------------------------------------
ce6d2511 309
82052aff 310BEGIN_EVENT_TABLE(MyFrame, wxFrame)
a4b59324
VZ
311 EVT_MENU(THREAD_QUIT, MyFrame::OnQuit)
312 EVT_MENU(THREAD_CLEAR, MyFrame::OnClear)
313 EVT_MENU(THREAD_START_THREAD, MyFrame::OnStartThread)
314 EVT_MENU(THREAD_START_THREADS, MyFrame::OnStartThreads)
315 EVT_MENU(THREAD_STOP_THREAD, MyFrame::OnStopThread)
316 EVT_MENU(THREAD_PAUSE_THREAD, MyFrame::OnPauseThread)
317 EVT_MENU(THREAD_RESUME_THREAD, MyFrame::OnResumeThread)
318
319 EVT_MENU(THREAD_EXEC_MAIN, MyFrame::OnExecMain)
320 EVT_MENU(THREAD_EXEC_THREAD, MyFrame::OnExecThread)
321
322 EVT_MENU(THREAD_SHOWCPUS, MyFrame::OnShowCPUs)
323 EVT_MENU(THREAD_ABOUT, MyFrame::OnAbout)
324
325 EVT_UPDATE_UI(THREAD_START_WORKER, MyFrame::OnUpdateWorker)
326 EVT_MENU(THREAD_START_WORKER, MyFrame::OnStartWorker)
ce6d2511 327 EVT_MENU(WORKER_EVENT, MyFrame::OnWorkerEvent)
a6b0bd49 328
3222fde2 329 EVT_IDLE(MyFrame::OnIdle)
82052aff
GL
330END_EVENT_TABLE()
331
82052aff 332// `Main program' equivalent, creating windows and returning main app frame
3222fde2 333bool MyApp::OnInit()
82052aff 334{
a4b59324
VZ
335 // uncomment this to get some debugging messages from the trace code
336 // on the console (or just set WXTRACE env variable to include "thread")
337 //wxLog::AddTraceMask("thread");
b8b9762a 338
a6b0bd49 339 // Create the main frame window
bee503b0
VZ
340 MyFrame *frame = new MyFrame((wxFrame *)NULL, "wxWindows threads sample",
341 50, 50, 450, 340);
3222fde2 342
a6b0bd49 343 // Make a menubar
a4b59324
VZ
344 wxMenuBar *menuBar = new wxMenuBar;
345
346 wxMenu *menuFile = new wxMenu;
347 menuFile->Append(THREAD_CLEAR, "&Clear log\tCtrl-L");
348 menuFile->AppendSeparator();
349 menuFile->Append(THREAD_QUIT, "E&xit\tAlt-X");
350 menuBar->Append(menuFile, "&File");
351
352 wxMenu *menuThread = new wxMenu;
353 menuThread->Append(THREAD_START_THREAD, "&Start a new thread\tCtrl-N");
354 menuThread->Append(THREAD_START_THREADS, "Start &many threads at once");
355 menuThread->Append(THREAD_STOP_THREAD, "S&top a running thread\tCtrl-S");
356 menuThread->AppendSeparator();
357 menuThread->Append(THREAD_PAUSE_THREAD, "&Pause a running thread\tCtrl-P");
358 menuThread->Append(THREAD_RESUME_THREAD, "&Resume suspended thread\tCtrl-R");
359 menuThread->AppendSeparator();
360 menuThread->Append(THREAD_START_WORKER, "Start &worker thread\tCtrl-W");
361 menuBar->Append(menuThread, "&Thread");
362
363 wxMenu *menuExec = new wxMenu;
364 menuExec->Append(THREAD_EXEC_MAIN, "&Launch a program from main thread\tF5");
365 menuExec->Append(THREAD_EXEC_THREAD, "L&aunch a program from a thread\tCtrl-F5");
366 menuBar->Append(menuExec, "&Execute");
367
368 wxMenu *menuHelp = new wxMenu;
369 menuHelp->Append(THREAD_SHOWCPUS, "&Show CPU count");
370 menuHelp->AppendSeparator();
371 menuHelp->Append(THREAD_ABOUT, "&About...");
372 menuBar->Append(menuHelp, "&Help");
373
374 frame->SetMenuBar(menuBar);
3222fde2 375
a6b0bd49
VZ
376 // Show the frame
377 frame->Show(TRUE);
3222fde2 378
a6b0bd49 379 SetTopWindow(frame);
3222fde2 380
a6b0bd49 381 return TRUE;
82052aff
GL
382}
383
384// My frame constructor
bf1852e1
VZ
385MyFrame::MyFrame(wxFrame *frame, const wxString& title,
386 int x, int y, int w, int h)
a6b0bd49 387 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
82052aff 388{
7c3d7e2d
VZ
389 m_nRunning = m_nCount = 0;
390
b9de1315
VZ
391 m_dlgProgress = (wxProgressDialog *)NULL;
392
7c3d7e2d 393 CreateStatusBar(2);
3222fde2 394
bee503b0
VZ
395 m_txtctrl = new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(0, 0),
396 wxTE_MULTILINE | wxTE_READONLY);
82052aff 397
a6b0bd49 398}
82052aff 399
7c3d7e2d 400MyThread *MyFrame::CreateThread()
a6b0bd49
VZ
401{
402 MyThread *thread = new MyThread(this);
3222fde2 403
bf1852e1
VZ
404 if ( thread->Create() != wxTHREAD_NO_ERROR )
405 {
4693b20c 406 wxLogError(wxT("Can't create thread!"));
bf1852e1 407 }
3222fde2 408
1bd3e1ef
GL
409 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
410 wxGetApp().m_threads.Add(thread);
bf1852e1 411
7c3d7e2d
VZ
412 return thread;
413}
414
415void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
416{
b568d04f
VZ
417 static long s_num = 10;
418
419 s_num = wxGetNumberFromUser("How many threads to start: ", "",
420 "wxThread sample", s_num, 1, 10000, this);
421 if ( s_num == -1 )
422 {
423 s_num = 10;
7c3d7e2d 424
7c3d7e2d 425 return;
b568d04f
VZ
426 }
427
428 size_t count = (size_t)s_num, n;
7c3d7e2d
VZ
429
430 wxArrayThread threads;
431
432 // first create them all...
433 for ( n = 0; n < count; n++ )
434 {
98f026a6
VZ
435 wxThread *thr = CreateThread();
436
437 // we want to show the effect of SetPriority(): the first thread will
438 // have the lowest priority, the second - the highest, all the rest
439 // the normal one
440 if ( n == 0 )
441 thr->SetPriority(WXTHREAD_MIN_PRIORITY);
442 else if ( n == 1 )
443 thr->SetPriority(WXTHREAD_MAX_PRIORITY);
444 else
445 thr->SetPriority(WXTHREAD_DEFAULT_PRIORITY);
446
447 threads.Add(thr);
7c3d7e2d
VZ
448 }
449
450 wxString msg;
4693b20c 451 msg.Printf(wxT("%d new threads created."), count);
7c3d7e2d
VZ
452 SetStatusText(msg, 1);
453
454 // ...and then start them
455 for ( n = 0; n < count; n++ )
456 {
457 threads[n]->Run();
458 }
459}
460
461void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
462{
463 MyThread *thread = CreateThread();
464
bf1852e1
VZ
465 if ( thread->Run() != wxTHREAD_NO_ERROR )
466 {
4693b20c 467 wxLogError(wxT("Can't start thread!"));
bf1852e1 468 }
7c3d7e2d
VZ
469
470 SetStatusText("New thread started.", 1);
82052aff
GL
471}
472
e3e65dac 473void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
82052aff 474{
b8b9762a
VZ
475 wxGetApp().m_critsect.Enter();
476
bf1852e1 477 // stop the last thread
1bd3e1ef 478 if ( wxGetApp().m_threads.IsEmpty() )
bee503b0 479 {
4693b20c 480 wxLogError(wxT("No thread to stop!"));
b8b9762a
VZ
481
482 wxGetApp().m_critsect.Leave();
bee503b0 483 }
bf1852e1
VZ
484 else
485 {
1bd3e1ef 486 wxThread *thread = wxGetApp().m_threads.Last();
7c3d7e2d
VZ
487
488 // it's important to leave critical section before calling Delete()
1bd3e1ef 489 // because delete will (implicitly) call OnExit() which also tries
7c3d7e2d 490 // to enter the same crit section - would dead lock.
1bd3e1ef 491 wxGetApp().m_critsect.Leave();
7c3d7e2d
VZ
492
493 thread->Delete();
494
495 SetStatusText("Thread stopped.", 1);
bf1852e1 496 }
a6b0bd49 497}
82052aff 498
a6b0bd49
VZ
499void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
500{
1bd3e1ef 501 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
bee503b0 502
3222fde2 503 // resume first suspended thread
1bd3e1ef
GL
504 size_t n = 0, count = wxGetApp().m_threads.Count();
505 while ( n < count && !wxGetApp().m_threads[n]->IsPaused() )
bf1852e1 506 n++;
3222fde2 507
bf1852e1 508 if ( n == count )
7c3d7e2d 509 {
4693b20c 510 wxLogError(wxT("No thread to resume!"));
7c3d7e2d 511 }
a6b0bd49 512 else
7c3d7e2d 513 {
1bd3e1ef 514 wxGetApp().m_threads[n]->Resume();
7c3d7e2d
VZ
515
516 SetStatusText("Thread resumed.", 1);
517 }
82052aff
GL
518}
519
e3e65dac 520void MyFrame::OnPauseThread(wxCommandEvent& WXUNUSED(event) )
f3855ef0 521{
1bd3e1ef 522 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
bee503b0 523
3222fde2 524 // pause last running thread
1bd3e1ef
GL
525 int n = wxGetApp().m_threads.Count() - 1;
526 while ( n >= 0 && !wxGetApp().m_threads[n]->IsRunning() )
a6b0bd49 527 n--;
3222fde2 528
a6b0bd49 529 if ( n < 0 )
7c3d7e2d 530 {
4693b20c 531 wxLogError(wxT("No thread to pause!"));
7c3d7e2d 532 }
a6b0bd49 533 else
7c3d7e2d 534 {
1bd3e1ef 535 wxGetApp().m_threads[n]->Pause();
88ac883a 536
7c3d7e2d
VZ
537 SetStatusText("Thread paused.", 1);
538 }
f3855ef0
RR
539}
540
3222fde2
VZ
541// set the frame title indicating the current number of threads
542void MyFrame::OnIdle(wxIdleEvent &event)
543{
7fe4f500 544 // update the counts of running/total threads
3222fde2 545 size_t nRunning = 0,
1bd3e1ef 546 nCount = wxGetApp().m_threads.Count();
3222fde2
VZ
547 for ( size_t n = 0; n < nCount; n++ )
548 {
1bd3e1ef 549 if ( wxGetApp().m_threads[n]->IsRunning() )
3222fde2
VZ
550 nRunning++;
551 }
552
7c3d7e2d
VZ
553 if ( nCount != m_nCount || nRunning != m_nRunning )
554 {
555 m_nRunning = nRunning;
556 m_nCount = nCount;
557
4693b20c 558 wxLogStatus(this, wxT("%u threads total, %u running."), nCount, nRunning);
7c3d7e2d
VZ
559 }
560 //else: avoid flicker - don't print anything
f3855ef0 561}
82052aff 562
e3e65dac 563void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
82052aff 564{
1bd3e1ef 565 size_t count = wxGetApp().m_threads.Count();
bf1852e1
VZ
566 for ( size_t i = 0; i < count; i++ )
567 {
1bd3e1ef 568 wxGetApp().m_threads[0]->Delete();
bf1852e1 569 }
3222fde2 570
a6b0bd49 571 Close(TRUE);
82052aff
GL
572}
573
a4b59324
VZ
574void MyFrame::OnExecMain(wxCommandEvent& WXUNUSED(event))
575{
576 wxLogMessage("The exit code from the main program is %ld",
577 EXEC("/bin/echo \"main program\""));
578}
579
580void MyFrame::OnExecThread(wxCommandEvent& WXUNUSED(event))
581{
582 MyExecThread thread("/bin/echo \"child thread\"");
583 thread.Run();
584
585 wxLogMessage("The exit code from a child thread is %ld",
586 (long)thread.Wait());
587}
588
589void MyFrame::OnShowCPUs(wxCommandEvent& WXUNUSED(event))
590{
591 wxString msg;
592
593 int nCPUs = wxThread::GetCPUCount();
594 switch ( nCPUs )
595 {
596 case -1:
597 msg = "Unknown number of CPUs";
598 break;
599
600 case 0:
601 msg = "WARNING: you're running without any CPUs!";
602 break;
603
604 case 1:
605 msg = "This system only has one CPU.";
606 break;
607
608 default:
609 msg.Printf("This system has %d CPUs", nCPUs);
610 }
611
612 wxLogMessage(msg);
613}
614
e3e65dac 615void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
82052aff 616{
bf1852e1
VZ
617 wxMessageDialog dialog(this, "wxWindows multithreaded application sample\n"
618 "(c) 1998 Julian Smart, Guilhem Lavaux\n"
07f5b19a
RR
619 "(c) 1999 Vadim Zeitlin\n"
620 "(c) 2000 Robert Roebling",
3222fde2
VZ
621 "About wxThread sample",
622 wxOK | wxICON_INFORMATION);
623
a6b0bd49 624 dialog.ShowModal();
82052aff
GL
625}
626
bee503b0
VZ
627void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
628{
629 m_txtctrl->Clear();
630}
ce6d2511 631
b9de1315
VZ
632void MyFrame::OnUpdateWorker(wxUpdateUIEvent& event)
633{
634 event.Enable( m_dlgProgress == NULL );
635}
636
ce6d2511
RR
637void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
638{
639 MyWorkerThread *thread = new MyWorkerThread(this);
640
641 if ( thread->Create() != wxTHREAD_NO_ERROR )
642 {
4693b20c 643 wxLogError(wxT("Can't create thread!"));
ce6d2511 644 }
b9de1315
VZ
645
646 m_dlgProgress = new wxProgressDialog
647 (
648 "Progress dialog",
649 "Wait until the thread terminates or press [Cancel]",
650 100,
651 this,
652 wxPD_CAN_ABORT |
653 wxPD_APP_MODAL |
654 wxPD_ELAPSED_TIME |
655 wxPD_ESTIMATED_TIME |
656 wxPD_REMAINING_TIME
657 );
658
659 // thread is not running yet, no need for crit sect
660 m_cancelled = FALSE;
661
ce6d2511
RR
662 thread->Run();
663}
664
07f5b19a 665void MyFrame::OnWorkerEvent(wxCommandEvent& event)
ce6d2511 666{
b9de1315 667#if 0
07f5b19a
RR
668 WriteText( "Got message from worker thread: " );
669 WriteText( event.GetString() );
670 WriteText( "\n" );
b9de1315
VZ
671#else
672 int n = event.GetInt();
673 if ( n == -1 )
674 {
675 m_dlgProgress->Destroy();
676 m_dlgProgress = (wxProgressDialog *)NULL;
677
678 // the dialog is aborted because the event came from another thread, so
679 // we may need to wake up the main event loop for the dialog to be
680 // really closed
681 wxWakeUpIdle();
682 }
683 else
684 {
685 if ( !m_dlgProgress->Update(n) )
686 {
687 wxCriticalSectionLocker lock(m_critsectWork);
688
689 m_cancelled = TRUE;
690 }
691 }
692#endif
ce6d2511
RR
693}
694
b9de1315
VZ
695bool MyFrame::Cancelled()
696{
697 wxCriticalSectionLocker lock(m_critsectWork);
698
699 return m_cancelled;
700}