Why does a simple method trigger a main loop message and then block? - user-interface

Here it was told me something I can't understand about wxPython and other GUI toolkits.
When I call GetLabel from a 'static text' control, there gets an event enqueued and GetLabel doesn't return until this event was processed by the main loop.
Why gets an event enqueued for such a simple task?
Why doesn't the method return immediately, but block til the message was processed?

I don't think GetLabel fires an event. The problem you were having in that other question is that you were using threads to try to manipulate the GUI and get information from it. Your thread is blocking the GUI's main thread. If you called GetLabel() from within your GUI code (such as within an event handler for a button), it would be immediate.

Related

Why does my Timage item work within a while loop inside the onKeyPress method?

I needed to create a application where the Timage can be hide after a certain key is pressed under a certain situation.
I have set KeyPreview to true, and the image can hide within the onKeyPress method, everything worked properly. But as soon as I implemented a while loop inside the onKeyPress method, the image doesn't hide anymore after the appropraite key is being pressed.
What should I do to fix that?
You shouldn't do a WHILE loop inside an event handler. The event handlers should do a simple update to UI and then exit, to allow Delphi to reflect the UI update on screen.
Move your WHILE loop out of the KeyPress event, preferably into a background thread, alternately into the Application.OnIdle event (where you then perform ONE iteration of the WHILE loop within the OnIdle event and turn off processing when the WHILE condition isn't valid anymore).
The "poor man"'s solution (and not one that is recommended, but can be used if all other options are too complicated) is to call
Application.ProcessMessages
either within the WHILE loop (if you are altering UI elements in the loop) or just before starting the WHILE loop (if you're not).
Note, however, that while the "Application.Processmessages" code is running, all other event handlers are capable of being run, so if you, f.ex., run an Application.ProcessMessages within a Timer Event, the Timer Event may be called again before the currently running Timer Event has finished running (leading to an infinite recursive loop and eventually a stack overflow and termination of your program).

Disable modal event processing in WINAPI

As far as I understand, WM_SIZING is a modal message, meaning that the event processing will enter an inner loop and only return to the user when the resizing is over. I also know that this event begins with WM_ENTERSIZEMOVE and ends with WM_EXITSIZEMOVE.
My question is: is there any way to disable this behavior so I can return to my own message loop after every single sizing event?
I know usually updates can be performed by setting a timer - and then killing it at the end of the modal message/event, but I'd like to return the control to my message loop.

Must a ProgessDialog run in an AsyncTask or on a seperate Thread?

I have two activities. The second activity if for data collection from the user (he types in new data) and the first for showing graphs. Once the user finish the second activity (by clicking back), I need to do calculations before the charts update on the MainActivity. It is important that the calculations finish first before activity 2 is finished. The code therefore runs in the onBackPressed method.
There seemed to be three options:
1) Use a thread that does the calculations and update the ProgressDialog with a seperate handler to watch for thread completion. The handler receives a message once the thread is complete and then close the second activity. Android Studio warns me that the handler needs to be static and warns me of memory leaks. So this doesn't seem to be a safe approach.
2) Use an AsyncTask and wait until the AsyncTask is completed before closing activity two. However, it appears meaningless to run a seperate thread or an AsyncTask for calculations that should run on the main thread simply to show a ProgressDialog.
3) Show the ProgressDialog on the main thread. However, this does not seem to be possible.
Could you please point this noob to the right method to show a ProgressDialog while sequentially executing calculations for which the user must wait (only a few seconds).
Thanks,
Jean
Use the AsyncTask in Activity one there is no need to open second activity for load data and calculation you can do that in activity one and just use progress dialog in AsyncTask and close that dailog in postExecute method of Asynctask and Call that AsyncTask on OnCreate() method of Activity One.

How does a modal dialog's message-pump interact with the main application message-pump?

My understanding is any modal dialog automatically has its own message-pump, running on a thread dedicated to that dialog - is that right?
If so, how does a modal dialog's existence affect the main application's message loop? Do both run in parallel, does one take priority?
I have a situation where a modal dialog seems to get stuck for several seconds waiting for something, and wondered if it's possible the dialog is forced to wait until the main application thread is not busy?
As IInspectable explained, the modal dialog will run in the same thread as the caller. Therefore if you run the dialog from the main UI thread that has your main message loop, you'll end up with a nested message loop. The stack would look something like:
WinMain
YourMainMessageLoop
DispatchMessage
SomeMessageHandler
DoModal
and DoModal spins in its own GetMessage/TranslateMessage/DispatchMessage loop. The main message loop (YourMainMessageLoop in the sample stack above) is "active" in the sense that it's still running, but it's blocked by the dialog's message loop. Execution won't return to YourMainMessageLoop until DoModal exits.
Note that even if you're within the modal dialog's message loop, your other windows will still handle messages because GetMessage and DispatchMessage will still retrieve and direct messages to those windows and invoke their WndProcs.

