I am trying to show the progress of my windows form application in a panel within the form. However, all the messages show together at the end of when the application completes executing. Is there a way to display the messages as the code - execution "progress" through these messages - just the way it would in an interpreted language?
PS: I am adding the message as a label control to the panel at different points within the code.
Thank you.
You have to invalidate the label every time you change the message:
label1.Text = "Initializing...";
label1.Refresh();
// Do Stuff
label1.Text = "Working...";
label1.Refresh();
// Do Stuff
label1.Text = "Completed.";
label1.Refresh();
Or, it may be worth using a backgroundWorker (or another thread). Whats happening now is that the main thread (the one that also draws the UI) is too busy doing the processing to update the UI.
I'm not sure what language you're using, but Ill assume C#. In that case, create a BackgroundWorker that reports progress. Call the Background worker asynchronously so that it does the processing and use the Reports_Progress event to set the label. You cant set the label in the main Backgroundworker do_work procedure since the label was created by another thread. See this example, it may help (admittedly he sets a progress-bar value but you can just as easily set label text - http://www.dotnetperls.com/progressbar)
If you dont have the Backgroundworker class, you can implement the same logic, just using a different thread.
If you need some more info, let me know.
Related
I'm working on a custom cross platform UI library that needs a synchronous "ShowPopup" method that shows a popup, runs an event loop until it's finished and automatically cancels when clicking outside the popup or pressing escape. Keyboard, mouse and scroll wheel events need to be dispatched to the popup but other events (paint, draw, timers etc...) need to be dispatched to their regular targets while the loop runs.
Edit: for clarification, by popup, I mean this kind of menu style popup window, not an alert/dialog etc...
On Windows I've implemented this fairly simply by calling GetMessage/DispatchMessage and filtering and dispatching messages as appropriate. Works fine.
I've much less experience with Cocoa/OS X however and finding the whole event loop/dispatch paradigm a bit confusing. I've seen the following article which explains how to implement a mouse tracking loop which is very similar to what I need:
http://stpeterandpaul.ca/tiger/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/chapter_5_section_4.html
but... there's some things about this that concern me.
The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and timers might not fire". Might not? Why not, when not, how to make sure they do?
The docs for nextEventMatchingMask:untilDate:inMode:dequeue: states "events that do not match one of the specified event types are left in the queue.". That seems a little odd. Does this mean that if an event loop only asks for mouse events then any pressed keys will be processed once the loop finishes? That'd be weird.
Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close the popup when it's clicked outside, but leaves the click event in the queue so that clicking outside the popup on a another button doesn't require a second click.
I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.
Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in NSApplication run loop does.
Another way of putting all this... what's the Cocoa equivalent of Windows' PeekMessage(..., PM_REMOVE), PeekMessage(..., PM_NOREMOVE) and DispatchMessage().
Any help greatly appreciated.
What exactly is a "popup" as you're using the term? That term means different things in different GUI APIs. Is it just a modal dialog window?
Update for edits to question:
It seems you just want to implement a custom menu. Apple provides a sample project, CustomMenus, which illustrates that technique. It's a companion to one of the WWDC 2010 session videos, Session 145, "Key Event Handling in Cocoa Applications".
Depending on exactly what you need to achieve, you might want to use an NSAlert. Alternatively, you can use a custom window and just run it modally using the -runModalForWindow: method of NSApplication.
To meet your requirement of ending the modal session when the user clicks outside of the window, you could use a local event monitor. There's even an example of just such functionality in the (modern, current) Cocoa Event Handling Guide: Monitoring Events.
All of that said, here are (hopefully no longer relevant) answers to your specific questions:
The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and
timers might not fire". Might not? Why not, when not, how to make
sure they do?
Because timers are scheduled in a particular run loop mode or set of modes. See the answer to question 4, below. You would typically use the event-tracking mode when running an event-tracking loop, so timers which are not scheduled in that mode will not run.
You could use the default mode for your event-tracking loop, but it really isn't a good idea. It might cause unexpected re-entrancy.
Assuming your pop-up is similar to a modal window, you should probably use NSModalPanelRunLoopMode.
The docs for nextEventMatchingMask:untilDate:inMode:dequeue:
states "events that do not match one of the specified event types are
left in the queue.". That seems a little odd. Does this mean that if
an event loop only asks for mouse events then any pressed keys will be
processed once the loop finishes? That'd be weird.
Yes, that's what it means. It's up to you to prevent that weird outcome. If you were to read a version of the Cocoa Event Handling Guide from this decade, you'd find there's a section on how to deal with this. ;-P
Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close
the popup when it's clicked outside, but leaves the click event in the
queue so that clicking outside the popup on a another button doesn't
require a second click.
Yes. Did you notice the "dequeue:" parameter of nextEventMatchingMask:untilDate:inMode:dequeue:? If you pass NO for that, then the event is left in the queue.
I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.
It's hard to know what to tell you without knowing what you're confused about and how the Apple guide failed you.
Are you familiar with handling multiple asynchronous communication channels using a loop around select(), poll(), epoll(), or kevent()? It's kind of like that, but a bit more automated. Not only do you build a data structure which lists the input sources you want to monitor and what specific events on those input sources you're interested in, but each input source also has a callback associated with it. Running the run loop is like calling one of the above functions to wait for input but also, when input arrives, calling the callback associated with the source to handle that input. You can run a single turn of that loop, run it until a specific time, or even run it indefinitely.
With run loops, the input sources can be organized into sets. The sets are called "modes" and identified by name (i.e. a string). When you run a run loop, you specify which set of input sources it should monitor by specifying which mode it should run in. The other input sources are still known to the run loop, but just ignored temporarily.
The -nextEventMatchingMask:untilDate:inMode:dequeue: method is, more or less, running the thread's run loop internally. In addition to whatever input sources were already present in the run loop, it temporarily adds an input source to monitor events from the windowing system, including mouse and key events.
Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in
NSApplication run loop does.
There's old Apple sample code, which is actually their implementation of GLUT. It provides a subclass of NSApplication and overrides the -run method. When you strip away some stuff that's only relevant for application start-up or GLUT, it's pretty simple. It's just a loop around -nextEventMatchingMask:... and -sendEvent:.
How can you tell if a VB6 user control is done loading? Is there a custom UserControl_Loaded event or something?
What do you mean by loading? A UserControl has an Initialize event which you should use to set initial values. VB itself will then load in property values. In any of the other events you can assume the control is set up and ready to go.
You can read about the order of events a UserControl goes through here: https://msdn.microsoft.com/en-us/library/aa242140%28v=vs.60%29.aspx
I tend to put "load" logic into the InitProperties and ReadProperties event handlers. The first one gets called when a UserControl instance is added to a container (Form, another UserControl) within the IDE. The second one gets called on all subsequent "creations" within the IDE and at run time.
You can check Ambient.UserMode to determine whether a subsequent creation's ReadProperties event is due to editing operations vs. an IDE or compiled run.
Initialize events always occur, and before the other two. At that time Ambient and other context objects are not available yet.
See that fine manual: Understanding Control Lifetime and Key Events
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.
I'm finding a common pattern during my WP7 development.
Something takes a long time to display and I want to break down the display into 2 parts - an initial display so I can show a Loading message and start the progress bar then a secondary display where I can load the data.
At the moment I'm trying to do this in a custom control but it could equally apply to user control or a page.
I can't find a way of doing this. Way back in WinForm days there were events I could call before the form was shown and others for after. I guess I'm looking for something similar.
I have also tried to see if I can display a stack panel first with the Loading message then capture an event on that to fire the data loading but nothing so far.
Any ideas?
I'm using Caliburn Micro BTW.
You can use the page's Loaded event or an OnNavigatedTo override to show the Loading message, and then you can use the BackgroundWorker class to run your long-running process on a background thread so that the UI thread remains responsive, and then in the handler for the RunWorkerCompletedEvent handler, which is marshalled onto the UI thread for you, you can hide the loading message and perform your second stage display.
Base question: TStatusBar flickers when calling Update procedure. Ways to painlessly fix this
The executed code is in the questions first posts first part ( you can see light grey separating line ) ...
But - problem is that while this code is executed, form does not automatically activate and focus on the top of all other applications.
I have read these articles:
http://www.installationexcellence.com/articles/VistaWithDelphi/Original/Index.html
http://delphi.about.com/od/formsdialogs/l/aa073101b.htm
but according to them it should be working no matter what. I tried all the TApplicationEvents and TForm events with Show; Visible: Repaint; Refresh; BringToFront; ... nothing works.
So - I think I have two options - multithreading or trapping WM_SYSCOMMAND message and in the SC_ACTIVE event simply repaint form. Could this scenario become successful?
None of your linked articles deal with the problem you are having. What you see is the behaviour of a program that does not process Windows messages, so consequently it will not redraw parts that become invalid, and it will not react to keyboard or mouse input (for example moving or resizing with the mouse, or app activation using the taskbar button).
In your code you call StatusBar1.Update, so at least the status bar text is redrawn, but apart from coming to the foreground your application is probably also ignoring move or resize requests.
You need to process Windows messages in a timely manner, so any execution path that takes more than say 200 or 300 milliseconds needs to make sure that messages are handled, otherwise the application will appear unresponsive or hung.
You have basically three options:
Keep the long running code, and insert calls to Application.ProcessMessages - this will allow Windows messages to be processed. Make sure that you keep the code from being entered again, for instance by disabling all the controls that are used to start the operation.
Rework your code in a way that it appears as a sequence of steps, each taking no more than a few 10 milliseconds. Put calls to the code in a timer event handler, or call it from the Application.OnIdle handler.
Call your code in a worker thread, and post messages to the main GUI thread to update your UI.
All these options have their own pros and cons, and for multithreading especially there is a lot of questions and answers already here on SO. It is the most difficult but best option overall when you are working on anything more than a toy program.