passing data from worker thread to the main

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
cadol_wx
In need of some credit
In need of some credit
Posts: 8
Joined: Thu Jan 30, 2020 3:27 pm

passing data from worker thread to the main

Post by cadol_wx » Mon Feb 24, 2020 5:04 pm

Hello everybody,

I have a newbie question about passing data from a worker thread to the main.

In the examples on-line I found how to attach an integer to an event in a worker thread and how to get it in the event handler of the main thread:

Code: Select all


//in worker thread:
wxThread::ExitCode wrkThr::Entry()
 {
  for (int n=0; n<100; n++)
   {
    this->Sleep(500);

    //notify the main thread
    wxCommandEvent e( wxEVT_COMMAND_TEXT_UPDATED, NUMBER_UPDATE_ID );
   
    //pass some data along the event, a number in this case
    e.SetInt(n);
   
    frmParent->GetEventHandler()->AddPendingEvent(e);
   }
   
  return 0;
 }

...

//in main thread:
void frmMain::OnNumberUpdate(wxCommandEvent& e)
 {
  //setting value in text box
  tbDisp->SetValue(std::to_string(e.GetInt()));
 }


So the main work done by two (probably standard) functions: SetInt(n) and GetInt().

But what if I need to pass two integers? Or an integer and a float? Or even more than two values? I do not need a variable size data, it always be the same type.

Say, if, for example, I use a struct:

Code: Select all

struct strData
 {
  int int1;
  int int2;
  float f1;
 }
How do I pass such a struct from the worker and read it in the main? What's the syntax in the example above?


Thank you in advance!

Kvaz1r
I live to help wx-kind
I live to help wx-kind
Posts: 183
Joined: Tue Jun 07, 2016 1:07 pm

Re: passing data from worker thread to the main

Post by Kvaz1r » Mon Feb 24, 2020 5:18 pm


cadol_wx
In need of some credit
In need of some credit
Posts: 8
Joined: Thu Jan 30, 2020 3:27 pm

Re: passing data from worker thread to the main

Post by cadol_wx » Mon Feb 24, 2020 5:42 pm

Hi Kvaz1r,

Thank you for a quick response. Could you please show how to use SetPayload(), GetPayload() in the example of my post? What's the syntax?

Kvaz1r
I live to help wx-kind
I live to help wx-kind
Posts: 183
Joined: Tue Jun 07, 2016 1:07 pm

Re: passing data from worker thread to the main

Post by Kvaz1r » Mon Feb 24, 2020 6:08 pm

Code: Select all

#include "wx/wx.h"
#include <wx/thread.h>

struct strData
{
    int int1;
    int int2;
    float f1;

    wxString asString() const {
        return wxString::Format("{%d %d %lf}", int1, int2, f1);
    }
};

class MyThread : public wxThread
{
public:
    MyThread(wxEvtHandler* parent) : wxThread(), m_parent(parent) {}

    ExitCode Entry()
    {
        for (unsigned n = 0; n < 10; n++)
        {
            wxThreadEvent *evt = new wxThreadEvent(wxEVT_THREAD);
            strData var;
            var.int1 = n;
            var.int2 = n * n;
            var.f1 = std::sqrt(n);
            evt->SetPayload(var);
            m_parent->QueueEvent(evt);
            this->Sleep(1000);
        }
        return NULL;
    }
protected:
    wxEvtHandler* m_parent;
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
    // ctor(s)
    MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
    {
        m_label = new wxStaticText(this, wxID_ANY, "", wxPoint(10, 100), wxSize(80, -1));

        MyThread* thread = new MyThread(this);
        if (thread->Create() == wxTHREAD_NO_ERROR)
        {
            thread->Run();
        }

        Bind(wxEVT_THREAD, [this](wxThreadEvent& ev)
            {
                m_label->SetLabel(ev.GetPayload<strData>().asString());
            });
    }

    wxStaticText* m_label;
};

class MyApp : public wxApp
{
public:
    virtual bool OnInit() wxOVERRIDE
    {
        if (!wxApp::OnInit())
            return false;

        (new MyFrame("Minimal wxWidgets App"))->Show(true);

        return true;
    }
};
wxIMPLEMENT_APP(MyApp);

cadol_wx
In need of some credit
In need of some credit
Posts: 8
Joined: Thu Jan 30, 2020 3:27 pm

