wxWidgets: Threading, and using the ClipboardTwo for one in this tutorial. We're going to create a thread using wxWidgets, and make it monitor the clipboard for text. Then, if we detect a change, we're going to add the new contents to a list.
It's a relatively simple process, but unfortunately wxWidgets isn't the most documented GUI toolkit out there.
So, let's get started. I'm gonna pile all the code into a single file instead of breaking my classes up into seperate files, just for ease of navigation in this tutorial. The code is relatively short anyway, with only 62 lines.
First off, as with any other program, we're going to want to get our includes done. We'll be needing three: The standard wx header, the clipboard header, and the thread header.
CODE
#include <wx/wx.h> // standard wx header
#include <wx/clipbrd.h> // clipboard - we'll monitor the clipboard for text
#include <wx/thread.h> // include threads!
The next thing we need to do is declare our
ClipLogger class - this will inherit wxThread, and have two variables: One to hold the most recent text that we got from the clipboard, and one which is a pointer to a
wxListBox object -- the object on the main window which we'll be updating.
CODE
class ClipLogger : public wxThread {
public:
ClipLogger(wxListBox*);
private:
void* Entry(); // the entry point to the thread
wxString LatestText; // store the last text so we can check for changes
wxListBox* list; // the list to update on a text change
};
The constructor is
very simple. All it does is take a wxListBox*, and assign it to a variable stored by the class - this is the list that we want to update on clipboard text changes.
CODE
ClipLogger::ClipLogger(wxListBox* l) {
this->list = l;
}
Next up is the main part of this tutorial. When we create a thread, we need to override the
Entry() method of the class, like so:
CODE
void* ClipLogger::Entry() {
To save time and memory, rather than creating a variable every time we loop, we'll create it before and simply overwrite it inside the loop.
CODE
wxTextDataObject temp;
wxTextDataObject is the type of object that the clipboard will store.
Next, since our thread is a constant "monitor" for the clipboard, we want it to loop.
CODE
while (true) {
Then, we need to think about how we can help our application not be CPU-hungry. The simple solution is to make the thread sleep each time it loops. We can do this with
wxSleep(int time), where time is the length of time to sleep in
seconds.
CODE
wxSleep(1);
The rest of the loop is the clipboard. It's very simple, so rather than break it up line-by-line, I've added comments along the way. We basically need to do the following:
- Open the clipboard
- If the clipboard is text, get it into our
temp variable
- Update the list and remember this is the most recent (so as not to constantly add the same data to the list)
- Close the clipboard
CODE
if (wxTheClipboard->Open()) { // try to open the clipboard
if (wxTheClipboard->IsSupported(wxDF_TEXT)) { // if the clipboard contains text
wxTheClipboard->GetData(temp); // get the data from the clipboard
if (this->LatestText != temp.GetText()) { // if it's changed, we want to update
if (temp.GetText() != wxT("")) { // if it's not an empty string
this->LatestText = temp.GetText(); // update the "LatestText"
this->list->Append(temp.GetText()); // append to the list
}
}
}
}
wxTheClipboard->Close(); // close the clipboard
The last thing left to do in the thread is simply close it off, and close off the loop.
CODE
}
}
Simple, huh?

And that's our thread defined. Now all we need to do is create the app itself, which is a simple process. I hope that you already know how to do it, so we can blitz through the majority of it. If not, you may want to review
this tutorial.
Create the app:
CODE
class threaded_app : public wxApp {
public:
bool OnInit(void);
};
The beginning of the
OnInit() should be nothing new at this point either.
CODE
bool threaded_app::OnInit(void) {
// quickly create a wxFrame to display a window
wxFrame* f = new wxFrame(NULL, wxID_ANY, wxT("Threaded App!"));
// add a list to the frame we created
wxListBox* list = new wxListBox(f, wxID_ANY);
// display the frame
f->Show(true);
The last part of
OnInit() that we need to do is actually create an instance of our thread and run it, like so:
CODE
// pass the list to the clipboard monitor so it knows what to update
ClipLogger* cl = new ClipLogger(list); // construct our thread
cl->Create(); // we have to create a thread before we can run it
cl->Run(); // run our thread
And we can simply finish off the
OnInit() and IMPLEMENT_APP:
CODE
return true;
}
IMPLEMENT_APP(threaded_app)
And that's all there is to threading and using the clipboard in wxWidgets!
Here's the complete code:
CODE
#include <wx/wx.h> // standard wx header
#include <wx/clipbrd.h> // clipboard - we'll monitor the clipboard for text
#include <wx/thread.h> // include threads!
class ClipLogger : public wxThread {
public:
ClipLogger(wxListBox*);
private:
void* Entry(); // the entry point to the thread
wxString LatestText; // store the last text so we can check for changes
wxListBox* list; // the list to update on a text change
};
ClipLogger::ClipLogger(wxListBox* l) {
this->list = l;
}
void* ClipLogger::Entry() {
wxTextDataObject temp; // create a "wxTextDataObject" to get the info from the clipboard
while (true) { // our thread will loop
wxSleep(1); // sleep for 1 second, make the thread less cpu-hungry
if (wxTheClipboard->Open()) { // try to open the clipboard
if (wxTheClipboard->IsSupported(wxDF_TEXT)) { // if the clipboard contains text
wxTheClipboard->GetData(temp); // get the data from the clipboard
if (this->LatestText != temp.GetText()) { // if it's changed, we want to update
if (temp.GetText() != wxT("")) { // if it's not an empty string
this->LatestText = temp.GetText(); // update the "LatestText"
this->list->Append(temp.GetText()); // append to the list
}
}
}
}
wxTheClipboard->Close(); // close the clipboard
}
}
class threaded_app : public wxApp {
public:
bool OnInit(void);
};
bool threaded_app::OnInit(void) {
// quickly create a wxFrame to display a window
wxFrame* f = new wxFrame(NULL, wxID_ANY, wxT("Threaded App!"));
// add a list to the frame we created
wxListBox* list = new wxListBox(f, wxID_ANY);
// display the frame
f->Show(true);
// pass the list to the clipboard monitor so it knows what to update
ClipLogger* cl = new ClipLogger(list); // construct our thread
cl->Create(); // we have to create a thread before we can run it
cl->Run(); // run our thread
return true;
}
IMPLEMENT_APP(threaded_app)
Happy coding!
