Dialog Based Applications

9
VC++ by BSS 1 CDialog Class The base class used for displaying dialog boxes on the screen. class CDialog : public CWnd Remarks Dialog boxes are of two types: modal and modeless. A modal dialog box must be closed by the user before the application continues. A modeless dialog box allows the user to display the dialog box and return to another task without canceling or removing the dialog box. A CDialog object is a combination of a dialog template and a CDialog-derived class. Use the dialog editor to create the dialog template and store it in a resource, then use the Add Class wizard to create a class derived from CDialog. A dialog box, like any other window, receives messages from Windows. In a dialog box, you are particularly interested in handling notification messages from the dialog box's controls since that is how the user interacts with your dialog box. Use the Properties window to select which messages you wish to handle and it will add the appropriate message-map entries and message-handler member functions to the class for you. You only need to write application-specific code in the handler member functions. If you prefer, you can always write message-map entries and member functions manually. In all but the most trivial dialog box, you add member variables to your derived dialog class to store data entered in the dialog box's controls by the user or to display data for the user. You can use the Add Variable wizard to create member variables and associate them with controls. At the same time, you choose a variable type and permissible range of values for each variable. The code wizard adds the member variables to your derived dialog class. A data map is generated to automatically handle the exchange of data between the member variables and the dialog box's controls. The data map provides functions that initialize the controls in the dialog box with the proper values, retrieve the data, and validate the data. To create a modal dialog box, construct an object on the stack using the constructor for your derived dialog class and then call DoModal to create the dialog window and its controls. If you wish to create a modeless dialog, call Create in the constructor of your dialog class.

Transcript of Dialog Based Applications

Page 1: Dialog Based Applications

VC++ by BSS

1

CDialog Class

The base class used for displaying dialog boxes on the screen.

class CDialog : public CWnd

Remarks

Dialog boxes are of two types: modal and modeless. A modal dialog box must be closed by the user before the application continues. A modeless dialog box allows the user to display the dialog box and return to another task without canceling or removing the dialog box.

A CDialog object is a combination of a dialog template and a CDialog-derived class. Use the dialog editor to create the dialog template and store it in a resource, then use the Add Class wizard to create a class derived from CDialog.

A dialog box, like any other window, receives messages from Windows. In a dialog box, you are particularly interested in handling notification messages from the dialog box's controls since that is how the user interacts with your dialog box. Use the Properties window to select which messages you wish to handle and it will add the appropriate message-map entries and message-handler member functions to the class for you. You only need to write application-specific code in the handler member functions.

If you prefer, you can always write message-map entries and member functions manually.

In all but the most trivial dialog box, you add member variables to your derived dialog class to store data entered in the dialog box's controls by the user or to display data for the user. You can use the Add Variable wizard to create member variables and associate them with controls. At the same time, you choose a variable type and permissible range of values for each variable. The code wizard adds the member variables to your derived dialog class.

A data map is generated to automatically handle the exchange of data between the member variables and the dialog box's controls. The data map provides functions that initialize the controls in the dialog box with the proper values, retrieve the data, and validate the data.

To create a modal dialog box, construct an object on the stack using the constructor for your derived dialog class and then call DoModal to create the dialog window and its controls. If you wish to create a modeless dialog, call Create in the constructor of your dialog class.

Page 2: Dialog Based Applications

VC++ by BSS

2

You can also create a template in memory by using a DLGTEMPLATE data structure as described in the Windows SDK. After you construct a CDialog object, call CreateIndirect to create a modeless dialog box, or call InitModalIndirect and DoModal to create a modal dialog box.

The exchange and validation data map is written in an override of CWnd::DoDataExchange that is added to your new dialog class. See the DoDataExchange member function in CWnd for more on the exchange and validation functionality.

Both the programmer and the framework call DoDataExchange indirectly through a call to CWnd::UpdateData.

The framework calls UpdateData when the user clicks the OK button to close a modal dialog box. (The data is not retrieved if the Cancel button is clicked.) The default implementation of OnInitDialog also calls UpdateData to set the initial values of the controls. You typically override OnInitDialog to further initialize controls. OnInitDialog is called after all the dialog controls are created and just before the dialog box is displayed.

You can call CWnd::UpdateData at any time during the execution of a modal or modeless dialog box.

If you develop a dialog box by hand, you add the necessary member variables to the derived dialog-box class yourself, and you add member functions to set or get these values.

A modal dialog box closes automatically when the user presses the OK or Cancel buttons or when your code calls the EndDialog member function.

When you implement a modeless dialog box, always override the OnCancel member function and call DestroyWindow from within it. Don't call the base class CDialog::OnCancel, because it calls EndDialog, which will make the dialog box invisible but will not destroy it. You should also override PostNcDestroy for modeless dialog boxes in order to delete this, since modeless dialog boxes are usually allocated with new. Modal dialog boxes are usually constructed on the frame and do not need PostNcDestroy cleanup.