Re: passing data from worker thread to the main

Post by cadol_wx » Mon Feb 24, 2020 6:33 pm

I am trying this:

Code: Select all

struct strData
 {
  int int1;
  int int2;
  float f1;
 }

...

//in worker thread:
wxThread::ExitCode wrkThr::Entry()
 {
  strData d1;

 
  for (int n=0; n<100; n++)
   {
    this->Sleep(500);

    //notify the main thread
    wxCommandEvent e( wxEVT_COMMAND_TEXT_UPDATED, NUMBER_UPDATE_ID );

    d1.int1 = n;
    d1.int2 = n*2;
    d1.f1 = n + 0.14;
    
    //pass struct
    e.SetPayload(d1);  
   
    frmParent->GetEventHandler()->AddPendingEvent(e);
   }
   
  return 0;
 }

...

//in main thread:
void frmMain::OnNumberUpdate(wxCommandEvent& e)
 {
  strData d2;

  d2 = e.GetPayload<strData>();
 
  //setting value in text box
  tbDisp->SetValue(std::to_string(d2.f1))
 }

But I am getting the following compiler errors (CodeLite):

expected primary-expression before '>' token d2 = e.GetPayload<strData>();

expected primary-expression before ')' token d2 = e.GetPayload<strData>();

'class wxCommandEvent' has no member named 'SetPayload' e.SetPayload(strData::d1);

Any idea what's wrong?..

cadol_wx
In need of some credit
In need of some credit
Posts: 8
Joined: Thu Jan 30, 2020 3:27 pm

Re: passing data from worker thread to the main

Post by cadol_wx » Mon Feb 24, 2020 6:50 pm

Hi Kvaz1r,

Thank you! - Your example works perfectly, I am trying to figure out why I am getting those compiler errors when trying to compile mine...

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3893
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: passing data from worker thread to the main

Post by ONEEYEMAN » Mon Feb 24, 2020 8:25 pm

Hi,
You need to use wxThreadEvent and not wxCommandEvent.

After all - this is a threads communication. ;-)

Thank you.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2230
Joined: Sun Jan 03, 2010 5:45 pm

Re: passing data from worker thread to the main

Post by PB » Mon Feb 24, 2020 10:04 pm

And you are supposed to use wxQueueEvent() instead of AddPendingEvent() as well.

Using an existing command event is a bad idea either way, as this one is supposed to be generated by a control and having its fields such as event object set accordingly. It is better to create a new event, it is simple, see e.g. this
viewtopic.php?f=1&t=46485#p194840

cadol_wx
In need of some credit
In need of some credit
Posts: 8
Joined: Thu Jan 30, 2020 3:27 pm

Re: passing data from worker thread to the main

Post by cadol_wx » Tue Feb 25, 2020 5:17 pm

ONEEYEMAN, PB,

Thank you for pointing out at these things. I am in process of adjusting my app accordingly, I will let you know about the result when done.

cadol_wx
In need of some credit
In need of some credit
Posts: 8
Joined: Thu Jan 30, 2020 3:27 pm

Re: passing data from worker thread to the main

Post by cadol_wx » Wed Feb 26, 2020 5:02 pm

Hello Everybody,

Taking your suggestions I've ended up with these two functions which do what I need:

Code: Select all

//in main frame:
void frmMain::OnWorkerThrEvent(wxThreadEvent& e)
 {
  strData d1;
  
  d1 = e.GetPayload<strData>();
  tbDisp->SetValue(std::to_string(d1.f1));
 }


//in worker thread
wxThread::ExitCode wrkThr::Entry()
 {
  int i;
  strData d1;

  wxThreadEvent e(wxEVT_THREAD,ID_WORKER_THREAD);

  for(i = 0; i < 10; i++)
   {
    d1.i1 = i;
    d1.i2 = i * i;
    d1.f1 = i + 0.11;
    
    e.SetPayload(d1);
    wxQueueEvent(frmParent, e.Clone());

    wxMilliSleep(500);
   }//for(i = 0; i < 10; i++)

  //on completion
  d1.f1 = 3.14;
  e.SetPayload(d1);
  wxQueueEvent(frmParent, e.Clone());

  return NULL;
 }//wxThread::ExitCode wrkThr::Entry()
       


Thank you all for your help!

Post Reply