Entries for tag "mfc", ordered from most recent. Entry count: 3.
# The Concept of Wait Cursor
Mon
23
Jan 2012
When coding a GUI application, sometimes we have to conduct lengthy operation like loading or saving a file. It would be perfect if every such operation was done on separate, background thread while main thread - the one responsible for windowed interface - would show progress and allow to cancel the operation at any time. But multithreaded programming is hard, so some (not so critical and not so long) operations, like loading a configuration file, are usually done on the main thread, freezing the whole GUI. It's OK as long as the operation takes no longer than a fraction of second or several seconds - just like loading and parsing small configuration file, unless the file is located on a floppy disk :)
But it's good to show to the user that some operation is being performed so he doesn't get angry and terminate your application so quickly. Changing mouse cursor from "Normal" to "Wait" is useful here, so GUI libraries provide functionality for this.
In C#, we do it by setting Cursor property of a Form. Assuming we are inside a method of a Form:
Cursor = Cursors.WaitCursor; // Lengthy process... Cursor = Cursors.Default;
Just don't forget to restore default cursor no matter what's the result of the operation. try-finally section can be useful here to make the wait cursor "exception-safe". Good news is that if you wish to show a MessageBox informing user about an error that happened between setting the cursor to WaitCursor and restoring it, the cursor will change to Default automatically for the time the message window is shown.
It may be tempting to use Application.UseWaitCursor instead, but this method is worse. It requires to go back to main message loop before the cursor change takes effect, so if you set Application.UseWaitCursor = true; then do some time-consuming process inside same function and set Application.UseWaitCursor = false; at the end, user won't see changed cursor at all, whereas setting Cursor property of a form takes effect immediately.
wxWidgets library makes it easy to change cursor to "busy" - as they call it - and restore it at the end of C++ scope by creating an object of class wxBusyCursor on the stack. It will change cursor in its constructor and automatically restore it in destructor of the object.
{ wxBusyCursor busyCursor; // Lengthy process... }
MFC library also has such class. It is called CWaitCursor.
If you know the way to show wait cursor in other GUI libraries, post it in a comment.
Comments | #wxwidgets #.net #mfc #gui Share
# How to Disable Redrawing of a Control
Thu
18
Mar 2010
When coding Windows application with GUI, there is an issue about how long does it take to add lots of items (like hundreds or thousands) into a list view or tree view control. It is caused by redrawing the control after each operation. I've seen this annoying effect in may programs, including some serious, commercial ones. Apparently many programmers don't know there is a simple solution. But first a bit of background...
When coding games, we constantly spin inside a big loop and redraw whole screen every frame. Calculations are separated from rendering so we can, for example, build a list with thousands of items in the computation function and the visible part of the list will start being rendered since the first rendering function call after that. When coding windowed applications, nothing new is drawn onto the screen unless needed. We have to manually do it and we can call redrawing function any time. So how should a list control be refreshed when we add an item into it? It is done automatically after each insert, which is a good solution... unless we want to add hundreds of them.
So GUI library developers provide a functionality to temporarily disable redrawing of a control.
Comments | #.net #mfc #wxwidgets #winapi #gui Share
# Dialog Layout Manager in MFC
Sat
08
Aug 2009
Sometimes I write some tools using C++ and MFC. In the Linux world it is common that GUI windows are resizeable. In Windows its not the case, but sometimes it would be nice to be able to resize a dialog window to see more information, like more rows and colums in a list. After repositioning and resizing controls in a window with my custom code I've decided to automate this task.
There are many possible approaches to this problem. WinAPI (and thus MFC) does not provide by itself any solution to automatically align controls inside a resizeable window. Each control has just its fixed rectangle (left, top, width, height) inside parent window. Delphi VCL uses Align property to snap selected controls (like Panel containing child controls) to left, right, top or bottom edge of the window. Qt encourages to design all windows with Layouts. For example, Vertical Layout splits the window into rows and automatically adjusts controls inside, one under the other.
But the solution of my choice is the one based on .NET. Controls in Windows Forms have a property called Anchor so they can be anchored to any of four possible window edges: left, top, right and bottom. If a controls is anchored only to left and top edges, it just doesn't change its position or size. If the control is anchored to right and bottom edges (for example: a button), it changes its position as window is resized so it preserves its distance to right and bottom edge of the window. If the control is anchored to all four possible window edges, it is resized to preserve distance to all window edges same as designed (for example: a list occupying central part of the window).
I've written a class which I called DialogLayoutManager. It's very easy to use and automates control resizing and repositioning inside an MFC window. All you need to do at the beginning is to create an object of this class, register your controls with selected anchors and call Save method:
m_LayoutManager->SetControl(GetDlgItem(ID_BTN_CANCEL), DialogLayoutManager::ANCHOR_RIGHT | DialogLayoutManager::ANCHOR_BOTTOM); m_LayoutManager->SetControl(GetDlgItem(ID_BTN_OK), DialogLayoutManager::ANCHOR_RIGHT | DialogLayoutManager::ANCHOR_BOTTOM); m_LayoutManager->Save(this);
Layout manager remembers positions and sizes of registered controls together with starting window size. Now all you need to do when the window is resized is to call Restore method. Layout manager will adjust registered controls according to new window size and specified anchors. For example, two buttons showed above will stay in bottom-right corner of the window.
void CDialog01::OnSize(UINT nType, int cx, int cy) { ... if (LayoutManager && LayoutManager->IsSaved()) m_LayoutManager->Restore(this); }
Here is the code of my DialogLayoutManager class and usage example: DialogLayoutManager.cpp. It's easy to translate this code to pure WinAPI.