How to make an event execute immediately ? Topic is solved

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
mybofy
Knows some wx things
Knows some wx things
Posts: 38
Joined: Fri Aug 07, 2015 2:09 pm

How to make an event execute immediately ?

Post by mybofy »

Bonjour

wxWidgets 3.1

My wxFrame : "PhotosToUpload" copies files from directory "srcDir" to directory "destDir"
Works fine.
Now more informative, "PhotosToUpload" call my wxFrame : "FilesToStartMoveAndShown" wich shall do two things
- start the copy of files in "PhotosToUpload" with a wxButton "start" : OK, works
- show a wxListCtrl : "list0", wich should add and show a new item with the name of the file moved, each time a file is moved :
problem : the names of the files moved is shown all together after all the files are moved and not after each file is moved

I use two method :
- in "PhotosToUpload" : filesToStartMoveAndShown->getList0()->InsertItem(index, "name of the current files beiing moved);
- defining a event with wxDEFINE_EVENT(FROM_UPLOAD_TO_AFFICHE_MOVE, wxCommandEvent), with wxPostEvent in "PhotosToUpload" and
the handler in "FilesToStartMoveAndShown"

NB : I want one only class "FilesToStartMoveAndShown", for many class like "PhotosToUpload", example "PhotoToDownload"...

I read much documentation, not really clear.
Should I use wxThread (as in sample thread GUI), wxMutex, other ?
What is the simplest possible ?

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

Re: How to make an event execute immediately ?

Post by doublemax »

Showing some code would have been helpful.

Without knowing more about the "bigger picture", try this:

Code: Select all

getList0()->InsertItem(...)
getList0()->Refresh();    // request redraw
::wxYield();                  // trigger processing events
Use the source, Luke!
Manolo
Can't get richer than this
Can't get richer than this
Posts: 828
Joined: Mon Apr 30, 2012 11:07 pm

Re: How to make an event execute immediately ?

Post by Manolo »

Only the OS dispatches the event to its handler. This means that you can post an event but you don't know when it will be "back" to your app.

The solution doublemax showed may help a bit, because wxYield will give the OS some time and then continue with the next instruction in your code.

Anyhow updating the GUI while some job is doing is the typical case for a working thread (your PhotosToUpload) that sends events to the main GUI thread when it needs to be updated (new item in a list control).
mybofy
Knows some wx things
Knows some wx things
Posts: 38
Joined: Fri Aug 07, 2015 2:09 pm

Re: How to make an event execute immediately ?

Post by mybofy »

Merci.

"The solution doublemax showed" helps.

My application is builded with several modules.
The modules are independent, more or less, each other.
Example : a module include several sub-modules, here "PhotosToUpload", "PhotoToDownload", etc. ; each of that sud-modules send infos to an uniq spcial sub-module which is a GUI, here "FilesToStartMoveAndShown".

There, I am lost.
What is the meaning of the main GUI thread ? It is a wxThread class, wich is a kind of wrapper form my wxFrame "FilesToStartMoveAndShown" ?

If I refer to the example in "wxThread Class Reference" and for my understanding, it is OK to replace the names
MyFrame : FilesToStartMoveAndShown
MyThread : CommonSpecialGuiModule
Then in "OnThreadUpdate(wxThreadEvent&)" I add something like
m_pHandler->getList0()->InsertItem(index, "File moved");

In "PhotosToUpload" I add
CommonSpecialGuiModule *CommonSpecialGuiModule = new CommonSpecialGuiModule(FilesToStartMoveAndShown *handler);
FilesToStartMoveAndShown-> DoStartThread(); (in "PhotosToUpload" instead to be called by a wxMenu ?)

And I use the classical wxPostEvent to send the wxEVT_COMMAND_MYTHREAD_UPDATE event to update the "list0", what is immediately done, safely and robustly ???

That is an correct approach ? Shall I go further in that direction ?
Manolo
Can't get richer than this
Can't get richer than this
Posts: 828
Joined: Mon Apr 30, 2012 11:07 pm

Re: How to make an event execute immediately ?

Post by Manolo »

The Graphic User Interface (GUI) runs in the "main thread", the one where your app executes. It could run in a secondary thread, but then the OS will get confused, the events will go "somewhere", and you app would stop responding to user actions.

An app consists on several tasks to be done. Some may start due to a timer, some due to common OS events (e.g. paint, resize, etc) and normally most due to user clicking a menu, button, etc.
When a task must be done (i.e. the proper handler is called) and only the main thread is active, the rest of tasks wait until this task is over. "rest of tasks" includes GUI update and all other stuff. Here is where wxYield helps: it allows pending events to be handled, at the price of perhaps blocking user action or delaying old actions.

If a taks is quickly done (say a few milliseconds) then it seems as if everything happened "at once": task is done, GUI is updated, user actions are accepted inmediately. No multi-thread is needed.
But if not, then everything is blocked. Think of a slow device (DVD, hard-disk, remote server, etc) being used: user clicks on "cancel" but nothing happens, not even the button changes its color. A case for using a dedicated thread for that task.

It's up to you to decide if your app needs multithreading or not.
A good advice: all GUI action (generate, update, etc) must be done only in the main thread.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to make an event execute immediately ?

Post by ONEEYEMAN »

In addition to Manolo' reply:
You can post an event from the secondary thread to the "main" one in order to update the GUI. It can be either user-declared event or the wxThreadEvent. For an example check the thread sample and event sample.
mybofy
Knows some wx things
Knows some wx things
Posts: 38
Joined: Fri Aug 07, 2015 2:09 pm

Re: How to make an event execute immediately ?

Post by mybofy »

Merci.

Very interesting for me : I understand that I understanded nothing how to works an application...

Some silly questions.

First, what is the "main thread" :
When I create MyApp (class MyApp : public wxApp), the "main tread" is created. All is in "main thread", unless I create secondary thread (with wxThread) ? Right ?

Next, what is "The Graphic User Interface (GUI)" : there is only one GUI for my Application, if mon-thread ? My I say that it is a mecanisme hided, wich cover all the interactions with the user (mouse/key clicks, etc ) in the existing frames in the application ?

I read several times your posts and the official documentation (http://docs.wxwidgets.org/3.1/overview_thread.html) :
"To implement non-blocking operations without using multiple threads you have two possible implementation choices:
"use wxIdleEvent (e.g. to perform a long calculation while updating a progress dialog)
"do everything at once but call wxWindow::Update() or wxApp::YieldFor(wxEVT_CATEGORY_UI) periodically to update the screen."

I believe I forget the idea of multi-threading : my application has - a priori - no blocking operations.
It is better to use wxApp::YieldFor(wxEVT_CATEGORY_UI) or wxApp::YieldFor(wxEVT_CATEGORY_ALL) or only wxApp::Yeld() ?

Sorry for my poor english...
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to make an event execute immediately ?

Post by ONEEYEMAN »

mybofy wrote: Merci.

Very interesting for me : I understand that I understanded nothing how to works an application...
;-)
mybofy wrote: Some silly questions.

First, what is the "main thread" :
When I create MyApp (class MyApp : public wxApp), the "main tread" is created. All is in "main thread", unless I create secondary thread (with wxThread) ? Right ?
There is no such thing as a silly question - only a silly answer....

But to answer the first question - yes, that is correct.
When you create an application it automatically creates a "main" thread for you by the underlying OS.
Then this thread creates a main window and all other GUI controls - list boxes, buttons, etc. And then the user of you application will interact with all those controls using mouse/keyboard or on some platforms with hands/fingers.
mybofy wrote: Next, what is "The Graphic User Interface (GUI)" : there is only one GUI for my Application, if mon-thread ? My I say that it is a mecanisme hided, wich cover all the interactions with the user (mouse/key clicks, etc ) in the existing frames in the application ?
I already touched the answer to this question - GUI or Graphical User Interface is defined as windows with which user is operating the data on the screen, being it a button, grid or a simple list box or even a main frame which holds all those controls the way you designed it.
Or simply put - it is a graphical presentation to the user of what the program will do and can do.
As you can see you answer is not really correct.
mybofy wrote: I read several times your posts and the official documentation (http://docs.wxwidgets.org/3.1/overview_thread.html) :
"To implement non-blocking operations without using multiple threads you have two possible implementation choices:
"use wxIdleEvent (e.g. to perform a long calculation while updating a progress dialog)
"do everything at once but call wxWindow::Update() or wxApp::YieldFor(wxEVT_CATEGORY_UI) periodically to update the screen."

I believe I forget the idea of multi-threading : my application has - a priori - no blocking operations.
It is better to use wxApp::YieldFor(wxEVT_CATEGORY_UI) or wxApp::YieldFor(wxEVT_CATEGORY_ALL) or only wxApp::Yeld() ?

Sorry for my poor english...
As doublemax said - just use "::wxYield();".
You probably know that application will create a main thread for you and this main thread will create a main window with all controls you put in.
Now all those controls are interacting with each other and with the user thru the events - you click the mouse on the button and the program sends an appropriate event to the system for processing.You press the key on the keyboard - the same thing. When you program will need to draw something - it also sends an event to the operating system for processing.
Now in you program you can intercept those events by using an event handler. If the execution time for the handler is significantly large - more than couple of minutes - it is a good idea to tell the user "Hey I'm working!!! Please wait..."
This can be achieved thru the wxProgressDialog (check the dialog sample) or just use busy cursor.
However if the program takes just couple of minutes to run - it is easier to use doublemax' code. What wxYield() does is following - you click on the button and you handler started working, but it work is continuous - meaning it will not return until finished. Which means you as a user will not be able to move the mouse, perform any drawing, type anything, etc. But if you put wxYield() in the handler - it will direct the handler to hold for a quick second and let the OS process any other possible events that occurred and then continue processing.

Now it is up to you to decide how to design you application.

If you have more questions - don't hesitate to ask.

Thank you.
Post Reply