Life Cycle of a Dialog Box

During the life cycle of a dialog box, the user invokes the dialog box, typically inside a command handler that creates and initializes the dialog object, the user interacts with the dialog box, and the dialog box closes.

Page 3: Dialog Based Applications

VC++ by BSS

3

For modal dialog boxes, your handler gathers any data the user entered once the dialog box closes. Since the dialog object exists after its dialog window has closed, you can simply use the member variables of your dialog class to extract the data.

For modeless dialog boxes, you may often extract data from the dialog object while the dialog box is still visible. At some point, the dialog object is destroyed; when this happens depends on your code.

Creating and Displaying Dialog Boxes

Creating a dialog object is a two-phase operation. First, construct the dialog object, then create the dialog window. Modal and modeless dialog boxes differ somewhat in the process used to create and display them. The following table lists how modal and modeless dialog boxes are normally constructed and displayed.

Dialog Creation Dialog type How to create it Modeless Construct CDialog, then call Create member function.

Modal Construct CDialog, then call DoModal member function.

To create a modal dialog box, call either of the two public constructors declared in CDialog. Next, call the dialog object's DoModal member function to display the dialog box and manage interaction with it until the user chooses OK or Cancel. This management by DoModal is what makes the dialog box modal. For modal dialog boxes, DoModal loads the dialog resource.

For a modeless dialog box, you must provide your own public constructor in your dialog class. To create a modeless dialog box, call your public constructor and then call the dialog object's Create member function to load the dialog resource. You can call Create either during or after the constructor call. If the dialog resource has the property WS_VISIBLE , the dialog box appears immediately. If not, you must call its ShowWindow member function.

Setting the Dialog Box’s Background Color

You can set the background color of your dialog boxes by handling WM_CTLCOLOR messages for the dialog box window. The color you set is used for only the specified dialog box.

Page 4: Dialog Based Applications

VC++ by BSS

4

Initializing the Dialog Box

After the dialog box and all of its controls are created but just before the dialog box (of either type) appears on the screen, the dialog object's OnInitDialog member function is called. For a modal dialog box, this occurs during the DoModal call. For a modeless dialog box, OnInitDialog is called when Create is called. You typically override OnInitDialog to initialize the dialog box's controls, such as setting the initial text of an edit box. You must call the OnInitDialog member function of the base class, CDialog, from your OnInitDialog override.

Commonly Overridden Member Functions

The following table lists the most likely member functions to override in your CDialog-derived class.

Commonly Overridden Member Functions of Class CDialog Member function

Message it responds to Purpose of the override

OnInitDialog WM_INITDIALOG Initialize the dialog box's controls.

OnOK BN_CLICKED for button IDOK Respond when the user clicks the OK button.

OnCancel BN_CLICKED for button IDCANCEL

Respond when the user clicks the Cancel button.

OnInitDialog , OnOK , and OnCancel are virtual functions. To override them, you declare an overriding function in your derived dialog class using the Properties window.

OnInitDialog is called just before the dialog box is displayed. You must call the default OnInitDialog handler from your override — usually as the first action in the handler. By default, OnInitDialog returns TRUE to indicate that the focus should be set to the first control in the dialog box.

OnOK is typically overridden for modeless but not modal dialog boxes. If you override this handler for a modal dialog box, call the base class version from your override — to ensure that EndDialog is called — or call EndDialog yourself.

OnCancel is usually overridden for modeless dialog boxes.

Page 5: Dialog Based Applications

VC++ by BSS

5

Retrieving Data from the Dialog Object

The framework provides an easy way to initialize the values of controls in a dialog box and to retrieve values from the controls. The more laborious manual approach is to call functions such as the SetDlgItemText and GetDlgItemText member functions of class CWnd, which apply to control windows. With these functions, you access each control individually to set or get its value, calling functions such as SetWindowText and GetWindowText. The framework's approach automates both initialization and retrieval.

Dialog data exchange (DDX) lets you exchange data between the controls in the dialog box and member variables in the dialog object more easily. This exchange works both ways. To initialize the controls in the dialog box, you can set the values of data members in the dialog object, and the framework will transfer the values to the controls before the dialog box is displayed. Then you can at any time update the dialog data members with data entered by the user. At that point, you can use the data by referring to the data member variables.

You can also arrange for the values of dialog controls to be validated automatically with dialog data validation (DDV).

For a modal dialog box, you can retrieve any data the user entered when DoModal returns IDOK but before the dialog object is destroyed.

For a modeless dialog box, you can retrieve data from the dialog object at any time by calling UpdateData with the argument TRUE and then accessing dialog class member variables.

Dialog Data Exchange

If you use the DDX mechanism, you set the initial values of the dialog object's member variables, typically in your OnInitDialog handler or the dialog constructor. Immediately before the dialog is displayed, the framework's DDX mechanism transfers the values of the member variables to the controls in the dialog box, where they appear when the dialog box itself appears in response to DoModal or Create. The default implementation