How modal dialog is implemented?

For a long time I have been wondering how modal dialog is implemented.
Let me take Qt as an example. (Nearly all GUI toolkit has this mechanism)
In the main event loop, a slot is called, and in this slot a modal dialog is opened. Before the dialog is closed, the slot doesn't return control to the main event loop. So I thought that the main event loop is blocked and become unresponsive. Apparently this is not true, since when you open a modal dialog, the background main window is still working, like repainting its UI or keep displaying a curve or some graph. It just becomes not to accept any user input.
I did an experiment. I didn't open a modal dialog in the slot, but start a new thread there, and wait for the thread to finish in that slot. This definitely blocked the main event loop.
How modal dialog is implemented after all? How does it keep main event loop unblocked but at the same time blocked the calling slot?
There is only ever a need for a single event loop, and it does not block when a modal dialog appears. Though, I suppose, different toolkits may handle this differently. You would need to consult the documentation to know for sure. Conceptually, however, it all works in the same way.
Every event has a source where the event occured. When a modal dialog appears, the event loop either ignores or redirects all events that originate outside of the dialog. There's really no magic to it. Generally speaking, it's like an if statement in the event loop code that says "if (modal_is_shown() and !event_is_in_modal_window()) {ignore_and_wait_for_next_event()}". Of course, the logic is a bit more complicated, but that's the gist of it.
If you're looking for examples here's another one:
In Tk, there is only ever one event loop. Modal behavior (doesn't have to be dialog, can also be tooltips, textbox etc) is simply implemented by making the main window ignore mouse and keyboard events. All other events like redraws etc. can still be serviced because the event loop is still running.
Tk implements this via the [grab] function. Calling grab on a UI object makes it the only object able to respond to keyboard and mouse events. Essentially blocking all other objects. This doesn't mess with the event loop. It merely temporarily disables event handlers until the grab is released.
It should be noted that Unix-like operating systems running X also has grab built in to the windowing system. So it's not necessarily implemented merely by UI toolkit libraries but is sometimes also a built in feature of the OS. Again, this is implemented by simple blocking/disabling of events instead of instantiating separate event loops. I believe this also used to be the case for the older MacOS before OSX. Not sure about OSX or Windows though. Even though modality is often implemented by the OS itself, toolkits like Qt and Tk often implement their own mechanisms to standardize behaviors across different platforms.
So the conclusion is, it is not necessary to block the main event loop to implement modality. You just need to block the events and/or event handlers.
The answer by https://stackoverflow.com/users/893/greg-hewgill is correct.
However, reading the follow-up discussion between him and https://stackoverflow.com/users/188326/solotim , I feel that there is room for further clarification, by means of prose and some pseudo-code.
I'll handle the prose part with a fact-list:
The main message loop does not run until the modal activity is finished
However, events are still delivered while the modal activity is running
This is because there is a nested event loop within the modal activity.
So far I just repeated Greg's answer, please bear with me as it is for continuity's sake. Below is where I hope to contribute additional, useful info.
The nested event loop is part of the GUI toolkit, and as such, it knows the callback functions related to every window in existence
When the nested event loop raises an event (such as a repaint event directed to the main window), it invokes the callback function associated with that event. Note that "callback" here may refer to a method of a class representing a window, in object-oriented systems.
the callback function does what is needed (e.g., repaint), and returns right back to the nested message loop (the one within the modal activity)
Last, but not least, here's pseudo-code to hopefully illustrate further, using a fictitious "GuiToolkit":
void GuiToolkit::RunModal( ModalWindow *m )
{
// main event loop
while( !GuiToolkit::IsFinished() && m->IsOpen() )
{
GuiToolkit::ProcessEvent(); // this will call
// MainWindow::OnRepaint
// as needed, via the virtual
// method of the base class
// NonModalWindow::OnRepaint
}
}
class AboutDialog: public ModalWindow
{
}
class MainWindow: public NonModalWindow
{
virtual void OnRepaint()
{
...
}
virtual void OnAboutBox()
{
AboutDialog about;
GuiToolkit::RunModal(&about); // blocks here!!
}
}
main()
{
MainWindow window;
GuiToolkit::Register( &window ) // GuiToolkit knows how to
// invoke methods of window
// main event loop
while( !GuiToolkit::IsFinished() )
{
GuiToolkit::ProcessEvent(); // this will call
// MainWindow::OnAboutBox
// at some point
}
}
In general, a modal dialog box of this type is implemented by running its own message loop instead of your application's message loop. Messages directed to your main window (such as timer or paint messages) will still get delivered, even during the modal operation.
In some situations, you may have to be careful that you don't recursively do the same thing repeatedly. For example, if you trigger a modal dialog box on a timer message combined with some persistent flag, you'll want to make sure you don't keep bringing up the same dialog box repeatedly whenever the timer message fires.

Resources