views:

827

answers:

1

Hello there,

I'm having problem (basically, I'm confused.) while trying to create a worker thread for my wxWidgets GUI application that WILL MODIFY one of the GUI property itself. (In this case, wxTextCtrl::AppendText).

So far, I have 2 source files and 2 header files for the wx program itself (excluding my own libs, MySQL lib, etc), say MainDlg.cpp which contains a derived class of wxFrame called 'MainDlg' and MainForm.cpp which contains a derived class of wxApp called 'MainForm'.

MainForm.cpp

#include "MainHeader.h" // contains multiple header files

IMPLEMENT_APP(MainForm)

bool MainForm::OnInit()
{
    MainDlg *Server = new MainDlg(wxT("App Server 1.0"), wxDEFAULT_FRAME_STYLE - wxRESIZE_BORDER - wxMAXIMIZE_BOX);
    Editor->Show();

    return true;
}

MainDlg.cpp:

#include "MainHeader.h"

BEGIN_EVENT_TABLE(MainDlg, wxFrame)
EVT_BUTTON(6, MainDlg::StartServer)
EVT_BUTTON(7, MainDlg::StopServer)
END_EVENT_TABLE()

CNETServerConnection *cnServCon;
std::string ServerIP, DBHost, DBUser, DBName, DBPass;
int UserCapacity, DBPort, ServerPort;
MYSQL *sqlhnd;

MainDlg::MainDlg(const wxString &title, long style) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(301, 230), style)
{
    cnServCon = new CNETServerConnection(100);
    this->InitializeComponent();
}

void MainDlg::InitializeComponent()
{
    this->SetTitle(wxT("App Server 1.0"));
    this->SetSize(396, 260);
    this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
    this->Centre();

    statBox = new wxTextCtrl(this, 4, wxT("Welcome to AppServer 1.0\n\n"), wxPoint(10, 10), wxSize(371, 141), wxTE_MULTILINE | wxTE_READONLY);

    //.................................
}

void MainDlg::StartServer(wxCommandEvent &event)
{
    this->startBtn->Enable(false);
    this->AppendStatus(wxT("\nLoading server configuration... "));

    //.................................

    this->AppendStatus(wxT("OK\n\nServer ready!\n\n"));

    // When the server is ready, I need to run a thread
    // that will update the statBox (through AppendStatus func or wxTextCtrl::AppendText directly)
    // regularly without interrupting the GUI itself.
    // Because the thread will contain a while-loop
    // to make the program keep receiving message from clients.

    this->startBtn->Hide();
    this->stopBtn->Show();
    this->cmdBtn->Enable();
    this->cmdBox->Enable();
}

void MainDlg::StopServer(wxCommandEvent &event)
{
    //...................................
}

void MainDlg::AppendStatus(const wxString &message)
{
    statBox->AppendText(message);
}

// Well, here is the function I'd like to run in a new thread
void MainDlg::ListenForMessages()
{
    int MsgSender = 0;
    while(1)
    {
        if(!cnServCon->GetNewMessage())
            continue;

        if(MsgSender = cnServCon->GetJoiningUser())
            this->AppendStatus(wxT("Someone connected to the server."));
    }
}

I also found an usage example of wxThread from http://stackoverflow.com/questions/266168/simple-example-of-threading-in-c:

class MessageThread : public wxThread
{
private:
    MessageThread(const MessageThread &copy);
public:
    MessageThread() : wxThread(wxTHREAD_JOINABLE)
    {
    }

    void *Entry(void)
    {
     // My works goes here
     return;
    }
};

wxThread *CreateThread()
{
        wxThread *_hThread = new MessageThread();

        _hThread->Create();
        _hThread->Run();

        return _hThread;
}

But I don't know how to associate it with my program and make it able to modify my GUI property (statBox).

Any kind of help would be appreciated! :)

Thanks.

+4  A: 

The easiest is to create an event type id, and use a wxCommandEvent using the type id, set its string member ("evt.SetText"), and send the event to one of your windows (using AddPendingEvent). In the handler of that event, you can then call AppendText on your control using the text you sent (evt.GetText), because you are in the GUI thread by then.

// in header
DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1)

// in cpp file
DEFINE_EVENT_TYPE(wxEVT_MY_EVENT)

// the event macro used in the event table. id is the window id you set when creating 
// the `wxCommandEvent`. Either use -1 or the id of some control, for example. 
EVT_COMMAND(window-id, event-id, handler-function)

Here is an overview how it works: Custom Events.

Johannes Schaub - litb
+1, didn't know you were a wxWidgets guy litb ;)
GRB
thanks :) **` `**
Johannes Schaub - litb