Staying up to date with what's happening inside a program is crucial. The user should always know what he is waiting for or what he has to do next. To satisfy this duty, the creators of the Windows Operating System graphic user interface implemented a bar that lets you show various information. Over time this bar has come to be called the Statusbar. Along with other controls, when the MFC Extension Pack was launched, this item got a well-deserved upgrade in the world of MFC. Let us review this interesting part of our applications. This article is the first in an eight-part series.
Contributed by Gabor Bernat Rating: / 2 October 07, 2009
The MFC was quite well received with the Visual Studio 6.0 package, and soon became one of the standards used to create applications under the Windows platform. This makes sense if you also know that MFC is the abbreviation for "Microsoft Foundation Class Library." Moreover, it was mainly developed by Microsoft to make Windows more popular.
However, as time has passed, the people from Redmond realized that it is a little too troublesome to create applications in the world of unmanaged programming. Therefore, they came up with a wise solution: they created a new managed language (C#) that made it a lot easier for people with little or no programming knowledge to create complicated applications. The down side of this was that managed programming also introduced heavy performance penalties.
These penalties must not exist if you create programs that require heavy CPU usage. This is the case when we are talking about video processing and CAD programs. Moreover, for any C# program to work, the presence of the .Net platform is required, because there are no longer machine codes generated, as would be in the case of a MFC program. With these programs, the world of C++ and MFC remains the only choice.
Realizing that they were losing market share with the aging of their MFC platform (not updated since the Visual Studio 2003 release), Microsoft decided to make a move. A little company had the opportunity to make the improvements. You can already see the result as the MFC Feature Pack. Inside this, the Statusbar also gained a couple of improvements. Today, I am going to show you how to use the bar generally, and in a future article, the new additions.
The creators of the MFC Feature Pack tried to keep it as conservative as possible. How things work remain the same. You will find just a couple of subtle changes that build on the old rules. For instance, in its basics, the Statusbar remains the same. Nevertheless, for anybody to make a difference (and of course avoid double declaration of the same class), the Statusbar has the name CMFCStatusBar instead of the CStatusBar. By default, the following is created by the wizard:
The Statusbar is composed by default of the Caps-,Num- and Scrl Lock plus a place for general texts. The first three are the size of a rectangle and include a 3D border These spaces are panes. The leftmost pane has no border and automatically extends to align to the right of tje other panes. You can remove any of these panes. Moreover, you can add other panes as well.
The difference between the old and the new Statusbar is that the new one supports features like displaying images, animations, and progress bars, as well as the ability to respond to mouse double-clicks. However first we need to learn to handle basic text editing. For this, you have two options. You can directly change a pane's text using an update handler, or overwrite the OnSetMessageString. Before I present these options, let us create a new pane in our application, that we will customize.
A pane is indicated via a number. To this pane, there is assigned a default text in the string table of the application. There are a couple of default panes that behave in specific ways. The definitions are as follows (taken from the afxres.h):
// Mode indicators in status bar - these are routed like commands
#define ID_INDICATOR_OVR 0xE704 // overtype mode #define ID_INDICATOR_REC 0xE705 // record mode #define ID_INDICATOR_KANA 0xE706 // kana lock
#define ID_SEPARATOR 0 // special separator
The ID_SEPARATOR is the expandable one. These also have default behavior already implemented. For example, the the caps lock is automatically toggled on and off as the same thing happens on the keyboard. In addition, you may reorganize this by using the indicators variable that you can find inside the Mainframe.cpp.
I added an extra pane for now between the CAP and NUM pane.
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_STATUS_TEXT,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL
};
First, you need to define this variable via the Resource View -> Resource Symbols.
Second, we need to declare a default text for this using the String table of our application. For now, it does not really matter what the text is, as we will change this in the future. Nevertheless, the length of the default text will be taken into account at the calculation of the default size of the pane. Therefore, so that I do not mess with this later or have the text inside the pane clipped, I set a large enough default text:
With this, we have created the pane inside the Statusbar. However, for now we will have the default text:
We have three ways to change the text. I will use the extra space we have to display the current clock and the name of the current day of the week. For this first, I will set up a timed event. Let us trigger it every second to update the clock as the seconds pass by. I have used the WM_TIMER event message. Just add it into the main frame via the class view and properties method. After this, we will set up the timed event as soon as we are ready with the window. The end of the OnCreate() method is perfect. Add the following line:
this->SetTimer(1,1000,NULL);
The first part is the ID of the timed event. Given that we will have only one timed event, any number will do. The second argument states after how many milliseconds the timer should be triggered. To find out the time format, I have used the CTime class and the following lines:
CTime today = CTime::GetCurrentTime();
time = today.Format(_T("%A - %H:%M:%S"));
First, we ask for the local time from the system with the static GetCurrentTime function. The time variable is just a string to store the value. The formatting characters used in the extraction of the current time are the same as for the strftime function. Now that we have the text, we can show it on the Statusbar.
The easiest and most straightforward method is to set the new text in the corresponding text. In my case, the m_wndStatusBar is the CMFCStatusBar declared in the Mainframe class.
m_wndStatusBar.SetPaneText(
m_wndStatusBar.CommandToIndex(ID_STATUS_TEXT),
time );
The panes after the addition are numbered in an increasing order, starting from zero. However, sometimes we might not exactly know in what position that specific text is. For these situations, you can use the CommandToIndex function that will return the current index number of the allocated resource ID. The first argument is the index of the pane, while the second is the text to set. Once you've added this line after finding out the time, when you run the application, success is at hand:
The second option is to assign to it an update controller. This function will be called every time an update is required for the assigned pane. Look at it as an OnDraw function of the pane. To start, assign the corresponding pane to a function as follows:
To make sure that the refresh will be made no matter what, we could force an update by calling the InvalidatePaneContent function with the corresponding index as a parameter. Here you also have the option to enable or disable the text in the message text. I am talking about using the gray or the black font (as you can observe in the case of the caps pane). Of course, you can use this function to perform various other tasks as well:
If you want to mess with the first pane (ID_SEPARATOR), where you can usually see the Ready text, you can use any of these methods. A more advanced technique is to use the OnSetMessageString of the mainframe. Add the following line to the message map:
The default text remains with this the one already defined in the string table for the AFX_IDS_IDLEMESSAGE variable (“Ready”). The ID_SEPARATOR pane is special. By default, multiple traits are already implemented; for instance, writing out the information about menu items or toolbar items when you pause above them. These basic behavior types are also defined in the afxres.h class.
//for application title (defaults to EXE name or name in constructor)
#define AFX_IDS_APP_TITLE 0xE000
// idle message bar line
#define AFX_IDS_IDLEMESSAGE 0xE001
// message bar line when in shift-F1 help mode
#define AFX_IDS_HELPMODEMESSAGE 0xE002
// document title when editing OLE embedding
#define AFX_IDS_APP_TITLE_EMBEDDING 0xE003
// company name
#define AFX_IDS_COMPANY_NAME 0xE004
// object name when server is inplace
#define AFX_IDS_OBJ_TITLE_INPLACE 0xE005
This function will be called whenever this pane requires an update due to a change of state from one of the above to another (except the first time; that counts as an initialization). The one in which we are interested is the AFX_IDS_IDLEMESSAGE. In fact, this is the situation when there is no behavior defined for the pane (there is no specific information to show other than Ready). This information is stored in the wParam variable. That is why we compare it at the input.
Once that is correct, we can do whatever we want. For example, in the case of a document editor, we can check for the current page number and display it. Alternatively, in the case of a paint application, we can just display the current coordinates of the mouse. On the other hand, you can also use it to display some useless information, as I did.
Just play around, hovering over the toolbar items, and you will get the picture.
This is all for today. In the next article, I will continue by presenting the new additions to the Statusbar like the presence of the images, animations, and progress bars; and the ability to respond to mouse double-clicks. For now, I've posted the source code of my creation if you would like to look at it and try it out (I used Visual Studio 9.0 with the MFC Feature Pack):
Thank you for the time you invested in reading this article. I hope you managed to extract some valuable information from it and that you will return for the next part. I encourage you to provide input using the comment feature near this work. I would also like to ask you to rate my piece accordingly. In the end, if you have any other questions, feel free to join the DevHardware forums and ask our experts directly. Live With Passion!