I need a very simple example to know how to use threads with wxGauge

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
User avatar
lionking
Earned a small fee
Earned a small fee
Posts: 17
Joined: Sun Apr 07, 2019 6:07 pm

I need a very simple example to know how to use threads with wxGauge

Post by lionking » Sat Apr 20, 2019 1:45 pm

I have to use "wxGauge" in my app, but when making a process that takes a long time my app freezes, therefore, I have to use threads to solve that problem, but I know that threads are complicated ,so, I want a very simple example to make a thread that works with "wxGauge" in order to make the app does not freeze.

How to do that mission?

User avatar
doublemax
Moderator
Moderator
Posts: 14596
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: I need a very simple example to know how to use threads with wxGauge

Post by doublemax » Sat Apr 20, 2019 2:27 pm

Do you really want to update just a single wxGauge, so that the user can still work with your application while the background thread is working?

Or do you want to display a wxProgressDialog and the user can not use the application during the process? In that case check the second part of this post: viewtopic.php?p=190707#p190707
Use the source, Luke!

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

Re: I need a very simple example to know how to use threads with wxGauge

Post by Kvaz1r » Sat Apr 20, 2019 2:34 pm

As far I know it's better do not use GUI stuff from others thread. So just send message(event) from worker thread and set value for your wxGauge.
I guess you can find something similar in thread sample.

User avatar
lionking
Earned a small fee
Earned a small fee
Posts: 17
Joined: Sun Apr 07, 2019 6:07 pm

Re: I need a very simple example to know how to use threads with wxGauge

Post by lionking » Sat Apr 20, 2019 4:11 pm

doublemax wrote:
Sat Apr 20, 2019 2:27 pm
Do you really want to update just a single wxGauge, so that the user can still work with your application while the background thread is working?
Or do you want to display a wxProgressDialog and the user can not use the application during the process?
Yes, I want to update the wxGauge and the user can still work with the application while the background thread is working.

User avatar
doublemax
Moderator
Moderator
Posts: 14596
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: I need a very simple example to know how to use threads with wxGauge

Post by doublemax » Sat Apr 20, 2019 5:10 pm

Ok, that makes things a little more complicated. The code from the wxThread documentation is almost as minimal as it gets. You can remove the parts for pause and resume if you don't need them.
https://docs.wxwidgets.org/trunk/classwx_thread.html
MyFrame::OnThreadUpdate(wxThreadEvent&) is where you would put the code for the wxGauge update.
Use the source, Luke!

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: I need a very simple example to know how to use threads with wxGauge

Post by alys666 » Sun Apr 21, 2019 12:48 am

to use wxGauge (or any other control from other thread) you must send a message to main thread. i do exactly the things, you need in my code:

my code to send a message from other thread to main frame-

Code: Select all

	void onTick(int ftick) override{
		wxThreadEvent *le = new wxThreadEvent();
		le->SetId(AsyncMessageUID::progress_id); //set message tag for message handler
		le->SetInt(ftick); //set gauge value
		_dst.QueueEvent(le); // send message to main frame(enqueue it in his message queue - it's a thread safe function)
	}
_dst here is a reference to your main frame of wxFrame class.

next, you must declare handler for your async messages in your main frame constructor.

Code: Select all

this->Bind(wxEVT_THREAD,&MyMainFrame::onAsyncEvent,this);
and implement member function inside main frame class,
in its body you can handle all events of your different threads, if they need to communicate
with controls or main frame(just use different message uids).

Code: Select all

void onAsyncEvent(wxThreadEvent &fe){
    if(fe.GetId()==AsyncMessageUID::progress_id) {
      this->progress(fe.GetInt()); //progress here - is just a setting of gauge value.
    }
}
Last edited by doublemax on Sun Apr 21, 2019 7:45 am, edited 1 time in total.
Reason: Added code tags
ubuntu 16.04, wxWidgets 3.0.4

User avatar
doublemax
Moderator
Moderator
Posts: 14596
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: I need a very simple example to know how to use threads with wxGauge

Post by doublemax » Sun Apr 21, 2019 8:30 am

Here's a minimal sample that uses CallAfter() instead of events. The amount of code is the same, but some people may find this easier to follow.
Attachments
minimal.cpp
(8.36 KiB) Downloaded 24 times
Use the source, Luke!

User avatar
lionking
Earned a small fee
Earned a small fee
Posts: 17
Joined: Sun Apr 07, 2019 6:07 pm

Re: I need a very simple example to know how to use threads with wxGauge

Post by lionking » Mon Apr 22, 2019 2:27 am

I wrote the following code as a try:

Code: Select all

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

wxDECLARE_EVENT(wxEVT_PROGRESSBAR_UPDATE, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_PROGRESSBAR_FINISHED, wxThreadEvent);

class ProgressBarThread: public wxThread {
public:
    ProgressBarThread(MainFrm *frame);
    virtual ExitCode Entry();
    ~ProgressBarThread();
protected:
    MainFrm *m_frame;
};

Code: Select all

//thread.cpp
#include "ProgressBarThread.h"

wxDEFINE_EVENT(wxEVT_PROGRESSBAR_UPDATE, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_PROGRESSBAR_FINISHED, wxThreadEvent);

ProgressBarThread::ProgressBarThread(MainFrm *frame) : wxThread(wxTHREAD_DETACHED) {
    this->m_frame = frame;
}

wxThread::ExitCode ProgressBarThread::Entry() {
    while (!TestDestroy()) {
        wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_UPDATE));
    }
    wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_FINISHED));
    return (wxThread::ExitCode)0;
}

ProgressBarThread::~ProgressBarThread() {
    delete m_frame;
}
Then, I have created the following methods in my "wxFrame" (main Window):

Code: Select all

// myframe.cpp
void myFrame::thread_ThreadStart() {
   // "progressBarThread" is a member pointer in  "myFrame" class (ex: ProgressBarThread *progressBarThread;)
    progressBarThread = new ProgressBarThread(this);
    if (progressBarThread->Run() != wxTHREAD_NO_ERROR) {
        wxLogError("Can't create the thread!");
        delete progressBarThread;
        progressBarThread = NULL;
    }
}

void myFrame::thread_ThreadUpdate(wxThreadEvent &event) {
    wxMessageOutputDebug().Printf("MyThread update...\n");
    //this->prograssive_gauge->Pulse();
}

void myFrame::thread_ThreadFinished(wxThreadEvent & event) {
    wxMessageOutputDebug().Printf("MyThread Finished!\n");
    //this->prograssive_gauge->SetValue(0);
}
And finally, I have inserted the following code in myFrame constructor:

Code: Select all

// myframe.cpp -> constructor method
this->Bind(wxEVT_PROGRESSBAR_UPDATE, &MainFrm::thread_ThreadUpdate, this);
this->Bind(wxEVT_PROGRESSBAR_FINISHED, &MainFrm::thread_ThreadFinished, this);
And the following code in the action button:

Code: Select all

// myframe.cpp -> onClickButton method
this->thread_ThreadStart();
The result:
Image

The problem is that the "thread_ThreadUpdate" method is executed continuously and the thread doesn't move to the next method "thread_ThreadFinished", Why?

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

Re: I need a very simple example to know how to use threads with wxGauge

Post by Kvaz1r » Mon Apr 22, 2019 6:22 am

Code: Select all

  while (!TestDestroy()) {
        wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_UPDATE));
    }
lionking wrote:
Mon Apr 22, 2019 2:27 am
The problem is that the "thread_ThreadUpdate" method is executed continuously and the thread doesn't move to the next method "thread_ThreadFinished", Why?
Why it should finished? Your operation only checking TestDestroy/0 so will finish loop only after calling Delete.

Look at example above it contains two condition, one for work (counting) and two for thread state (TestDestroy).

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: I need a very simple example to know how to use threads with wxGauge

Post by alys666 » Mon Apr 22, 2019 9:02 am

The problem is that the "thread_ThreadUpdate" method is executed continuously and the thread doesn't move to the next method "thread_ThreadFinished", Why?

to easy stop your thread add to your MainFrame a member
public:
bool _stopThread=false;

because thread has reference(or pointer) to MainFrame, he can check this var and exit.
write his body as

Code: Select all

wxThread::ExitCode ProgressBarThread::Entry() {
    while (!m_frame->_stopThread) {
        wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_UPDATE));
        wxMilliSleep(100); //sleep for some time, because you could overflow the queue(depends on queue implementation), with such plenty of events
    }
    wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_FINISHED));
    return (wxThread::ExitCode)0;
}
then you must add a button, to switch _stopThread variable from false to true.

or you can just post N events and go out(while you are testing how it works), kinda

Code: Select all

wxThread::ExitCode ProgressBarThread::Entry() {
	for (int i=0; i<N; i++) {
		wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_UPDATE));
		wxMilliSleep(100);
	}
	wxQueueEvent(m_frame, new wxThreadEvent(wxEVT_PROGRESSBAR_FINISHED));
	return (wxThread::ExitCode)0;
}
ubuntu 16.04, wxWidgets 3.0.4

Post Reply