Page 6: Dialog Based Applications

VC++ by BSS

6

of OnInitDialog in CDialog calls the UpdateData member function of class CWnd to initialize the controls in the dialog box.

The same mechanism transfers values from the controls to the member variables when the user clicks the OK button (or whenever you call the UpdateData member function with the argument TRUE). The dialog data validation mechanism validates any data items for which you specified validation rules.

The following figure illustrates dialog data exchange.

Dialog Data Exchange

UpdateData works in both directions, as specified by the BOOL parameter passed to it. To carry out the exchange, UpdateData sets up a CDataExchange object and calls your dialog class's override of CDialog's DoDataExchange member function. DoDataExchange takes an argument of type CDataExchange. The CDataExchange object passed to UpdateData represents the context of the exchange, defining such information as the direction of the exchange.

When you (or a Code wizard) override DoDataExchange, you specify a call to one DDX function per data member (control). Each DDX function knows how to exchange data in both directions based on the context supplied by the CDataExchange argument passed to your DoDataExchange by UpdateData.

MFC provides many DDX functions for different kinds of exchange. The following example shows a DoDataExchange override in which two DDX functions and one DDV function are called:

void CTestDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Check(pDX, IDC_MY_CHECKBOX, m_bVal); DDX_Text(pDX, IDC_MY_TEXTBOX, m_strName); DDV_MaxChars(pDX, m_strName, 20); }

Page 7: Dialog Based Applications

VC++ by BSS

7

The DDX_ and DDV_ lines are a data map. The sample DDX and DDV functions shown are for a check-box control and an edit-box control, respectively.

If the user cancels a modal dialog box, the OnCancel member function terminates the dialog box and DoModal returns the value IDCANCEL . In that case, no data is exchanged between the dialog box and the dialog object.

Dialog Data Validation

You can specify validation in addition to data exchange by calling DDV functions, as shown in the example in Dialog Data Exchange. The DDV_MaxChars call in the example validates that the string entered in the text-box control is not longer than 20 characters. The DDV function typically alerts the user with a message box if the validation fails and puts the focus on the offending control so the user can reenter the data. A DDV function for a given control must be called immediately after the DDX function for the same control.

You can also define your own custom DDX and DDV routines. For details on this and other aspects of DDX and DDV, see MFC Technical Note 26.

Closing the Dialog Box

A modal dialog box closes when the user chooses one of its buttons, typically the OK button or the Cancel button. Choosing the OK or Cancel button causes Windows to send the dialog object a BN_CLICKED control-notification message with the button's ID, either IDOK or IDCANCEL . CDialog provides default handler functions for these messages: OnOK and OnCancel. The default handlers call the EndDialog member function to close the dialog window. You can also call EndDialog from your own code. For more information, see the EndDialog member function of class CDialog in the MFC Reference.

Page 8: Dialog Based Applications

VC++ by BSS

8

Destroying the Dialog Box

To arrange for closing and deleting a modeless dialog box, override PostNcDestroy and invoke the delete operator on the this pointer. Destroying the Dialog Box explains what happens next.

Modal dialog boxes are normally created on the stack frame and destroyed when the function that created them ends. The dialog object's destructor is called when the object goes out of scope.

Modeless dialog boxes are normally created and owned by a parent view or frame window — the application's main frame window or a document frame window. The default OnClose handler calls DestroyWindow, which destroys the dialog-box window. If the dialog box stands alone, with no pointers to it or other special ownership semantics, you should override PostNcDestroy to destroy the C++ dialog object. You should also override OnCancel and call DestroyWindow from within it. If not, the owner of the dialog box should destroy the C++ object when it is no longer necessary.

CDialog::OnInitDialog

This method is called in response to the WM_INITDIALOG message.

virtual BOOL OnInitDialog( );

Return Value

Specifies whether the application has set the input focus to one of the controls in the dialog box. If OnInitDialog returns nonzero, Windows sets the input focus to the default location, the first control in the dialog box. The application can return 0 only if it has explicitly set the input focus to one of the controls in the dialog box.

Remarks

Windows sends the WM_INITDIALOG message to the dialog box during the Create, CreateIndirect, or DoModal calls, which occur immediately before the dialog box is displayed.

Page 9: Dialog Based Applications

VC++ by BSS

9

Override this method if you want to perform special processing when the dialog box is initialized. In the overridden version, first call the base class OnInitDialog but ignore its return value. You will typically return TRUE from your overridden method.

Windows calls the OnInitDialog function by using the standard global dialog-box procedure common to all Microsoft Foundation Class Library dialog boxes. It does not call this function through your message map, and therefore you do not need a message map entry for this method.

WM_INITDIALOG Message

Sent to the dialog box procedure immediately before a dialog box is displayed. Dialog box procedures typically use this message to initialize controls and carry out any other initialization tasks that affect the appearance of the dialog box.