In a Windows application, dialog boxes are the most common object used to get information from the user to the program. Of course, dialog boxes aren't much good without the many controls that can be placed in them. Edit controls, list boxes, combo boxes, radio buttons, check boxes, and other types of controls all work together to provide the application's user with convenient ways to enter data into a program. Without these controls, a dialog box is about as useful as a telephone without number buttons.
In this chapter, you learn to program window controls in dialog boxes. You'll also learn new ways to extract information from a window's controls.
Until now, the programs in this book have featured dialog boxes containing basic controls such as edit controls and buttons. Edit controls and buttons are probably the most important types of controls at your disposal. However, often you can give your program's user easier methods of selecting the data that must be entered into the program.
There are several types of controls you can place in a dialog box, including check boxes, radio buttons, list boxes, combo boxes, and scroll bars. You should already be familiar with how these controls work, both from a user's and a programmer's point of view. If you've never programmed with Microsoft Foundation Classes, you may not be familiar with the classes with which MFC encapsulates each of the window controls. These classes include CButton, CEdit, CStatic, CListBox, and CComboBox.
Although MFC supplies classes that encapsulate the many window controls, Windows provides most of the services needed to handle these controls. A description of each window control follows:
As mentioned previously, you can add any of these controls to a dialog box simply by using Developer Studio's dialog box editor. Figure 8.1 shows the dialog box under construction in this chapters first program, Control1.
The dialog box under construction in Developer Studio's resource editor contains several standard Windows controls.
This chapter's sample program is called Control1. You can find the source code and executable file for this program in the CHAP08\CONTROL1 folder on this book's CD-ROM. When you run Control1, you see the window shown in Figure 8.2. This window shows the data that the user has currently selected from the application's dialog box. At the start of the program, this data is set to default values. The EDIT CONTROL field of the display shows the current string copied from the dialog box's edit control. The RADIO BUTTON field shows which radio button in the dialog box is selected. The CHECK BOX fields show the status of each of the three check boxes. The LIST BOX field shows the string currently selected in the list box, and the COMBO BOX field shows the currently selected string in the combo box.
The Control1 application's main window shows the controls' settings.
To find out where all these controls are, select the Dialog, Test command to bring up the Control Dialog dialog box shown in Figure 8.3. This
dialog box contains the controls whose data is shown in the main window. You can change the controls' setting any way you want. When you exit the Control
Dialog dialog box via the OK button, the main window displays the controls' new settings. Exiting the dialog box by clicking the Cancel button has no effect on the
main window's display, because any changes made to the data in the dialog box are ignored.
The Control1 application's dialog box enables you to manipulate several standard Windows controls.
As you experimented with the Control1 application, it may have seemed to you that the program doesn't do a heck of a lot more than the dialog box sample you created in chapter 7, Programming Dialog Boxes. The truth is, it's not so much what the Control1 application does, but rather how it does it. Specifically, the controls in the application's dialog box are associated with MFC control classes so that the program can directly manipulate the controls. In this section, you'll see how this bit of MFC trickery is accomplished.
Listings 8.1 through 8.4 are the most pertinent source code files for the Control1 application. Listings 8.1 and 8.2 comprise the application's CMainFrame class, which represents the application's main window.
Listing 8.1 MAINFRM.H The Header File for the Main Window Class
/////////////////////////////////////////////////////////// // MAINFRM.H: Header file for the CMainFrame class, which // represents the application's main window. /////////////////////////////////////////////////////////// class CMainFrame : public CFrameWnd { // Protected data members. protected: CString m_edit1; int m_radio1; int m_radio2; int m_radio3; CString m_combo1; int m_check1; int m_check2; int m_check3; CString m_list1; // Constructor and destructor. public: CMainFrame(); ~CMainFrame(); // Overrides. protected: virtual BOOL PreCreateWindow(CREATESTRUCT& cs); // Message map functions. protected: // System message handlers. afx_msg void OnPaint(); // Menu command message handlers. afx_msg void OnDialogTest(); // Update command UI handlers. // None. // Protected member functions. protected: DECLARE_MESSAGE_MAP() };
Listing 8.2 MAINFRM.CPP The Implementation File for the Main Window Class
/////////////////////////////////////////////////////////// // MAINFRM.CPP: Implementation file for the CMainFrame // class, which represents the application's // main window. /////////////////////////////////////////////////////////// #include <afxwin.h> #include "mainfrm.h" #include "resource.h" #include "cntldlg.h" BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) // Message map entries for system messages. ON_WM_PAINT() // Message map entries for menu commands. ON_COMMAND(IDM_DIALOG_TEST, OnDialogTest) // Message map entries for update command UI handlers. // None. END_MESSAGE_MAP() /////////////////////////////////////////////////////////// // CMainFrame: Construction and destruction. /////////////////////////////////////////////////////////// CMainFrame::CMainFrame() { // Create the main frame window. Create(NULL, "Control App", WS_OVERLAPPEDWINDOW, rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU1)); // Initialize the class's data members. m_edit1 = "Default"; m_radio1 = 1; m_radio2 = 0; m_radio3 = 0; m_combo1 = "ComboString1"; m_check1 = 1; m_check2 = 0; m_check3 = 0; m_list1 = "ListString1"; } CMainFrame::~CMainFrame() { } /////////////////////////////////////////////////////////// // Overrides. /////////////////////////////////////////////////////////// BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { // Set the size of the main window. cs.cx = 330; cs.cy = 200; // Call the base class's version. BOOL returnCode = CFrameWnd::PreCreateWindow(cs); return returnCode; } /////////////////////////////////////////////////////////// // Message map functions. /////////////////////////////////////////////////////////// void CMainFrame::OnPaint() { // Create a device context. CPaintDC paintDC(this); // Have Windows fill in a TEXTMETRIC structure. TEXTMETRIC textMetric; paintDC.GetTextMetrics(&textMetric); // Initialize the vertical position of a text line. UINT position = 10; // Display the edit control's contents. paintDC.TextOut(10, position, "EDIT CONTROL:"); paintDC.TextOut(150, position, m_edit1); // Display the state of the radio buttons. position += textMetric.tmHeight; paintDC.TextOut(10, position, "RADIO BUTTON:"); if (m_radio1) paintDC.TextOut(150, position, "Button #1 chosen"); else if (m_radio2) paintDC.TextOut(150, position, "Button #2 chosen"); else paintDC.TextOut(150, position, "Button #3 chosen"); // Display the selected combo box string. position += textMetric.tmHeight; paintDC.TextOut(10, position, "COMBO BOX:"); paintDC.TextOut(150, position, m_combo1); // Display the status of the check boxes. position += textMetric.tmHeight; paintDC.TextOut(10, position, "CHECK BOXES:"); if (m_check1) paintDC.TextOut(150, position, "Check 1 selected"); else paintDC.TextOut(150, position, "Check 1 not selected"); position += textMetric.tmHeight; if (m_check2) paintDC.TextOut(150, position, "Check 2 selected"); else paintDC.TextOut(150, position, "Check 2 not selected"); position += textMetric.tmHeight; if (m_check3) paintDC.TextOut(150, position, "Check 3 selected"); else paintDC.TextOut(150, position, "Check 3 not selected"); // Display the selected list box string. position += textMetric.tmHeight; paintDC.TextOut(10, position, "LIST BOX:"); paintDC.TextOut(150, position, m_list1); } void CMainFrame::OnDialogTest() { // Create and display the dialog box. CCntlDlg dialog(this); int result = dialog.DoModal(); if (result == IDOK) { // Save the contents of the dialog box. m_edit1 = dialog.m_edit1; m_radio1 = dialog.m_radio1; m_radio2 = dialog.m_radio2; m_radio3 = dialog.m_radio3; m_combo1 = dialog.m_combo1; m_check1 = dialog.m_check1; m_check2 = dialog.m_check2; m_check3 = dialog.m_check3; m_list1 = dialog.m_list1; // Force the window to repaint. Invalidate(); } }
Listings 8.3 and 8.4 are the source code files for the CCntlDlg class, which represents the dialog that appears when you select the application's Dialog,
Test command. Because there are few changes to the application class as compared with other programs in this book, the CONTROL1.H and
CONTROL1.CPP files, which are the source code for the CControl1App class, are not shown here.
Listing 8.3 CNTLDLG.H The Header File for the Dialog Box Class
/////////////////////////////////////////////////////////// // CNTLDLG.H: Header file for the CCntlDlg class. /////////////////////////////////////////////////////////// class CMainFrame; class CCntlDlg : public CDialog { // Class data members. protected: CString m_edit1; int m_radio1; int m_radio2; int m_radio3; int m_check1; int m_check2; int m_check3; CString m_list1; CString m_combo1; // Constructor. public: CCntlDlg(CWnd* pParent); // Overrides. protected: virtual BOOL OnInitDialog(); virtual void OnOK(); friend CMainFrame; };
Listing 8.4 CNTLDLG.CPP The Implementation File for the Dialog Box Class
/////////////////////////////////////////////////////////// // CNTLDLG.CPP: Implementation file for the CCtrlDlg class. /////////////////////////////////////////////////////////// #include <afxwin.h> #include "resource.h" #include "cntldlg.h" /////////////////////////////////////////////////////////// // CONSTRUCTOR /////////////////////////////////////////////////////////// CCntlDlg::CCntlDlg(CWnd* pParent) : CDialog(IDD_CONTROLDIALOG, pParent) { } /////////////////////////////////////////////////////////// // Overrides. /////////////////////////////////////////////////////////// BOOL CCntlDlg::OnInitDialog() { // Make sure the base class gets initialized properly. CDialog::OnInitDialog(); // Set the text in the edit box. CEdit* pEdit1 = (CEdit*)GetDlgItem(IDC_EDIT1); pEdit1->SetWindowText("Default"); // Select the first radio button. CButton* pRadio1 = (CButton*)GetDlgItem(IDC_RADIO1); pRadio1->SetCheck(TRUE); // Select the first check box. CButton* pCheck1 = (CButton*)GetDlgItem(IDC_CHECK1); pCheck1->SetCheck(TRUE); // Add strings to the list box and select the // first string in the list. CListBox* pList1 = (CListBox*)GetDlgItem(IDC_LIST1); pList1->AddString("ListString1"); pList1->AddString("ListString2"); pList1->AddString("ListString3"); pList1->AddString("ListString4"); pList1->AddString("ListString5"); pList1->AddString("ListString6"); pList1->SetCurSel(0); // Add strings to the combo box and select // the first string in the list. CComboBox* pCombo1 = (CComboBox*)GetDlgItem(IDC_COMBO1); pCombo1->AddString("ComboString1"); pCombo1->AddString("ComboString2"); pCombo1->AddString("ComboString3"); pCombo1->AddString("ComboString4"); pCombo1->AddString("ComboString5"); pCombo1->AddString("ComboString6"); pCombo1->SetCurSel(0); return TRUE; } void CCntlDlg::OnOK() { // Get the text in the edit box. CEdit* pEdit1 = (CEdit*)GetDlgItem(IDC_EDIT1); pEdit1->GetWindowText(m_edit1); // Get the states of the radio buttons. CButton* pRadio = (CButton*)GetDlgItem(IDC_RADIO1); m_radio1 = pRadio->GetCheck(); pRadio = (CButton*)GetDlgItem(IDC_RADIO2); m_radio2 = pRadio->GetCheck(); pRadio = (CButton*)GetDlgItem(IDC_RADIO3); m_radio3 = pRadio->GetCheck(); // Get the states of the check boxes. CButton* pCheck = (CButton*)GetDlgItem(IDC_CHECK1); m_check1 = pCheck->GetCheck(); pCheck = (CButton*)GetDlgItem(IDC_CHECK2); m_check2 = pCheck->GetCheck(); pCheck = (CButton*)GetDlgItem(IDC_CHECK3); m_check3 = pCheck->GetCheck(); // Get the list box's selected string. CListBox* pList1 = (CListBox*)GetDlgItem(IDC_LIST1); int listIndex = pList1->GetCurSel(); pList1->GetText(listIndex, m_list1); // Get the combo box's selected string. CComboBox* pCombo1 = (CComboBox*)GetDlgItem(IDC_COMBO1); int comboIndex = pCombo1->GetCurSel(); pCombo1->GetLBText(comboIndex, m_combo1); // Call the base class's OnOK() in order to // shut down the dialog box. CDialog::OnOK(); }
Declaring a Friend Function
In Chapter 7, Programming Dialog Boxes, you may recall that I mentioned two ways for a window class to get access to a dialog box class's data members. The first, which was demonstrated in that previous chapter, is to declare the dialog box class's data members (at least, the data members that must participate in the data exchange) as public. While this solution is easy to accomplish, it's not as elegant as it could be, because it grants access not only to the window class that must access the dialog box variables, but also to any other class that might try to gain such access.
See Writing a Dialog Box Class, (ch. 7)
A good way to limit this uncontrolled access is to make the window class that needs to read information from the dialog box class a friend of the dialog box class. A class declared as a friend of another class has access to that class's public, protected, and even private data members. However, the access is limited to the friend class. No other class can access the protected and private data members.
The Control1 application uses the friend access method to share the dialog box class's variables with the main window class. If you look at the top of the CCntlDlg class's header file (Listing 8.3), you see this line:
class CMainFrame;
This line tells the compiler that the identifier CMainFrame represents a class. Near the end of the CCntlDlg class's header file, you'll see why the compiler needs this information. The line
friend CMainFrame;
tells the compiler to make the CMainFrame class a friend of the CCntlDlg class, giving CMainFrame access to all of CCntlDlg's data members. This is all the code it takes just two lines to limit outside access of CCntlDlg's variables to the CMainFrame class.
As you know, MFC features many classes for window controls. You were introduced to these classes in Chapter 1, "An Introduction to MFC." The control classes were also mentioned at the beginning of this chapter. Up until now, however, you haven't used these classes with the controls you added to your dialog boxes. This is because, in many cases, you don't to need manipulate a control at that level. You just display your dialog box and let the controls take care of themselves. There are times, though, when it's handy to be able to manipulate a control directly, which is what the many control classes such as CEdit, CButton, and CListBox enable you to do.
Each of the control classes features member functions that do everything from initialize the contents of the control to respond to Windows messages. But to use these member functions, you must first associate the control with the appropriate class. For example, to manipulate an edit box through MFC, you must first associate that control with the CEdit class. Then, you can use the CEdit class's member functions to manage the control.
To associate a control with a class, you must first get a pointer to the control. You can do this easily by calling the GetDlgItem() member function, which a dialog box class inherits from CWnd. You call GetDlgItem() like this:
CEdit* pEditControl = (CEdit*)GetDlgItem(IDC_EDIT1);
The GetDlgItem() function returns a pointer to a CWnd object. (Remember: Every control class has CWnd as a base class.) It's single argument is the resource ID of the control for which you want the pointer. To gain access to the member functions of a control class, the returned CWnd pointer must be cast to the appropriate type of pointer. In the above line, you can see that GetDlgItem()'s return value is being cast to a CEdit pointer.
Once you have the pointer, you can access the class's member functions through that pointer. For example, to set the contents of the edit control for which the previous code line got a pointer, you'd use a line like this:
pEditControl->SetWindowText("Text for the edit control");
In the Control1 application, the program uses the above technique to create a simple data transfer mechanism for the dialog box, without calling upon MFC's DDX functions. The dialog box class first declares in its header file data members for holding the information the user entered into the dialog box, as shown in Listing 8.5.
Listing 8.5 LST08_05.CPP Declaring Data Members for the Dialog Box Class
protected: CString m_edit1; int m_radio1; int m_radio2; int m_radio3; int m_check1; int m_check2; int m_check3; CString m_list1; CString m_combo1;
As you can see, there is one variable for each dialog box control with which the user can interact. Notice also that these data members are declared as protected. However, in spite of their protected status, the CMainFrame class can access them, because CMainFrame is a friend class of CCntlDlg.
If you recall, the Control1 application's dialog box appears with default values already selected in its controls. For example, the edit box appears with the text "Default," and the first radio button in the radio button group is selected. Obviously, these controls are being initialized somewhere in the program and that somewhere is the CCntlDlg class's OnInitDialog() function. The OnInitDialog() function gets called as part of the dialog box creation process (specifically, it responds to the WM_INITDIALOG Windows message). Because OnInitDialog() is a virtual function of the CDialog class, however, you don't need to create an entry in a message map. Just override the function in your custom dialog box class.
In your overridden OnInitDialog(), you must first call the base class's version, like this:
CDialog::OnInitDialog();
Then, you can perform whatever special initialization is required by your dialog box class. In the CCntlDlg class, that initialization is setting the various controls to their default values. First, the program sets the edit box, like this:
CEdit* pEdit1 = (CEdit*)GetDlgItem(IDC_EDIT1); pEdit1->SetWindowText("Default");
This code is very similar to the example you saw earlier in this section.
Next, the program sets the radio button group to its default state, which is the first button selected, like this:
CButton* pRadio1 = (CButton*)GetDlgItem(IDC_RADIO1); pRadio1->SetCheck(TRUE);
The SetCheck() member function of the CButton class determines the check state of a button. Although the preceding example uses TRUE as the function's argument, there are actually three possible settings: 0 turns off the check mark; 1 turns on the check mark; and 2 sets the button control to its "indeterminate" state. However, you can use 2 only when you've given the button the BS_3STATE or BS_AUTO3STATE style (which applies mostly to check boxes rather than radio buttons).
After setting the radio buttons, the program performs similar initialization on the first check box, like this:
CButton* pCheck1 = (CButton*)GetDlgItem(IDC_CHECK1); pCheck1->SetCheck(TRUE);
Setting the checked state of buttons is pretty easy. Initializing a list box, however, takes a little extra work, as shown in Listing 8.6.
Listing 8.6 LST08_06.CPP Initializing a List Box
CListBox* pList1 = (CListBox*)GetDlgItem(IDC_LIST1); pList1->AddString("ListString1"); pList1->AddString("ListString2"); pList1->AddString("ListString3"); pList1->AddString("ListString4"); pList1->AddString("ListString5"); pList1->AddString("ListString6"); pList1->SetCurSel(0);
The AddString() member function of the CListBox class, adds a string to the contents of the list box. So, the code in Listing 8.6 adds the six selections that the user can choose from the list box. The SetCurSel() function, also a member of the CListBox class, determines which of the entries on the list box are selected. The function's single argument is the zero-based index of the item to select. So, an index of 0 selects the first item in the list. An index of [ms]1 initializes the list box without a selection.
A combo box is not unlike a list box when it comes to initialization, as you can see in Listing 8.7.
Listing 8.7 LST08_07.CPP Initializing a Combo Box
CComboBox* pCombo1 = (CComboBox*)GetDlgItem(IDC_COMBO1); pCombo1->AddString("ComboString1"); pCombo1->AddString("ComboString2"); pCombo1->AddString("ComboString3"); pCombo1->AddString("ComboString4"); pCombo1->AddString("ComboString5"); pCombo1->AddString("ComboString6"); pCombo1->SetCurSel(0);
The preceding lines work exactly like the similar lines used to initialize the list box, adding six strings to the combo box's list, and then making the first string the default selection in the list. That is, the first string will already be entered into the combo box's edit box when the dialog box appears.
If you want to create a dialog box class that retains the most recently entered data, use OnInitDialog() to copy the contents of the appropriate class data members to the controls rather than using "hard-coded" data as is done in the Control1 application. Using this method, you enable the Windows class that creates the dialog box object to initialize the dialog box's controls, by copying data into the dialog box class's data members before displaying the dialog box.
Once the dialog box appears on the screen, the user can enter whatever data he likes into the dialog box's controls. The Control1 application doesn't regain control until the user exits the dialog box, by clicking either the Cancel or OK buttons. As with most dialog boxes, if the user clicks the Cancel button (indicated by a return value of IDCANCEL from DoModal()), the program simply ignores any changes that may have been made in the dialog box. However, if the user exits the dialog box via the OK button, the program must transfer the dialog box's data from the controls to the dialog box class's data members. If the dialog box is allowed to close before the controls' contents are copied, the data disappears along with the dialog box.
So, in order to copy data from the dialog box's controls to the class's data members, a program must first know when the user has clicked the OK button. This is done by overriding the dialog box class's OnOK() member function. In OnOK(), the program associates controls with the appropriate control classes, and then uses the class member functions to perform whatever tasks are required to process the dialog box's data before the dialog box is deleted.
If your dialog box class needs to know before the dialog box is removed from the screen when the user has clicked the Cancel button, you can override the OnCancel() member function. After processing the Cancel button as required for your application, you'll usually want to call CDialog::OnCancel() to continue with the cancel process.
In the Control1 application, the OnOK() function first extracts the contents of the edit box, like this:
CEdit* pEdit1 = (CEdit*)GetDlgItem(IDC_EDIT1); pEdit1->GetWindowText(m_edit1);
The first of these two lines gets a pointer to the edit control and casts it to a CEdit pointer. The program can then use the pointer to call the CEdit member function GetWindowText(), whose single argument is a string object into which the edit box's contents should be copied.
The program copies the contents of the radio buttons similarly, as shown in Listing 8.8.
Listing 8.8 LST08_08.CPP Storing the Status of the Radio Buttons
// Get the states of the radio buttons. CButton* pRadio = (CButton*)GetDlgItem(IDC_RADIO1); m_radio1 = pRadio->GetCheck(); pRadio = (CButton*)GetDlgItem(IDC_RADIO2); m_radio2 = pRadio->GetCheck(); pRadio = (CButton*)GetDlgItem(IDC_RADIO3); m_radio3 = pRadio->GetCheck();
Here, after getting a pointer to each control and casting it to the CButton class, the program calls the CButton member function GetCheck() to obtain the status of each of the radio buttons. GetCheck() returns a 0, 1, or 2, depending on whether the control is in an unchecked, checked, or indeterminate state, respectively.
The program gets the contents of the check boxes in almost exactly the same way, as shown in Listing 8.9.
Listing 8.9 LST08_09.CPP Storing the Status of the Check Boxes
CButton* pCheck = (CButton*)GetDlgItem(IDC_CHECK1); m_check1 = pCheck->GetCheck(); pCheck = (CButton*)GetDlgItem(IDC_CHECK2); m_check2 = pCheck->GetCheck(); pCheck = (CButton*)GetDlgItem(IDC_CHECK3); m_check3 = pCheck->GetCheck();
As you can see, the CButton class handles both radio buttons and check boxes. The only difference between Listing 8.8 and 8.9 is the resource IDs used to obtain pointers to the buttons.
The following lines show how the Control1 application extracts data from the list box control:
CListBox* pList1 = (CListBox*)GetDlgItem(IDC_LIST1); int listIndex = pList1->GetCurSel(); pList1->GetText(listIndex, m_list1);
The first line above obtains a pointer to the list box control and associates it with the CListBox class. With the CListBox pointer in hand, the program can call the GetCurSel() member function, which returns the zero-based index of the selected item in the list box. Finally, a call to the CListBox member function GetText() copies the selected text string into the CCntlDlg class's m_list1 data member. GetText()'s two arguments are the index of the text item to get and a reference to a CString object into which to store the string. (The second argument can also be a pointer to a char array.)
As you may have guessed, the program can copy the contents of the combo box in almost exactly the same manner, like this:
CComboBox* pCombo1 = (CComboBox*)GetDlgItem(IDC_COMBO1); int comboIndex = pCombo1->GetCurSel(); pCombo1->GetLBText(comboIndex, m_combo1);
As always, the first line gets a pointer to the control; only this time the pointer is cast to a CComboBox pointer. The second line gets the zero-based index of the selected item in the combo box, whereas the third line copies the selected text line to the CCntlDlg class's m_combo1 data member. The CComboBox class's GetLBText() member function works just like the CListBox class's GetText(), the two arguments being the index of the text item to get and a reference to a CString object into which to store the string. (Again, the second argument can also be a pointer to a char array.)
At this point in the program, all the important data has been copied from the dialog box's controls into the dialog box class's data members, which means it's now safe to remove the dialog box from the screen. Removing the dialog box is as simple as calling the base class's OnOK() member function, like this:
CDialog::OnOK();
You can also use the OnOK() member function to perform data validation. To do this, after extracting the contents of a control, determine whether the control's data is valid. If the data is not valid, display a message box to the user describing the problem, and then return from OnOK() without calling CDialog::OnOK(). Not calling CDialog::OnOK() leaves the dialog box on the screen so the user can correct the bad entry.
As you've seen, you can create your own data transfer and validation mechanisms by directly manipulating controls in a dialog box. Those DDX and DDV functions don't seem so mysterious now, do they? (You can, of course, do much more with your dialog box's controls than copy and validate data. In fact, once you have a pointer to a control, you can call any of the control's member functions.) The final step is to display your dialog box from within your main program, usually from a window class.
The Control1 application displays the dialog box in response to its Dialog, Test command, which is handled by the OnDialogTest() message
response function. In that function, the program first creates the dialog box object and then calls DoModal() to display it, like this:
CCntlDlg dialog(this); int result = dialog.DoModal();
If the user exits the dialog box by clicking the OK button, the function copies the dialog box's data into data members of the window class and then calls Invalidate() in order to repaint the window, which displays the current data from the dialog box. The code that handles these tasks is shown in Listing 8.10.
Listing 8.10 LST08_10.CPP Copying the Dialog Box's Data
if (result == IDOK) { // Save the contents of the dialog box. m_edit1 = dialog.m_edit1; m_radio1 = dialog.m_radio1; m_radio2 = dialog.m_radio2; m_radio3 = dialog.m_radio3; m_combo1 = dialog.m_combo1; m_check1 = dialog.m_check1; m_check2 = dialog.m_check2; m_check3 = dialog.m_check3; m_list1 = dialog.m_list1; // Force the window to repaint. Invalidate(); }
The dialog box object is automatically deleted when it goes out of scope, taking all its data with it, which is why you must copy whatever data you need from the dialog box.