13c. wxWidgets – Multithreading

OVERVIEW

Multi-threading is a complex topic and it requires a good amount of usage before one can get familiar with it. Here we are only going to deal with some basic handling of threads. By default everything in wxWidgets is handled on the main GUI thread. If you try to do some time consuming process on the main thread, it will block up the UI and the application will freeze for the time that the process is active.

The correct way to handle long running tasks is to run them on a different thread. That way, the main GUI thread is kept free and the application remains responsive.

Another thing to deal with is the updation of the UI from another thread. It is not recommended to try and update anything on the UI from a non-GUI thread. Anyway , any wxWidget object which has been created on the main GUI thread cannot be manipulated from another thread. The correct way to update the UI from another thread is to send an event message to the main thread.

In the sample code below. we subclass a wxThread class and we run a simple loop from which we update the main GUI after each iteration of the loop. We have added a Sleep() method so that the thread executes slowly. The main point to notice here is that while the thread is running, the wxFrame is still responsive and you can move it around or resize it.

SAMPLE CODE

threadtest.h
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif
	
class TestThread:public wxThread {

	public:
		TestThread(wxFrame *parent);
		virtual ~TestThread();
		virtual void *Entry();

	private:
		int mCount;
		wxFrame *mParent;
		void sendMessage(wxString message);
		
};
const int EVENT_UPDATE_UI = 101;

testthread.cpp
#include "threadtest.h"

TestThread::TestThread(wxFrame *parent): wxThread() {
	mCount = 0;
	mParent = parent;
}

TestThread::~TestThread() { }

wxThread::ExitCode TestThread::Entry() {
	sendMessage(wxT("Thread started\n"));
	
	for(int mCount = 0; mCount <= 10; mCount++) {
		if (TestDestroy())
			break;
		sendMessage((wxString::Format("Thread no.%d\n", mCount)));
		wxThread::Sleep(1000);
	}
	sendMessage(wxT("Thread completed.\n"));

	return NULL;
}

void TestThread::sendMessage(wxString message) {

	wxThreadEvent event(wxEVT_THREAD, EVENT_UPDATE_UI);
	event.SetString(message);
	mParent->GetEventHandler()->AddPendingEvent(event);
}

runthreadtest.h
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif

class RunTestThread:public wxFrame {

	public:
		RunTestThread(const wxString &title);
		void onUIUpdate(wxThreadEvent &event);
	private:
		wxTextCtrl *mText;	
		
};



runtestthread.cpp
#include "runthreadtest.h"
#include "threadtest.h"

RunTestThread::RunTestThread(const wxString &title):
	wxFrame(NULL,-1, title, wxDefaultPosition, wxSize(500,400)) {
	mText = new wxTextCtrl(this, -1, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);

	this->Bind(wxEVT_THREAD, &RunTestThread::onUIUpdate, this); 
	
	TestThread *th = new TestThread(this);
	if(th->Create() != wxTHREAD_NO_ERROR) {
		wxPuts("Cannot create thread\n");
		return;
	}	

	if (th->Run() != wxTHREAD_NO_ERROR) {
		wxPuts("Could not start thread.\n");
		return;
	}
	
	Center();
}

void RunTestThread::onUIUpdate(wxThreadEvent &event) {
	mText->AppendText(event.GetString());
	mText->AppendText(wxT("\n"));	
}



main.h
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif

class Main: public wxApp {

	public:
		virtual bool OnInit();
};
main.cpp
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif

class RunTestThread:public wxFrame {

	public:
		RunTestThread(const wxString &title);
		void onUIUpdate(wxThreadEvent &event);
	private:
		wxTextCtrl *mText;	
		
};


The sample output is given below

Be the first to comment

Leave a Reply

Your email address will not be published.


*