When an object such as a dialog box is created, it sends a message named ON_WM_CREATE. Its syntax is: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); This message takes one argument, which is a pointer to a CREATESTRUCT class. The CREATESTRUCT class provides all the information needed to create a window. It is defined as follows: typedef struct tagCREATESTRUCT { LPVOID lpCreateParams; HANDLE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCSTR lpszName; LPCSTR lpszClass; DWORD dwExStyle; } CREATESTRUCT; When sending the ON_WM_CREATE message, the dialog box is usually created without your intervention but when calling it, you should check that the window has been created. This can be done by checking the result returned by the OnCreate() message from the parent class. If the message returns 0, the window was created. If it returns -1, the class was not created or it would simply be destroyed. Before processing your own implementation of the ON_WM_CREATE message, you should call the implementation of the parent class and find out what value it returns. If the parent return 0, then you can proceed. Once you have done this, you can define your own version. This can be done as follows: int CExerciseDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
return 0;
}
To use this message, in the class definition, type its syntax. In the message table, type the name of the message ON_WM_CREATE(): BEGIN_MESSAGE_MAP(CExerciseDlg, CDialog) ON_WM_CREATE() END_MESSAGE_MAP()
As the most regular host of Windows Controls, a dialog box must be able to handle messages that not only pertain to its own existence but also to the availability, visibility, and behaviors of the controls it is holding. For example, if you create a control and position it on the dialog box, sometimes you will need to initialize it by giving it primary values. The WM_INITDIALOG message fires the OnInitDialog() event after a dialog box has been created but before it displays. This event should be your favorite place to initialize a control that is hosted by the dialog box. Do not initialize controls in your dialog's constructor. Use the constructor only to allocate memory for a dynamically created control using the new operator. If you create a dialog-based application using the MFC Application option, the wizard automatically generates the WM_INITDIALOG message for you. If you add a dialog box to an existing application, this message may not be added automatically. You would have to fire it. In reality, the WM_INITDIALOG message is inherited from the CDialog class. Therefore, you would only be overriding it.
After creating the dialog box, if you want to paint it or draw something on it, such as changing its background color, use the WM_PAINT message. If you create a dialog-based application, this message is automatically generated by the wizard. If you add a dialog-based object to your application and need the OnPaint() event, you would have to add it yourself.
If a dialog object is equipped with one or two scroll bars or one of its controls is based on scrolling operations, when the user clicks a scroll bar, the OnHScroll() or the OnVScroll() event is sent based on the WM_HSCROLL or the WM_VSCROLL messages respectively.
As mentioned already, a regular dialog box is equipped with the system Close button on its title bar. This allows the user to close it any time. As a programmer, one of your jobs is to control your application, to be able to predict "bad moves" from the user. For example, imagine you create a dialog-based object without a Cancel button but with OK (like the most basic message box). If the user clicks the system Close button , you may not know what the user did. The WM_CLOSE message fires the OnClose() event when the user clicks the system Close button. It is important to understand that WM_CLOSE is a message and not a method, meaning it sends a message, it does not take an action. This implies that the OnClose() event fires when the user makes an attempt to close the dialog but before the dialog is actually closed. You can use the OnClose() event to find out what has been done on the dialog prior to the user's attempt to close it. You can also use it to deny closing the dialog box, to warn the user about something, or to do anything that you judge necessary. If you perform some processing, such as validating some values, when the user attempts to close the dialog box, if you still want to close the dialog box, call the parent event handler with CDialog::OnClose(). In fact, this line of code is added to the event if you generate it using the wizard: void CExerciseDlg::OnClose() { // TODO: Add your message handler code here and/or call default CDialog::OnClose(); } If you want to conditionally close the dialog box, you can write a conditional statement that can check whether something is necessary before closing it. If you don't want to close the dialog box, don't call CDialog::OnClose().
Once a dialog box, in fact any (CWnd) window object, has been closed, it must be destroyed so the memory it was using can be reclaimed. If you want to do something before the object is destroyed, use the WM_DESTROY to fire the OnDestroy() event. Before doing anything on this event, first call the OnDestroy() event of the parent class. this can be done as follows: void CExerciseDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
}
As a very early implementer of the Win32 library, the MFC provides various ways of creating a dialog-based application. As we saw already, you can work from scratch. Otherwise, Microsoft Visual Studio provides all the tools and accessories you need. It allows you to combine your knowledge of C++, the MFC library, and other accessories. For example, in the above example, we put all of our code in one file. Most of the time, you will want to spread code in various files, in accordance with the C++ language.
Microsoft Visual C++ provides an easier way to create an application that is mainly based on a dialog box. To use this technique, start a new project and specify that you want to create an MFC Application. In the MFC Application Wizard, set the Application Type to Dialog Based.
As you may have realized by now, a dialog box is created in various objects and files: the "physical" object that is being designed, the representation of the dialog box in the resource file that has the .rc extension, the header resource file that has a .h extension, and the class associated with the dialog box (a header file and/or a source file). Microsoft Visual C++ provides many tools used to create and manage all aspects of a dialog box.
In the Win32 and MFC programming, the resource file is probably the most important aspect of a dialog box. It is used to hold the description of the object. The compiler refers to it when it comes time to display the dialog box (unless it is manipulated with code). Most of the time, you will visually design your dialog box and the objects positioned on it as we will see starting in the next lesson. Sometimes, there will be problems. You may make a change in the designed but for some reason, either the .rc file doesn't get updated, the resource.h doesn't receive the change, or both ignore the new modification. When any of these situations happens, either you will receive a bad message immediately or the compiler would display a bad message box when you compile the project, and the intended result would not appear. In such cases, you can continue making changes or the dialog box or, in some cases, you will have to open the resource file and manually make the necessary changes. As we saw in Lesson 2, when you create an application, you should also create a resource file, a file with the .rc extension. If you start a project using a wizard, the resource file is automatically created for you. The resource file is text-based. This means that you can open it using any text editor. By default, in the Solution Explorer, if you double-click a a file with .rc extension, the Resource View would display. In the Resource View, to access any object, you can expand its parent folder and double-click the object such as a dialog box. The "physical" object would display, ready to be designed. An alternative is to open the resource file as text. Before opening a resource file as text, you should close any opened dialog box that is being designed. To open a resource file as text, in the Solution Explorer, right-click the file with .rc extension and click Open With... In the Open With dialog box, click Classic Editor (Text)
Click OK. You may receive a message box indicating that the resource file is already open and asking you whether you want to open it. If so, click Yes. In the file, locate the section you want. Here is an example of a section for the dialog box: ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_EXAMPLE_DLG DIALOGEX 0, 0, 224, 126 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW CAPTION "Example" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN DEFPUSHBUTTON "OK",IDOK,113,105,50,14 PUSHBUTTON "Cancel",IDCANCEL,167,105,50,14 END Once you get to the section, you can make the necessary changes. Don't change anything you are are sure of. In other words, change only something you know for sure needs to be changed. If you don't know or don't understand why something is there, don't touch it. Whenever in doubts or you are having a second tought, don't change anything. Make a change only if you know exactly what you are doing. Any change you make will have to be understood by the compiler and the studio. If the studio doesn't understand something, the dialog box or any object on it would either be lost or show weird behavior. After making changes to the resource file, save it.
Besides the "physical" resource file, we already know that an application also has a resource header file named Resource.h (or resource.h). This too is a text-based file that you can open and manipulate. For example, you may change the identifier of a dialog box but for some reason the resource header file would not update itself. You can open and change it. To open a resource header file, in the Solution Explorer, double-click the Resource.h (or resource.h) file. Locate the identifier you want to modify and change it.
A class associated with a dialog box is primarily a normal C++-based class. That is, it can have member variables. In many classes you use, the studio will automatically insert some member variables. In the next lessons, we see some ways of adding member variables associated with objects positioned on the dialog box. Still, because we are dealing with a normal class, you can add any members you judge necessary. There are various ways you can add a member variable to a class:
Once a member variable exists, you can perform some operations on it. For example, to access a variable:
One of the operations you can perform on a variable consists of changing or renaming it. You can access the variable in the header file of the class and edit its name. The drawback is that you will have manually locate the variable wherever it is being used and edit its name. This can be cumbersome if the variable has been used in various parts of the project and there is a chance you will forget it in some parts. Fortunately, Microsoft Visual Studio can assist you with this operation. You can rename the variable in one place and its name would be changed everywhere. To rename a member variable, in the top section of the Class View, click the name of the class. In the lower section, right-click the name of the variable and click Properties. In the (Name) field, select the name, change it, and press Enter. In the same way, using the Properties window, you can change any option about the variable.
Besides member variables, a class can have member functions. If you start a project from a wizard, the studio will create some classes and add some member functions to it. You too can (and will) add member functions that you need. There are many ways you can add a member function to a class:
Just as mentioned for a member variable, you can manage a member function. To open a function:
As done for a variable, you can rename a function. The best way to rename a function is to get assistance from Microsoft Visual Studio. To do this, in the top section of the Class View, click the name of the class. In the lower section, click the name of the function. In the (Name) field of the Properties window, change or edit the name, and press Enter. From the the Properties window, you can change any other option you want about the member function. |
|
|||||||||||||||||||||||||||||||||||||
|