Programming with Microsoft Visual C++.NET 6ed [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming with Microsoft Visual C++.NET 6ed [Electronic resources] - نسخه متنی

George Shepherd, David Kruglinski

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید








The Ex07a Example: The Dialog Box That Ate Cincinnati


We'll dive in headfirst here and build a dialog box that contains almost every kind of control. The job will be easy because Visual Studio's dialog editor will help us. The finished product is shown in Figure 7-1.


Figure 7-1: The finished dialog box in action.

As you can see, the dialog box supports a human resources application. The program is brightened a little by the use of Loyalty and Reliability scroll bar controls. Here is a classic example of direct action and visual representation of data! These are standard Windows controls we're looking at—we'll cover ActiveX controls in Chapter 9.


Building the Dialog Resource


Here are the steps for building the dialog resource:



    Run the MFC Application Wizard to generate a project named Ex07a. Choose New Project from Visual Studio's File menu. In the New Project dialog box, select the MFC Application, type the name Ex07a, and click OK. In the MFC Application Wizard, accept all the defaults but two: On the Application Type page, select Single Document, and on the Advanced Features page, deselect Printing And Print Preview.



    Create a new dialog resource with ID IDD_DIALOG1. Choose Add Resource from Visual Studio's Project menu. In the Add Resource dialog box, click Dialog and then click New. Visual Studio will create a new dialog resource and display it in the dialog editor, as shown here:


    The dialog editor will assign the resource ID IDD_DIALOG1 to the new dialog box. Notice that the dialog editor inserts OK and Cancel buttons for the new dialog box.



    Size the dialog box and set its properties. Enlarge the dialog box so that it is about 6 inches wide and 5 inches tall.

    Right-click on the new dialog box and choose Properties from the shortcut menu. The Properties window will appear (usually on the right side of the screen, depending upon your profile settings):

    The state of the pushpin button in the title bar of the Properties window determines whether the Properties window stays visible. (When the pushpin is "pushed in," the dialog box stays visible and does not slide out of view when not in use.) In the Properties window, change the Caption property for the new dialog box to The Dialog Box That Ate Cincinnati. Change the System Menu property to False to remove the close button from the dialog box title bar.



    Add the dialog box's controls. Use the Toolbox to add each control. (If the Toolbox is not visible, choose Toolbox from the View menu.) Drag controls from the Toolbox to the new dialog box, and then position and size the controls, as shown in Figure 7-1. Here are the Toolbox controls:






    Note

    The dialog editor displays the position and size of each control in the lower right corner of the status bar. The position units are special "dialog units," or DLUs, not device units. A horizontal DLU is the average width of the dialog font divided by 4. A vertical DLU is the average height of the font divided by 8. The dialog font is normally 8-point MS Sans Serif.


    Here's a brief description of the dialog box's controls:



      The static text control for the Name field. A static text control simply paints characters on the screen. No user interaction occurs at run time. You can type the text after you position the bounding rectangle (which sets the Caption property in the Properties window), and you can resize the rectangle as needed. Add a static text control for the Name field and set the Caption property to &Name. Follow the same procedure for the other static text controls in the dialog box. All static text controls have the same ID, but that's okay because the program doesn't need to access any of them.





      Note

      If you include an ampersand (&) in the Caption property for a static text control, at run time an underline will appear below the character that follows when the Alt key is pressed. This enables the user to jump to selected controls by holding down the Alt key and pressing the key corresponding to the underlined character. The related control must immediately follow the static text in the tabbing order. (I'll discuss tabbing order later in the chapter.) Thus, Alt+N jumps to the Name edit control and Alt+K jumps to the Skill combo box. (See Figure 7-1, shown earlier.) Needless to say, designated jump characters should be unique within the dialog box. The Skill control uses Alt+K because the SS Nbr control uses Alt+S.




      The Name edit control. An edit control is the primary means of entering text in a dialog box. Add a Name edit control and in the Properties window change this control's ID from IDC_EDIT1 to IDC_NAME. Leave the defaults for the rest of the properties. Notice that the default sets Auto HScroll to True, which means that the text scrolls horizontally when the box is filled.



      The SS Nbr (social security number) edit control. The SS Nbr control is similar to the Name edit control. Simply change its ID to IDC_SSN. Later, you'll use the Add Member Variable Wizard to make this a numeric field.





      Note

      To align two or more controls, first select the controls by dragging or by clicking on the first control and then Shift+clicking on the other controls you want to align. Next, choose one of the alignment commands (Lefts, Centers, Rights, Tops, Middles, or Bottoms) from the Format menu's Align submenu.

      You can also align controls to a grid. To turn on the grid, click the Toggle Grid button (on the Dialog Editor toolbar) to reveal the grid and to help align controls.




      The Bio (biography) edit control. This is a multi-line edit control. To make an edit control multi-line, set the Multiline property to True. Set Auto HScroll to False and change its ID to IDC_BIO.



      The Category group box. This control serves only to group two radio buttons visually. Set the Caption property to &Category. The default ID is sufficient.



      The Hourly and Salary radio buttons. Position these radio buttons inside the Category group box. For the Hourly radio button, set Caption to Hourly, Group to True, ID to IDC_CAT, and Tabstop to True. For the Salary radio button, set Caption to Salary and Tabstop to True.

      Be sure that both buttons have the Auto property set to True (the default) and that only the Hourly button has the Group property set to True. Setting the Group property to True indicates that the Hourly radio button is the first control in the Category group. When these properties are set correctly, Windows will ensure that only one of the two buttons can be selected at a time. The Category group box has no effect on the buttons' operation.



      The Insurance group box. This control holds three check boxes. Set the Caption property to &Insurance and set the Group property to True.





      Note

      Later, when you set the dialog box's tab order, you can ensure that the Insurance group box follows the last radio button of the Category group. Setting the Group property to True will "terminate" the previous group. If you fail to do this, it isn't a serious problem, but you'll get several warning messages when you run the program through the debugger.




      The Life, Disability, and Medical check boxes. Place these controls inside the Insurance group box. Set the Caption properties to Life, Disability, and Medical and set the IDs to IDC_LIFE, IDC_DIS, and IDC_MED. Unlike radio buttons, check boxes are independent; the user can set any combination.



      The Skill combo box. This is the first of three types of combo boxes. Change the ID to IDC_SKILL, and then set the Type property to Simple. Increase the height of the control to accommodate multiple lines. In the Data property, add the three skills Manager, Programmer, and Writer (separating each line with a semicolon).

      This is a combo box of type Simple. The user can type anything in the top edit control, use the mouse to select an item from the attached list box, or use the Up or Down direction key to select an item from the attached list box.



      The Educ (education) combo box. Change the ID to IDC_EDUC and set the Sort property to False. In the Data property, add the three education levels High School, College, and Graduate (separating each line with a semicolon. In this drop-down combo box, the user can type anything in the edit box, click on the arrow, and then select an item from the drop-down list or use the Up or Down direction key to select an item from the attached list box.





      Note

      To set the size for the drop-down portion of a combo box, click on the box's arrow and drag down from the center of the bottom of the rectangle.




      The Dept (department) list box. Change the ID to IDC_DEPT; otherwise, leave the defaults. In this list box, the user can select only a single item by using the mouse, by using the Up or Down direction key, or by typing the first character of a selection. Note that the list box doesn't have a Data property, so you can't enter the initial choices. You'll see how to programmatically set these choices later in the chapter.



      The Lang (language) combo box. Change the ID to IDC_LANG, and then set the Type property to Drop List. In the Data property, add the languages English, French, and Spanish (separating each line with a semicolon). With this drop-down combo box, the user can select only from the attached list box. To select, the user can click on the arrow and then select an entry from the drop-down list, or the user can type in the first letter of the selection and then refine the selection using the Up or Down direction key.



      The Loyalty and Reliability horizontal scroll bars. Do not confuse scroll bar controls with a window's built-in scroll bars (as seen in scrolling views). A scroll bar control behaves in the same manner as other controls do and can be resized at design time. Position and size the horizontal scroll bar controls as shown earlier in Figure 7-1, and then assign the IDs IDC_LOYAL and IDC_RELY.



      The OK, Cancel, and Special buttons. Add a button control below the existing OK and Cancel buttons. Set the Caption property to S&pecial and then set the ID IDC_SPECIAL. Later, you'll learn about special meanings that are associated with the default IDs IDOK and IDCANCEL.



      Any icon. (The MFC icon is shown as an example.) You can use the Picture control to display any icon or bitmap in a dialog box, as long as the icon or bitmap is defined in the resource script. We'll use the program's MFC icon, identified as IDR_MAINFRAME. Set the Type option to Icon, and set the Image property to IDR_MAINFRAME. Leave the ID as IDC_STATIC.





    Check the dialog box's tabbing order. Choose Tab Order from the Format menu. Use the mouse to set the tabbing order shown below. Click on each control in the order shown, and then press Enter.







    Tip

    If you mess up the tab sequence partway through, you can recover with a Ctrl+left mouse click on the last correctly sequenced control. Subsequent mouse clicks will start with the next sequence number.




    Save the resource file on disk. For safety, choose Save from the File menu or click the Save button on the toolbar to save

    Ex07a.rc . Keep the newly built dialog box open in the dialog editor.





Creating the Dialog Class


You've now built a dialog resource, but you can't use it without a corresponding dialog class. (The section titled "Understanding the Ex07a Application" later in this chapter explains the relationship between the dialog box and the underlying classes.) Class View works in conjunction with the dialog editor to create that class. Here are the steps to create a dialog class:



    Start the MFC Class Wizard. In Class View, select the Ex07a project, as shown here.


    On the Project menu, choose Add Class (or right-click on the project name in Class View and choose Add, Add Class). In the Add Class dialog box, select the MFC Class template. Click Open in the Add Class dialog box. The MFC Class Wizard will appear.



    Add the CEx07aDialog class. Create a CDialog-based class by filling in the fields of the MFC Class Wizard, as shown below. Be sure the Dialog ID drop-down list is set to IDD_DIALOG1 so the dialog resource you created earlier is used.


    When you click Finish, the CEx07aDialog class will be added to Class View and its CPP file will be opened in the editor.



    Add the CEx07aDialog member variables.After the CEx07aDialog class is added, you can add member variables using the Add Member Variable Wizard (shown below). To start the wizard, right-click on the CEx07aDialog class in Class View and choose Add, Add Variable.

    You must associate data members with each of the dialog box's controls. To do this, select the Control Variable check box, select a control from the Control ID drop-down list, and select Value from the Category drop-down list. Type a name in the Variable Name box and enter any other parameters. Here you can see the settings for adding the CString member variable named m_strBio for the Bio edit control:


    When you're finished, click Finish and repeat this process for each of the controls listed in the table on the following page.

    As you select controls in the Add Member Variables Wizard, you can set such things as the length of the string to enter or the range of numbers to enter. If you select a CString variable, you can set its maximum number of characters; if you select a numeric variable, you can set its minimum and maximum values. Set the minimum value for IDC_SSN to 0 and the maximum value to 999999999.

    Most relationships between control types and variable types are obvious. The way in which radio buttons correspond to variables is not so intuitive, however. You should associate an integer variable with each radio button group, with the first radio button corresponding to value 0, the second to 1, and so forth.

















































    Control ID


    Data Member


    Type


    Parameters


    IDC_BIO


    m_strBio


    CString


    Max chars = 1000


    IDC_CAT


    m_bCat


    int


    IDC_DEPT


    m_strDept


    CString


    IDC_DIS


    m_bInsDis


    BOOL


    IDC_EDUC


    m_strEduc


    CString


    IDC_LANG


    m_strLang


    CString


    IDC_LIFE


    m_bInsLife


    BOOL


    IDC_LOYAL


    m_nLoyal


    int


    IDC_MED


    m_bInsMed


    BOOL


    IDC_NAME


    m_strName


    CString


    IDC_RELY


    m_nRely


    int


    IDC_SKILL


    m_strSkill


    CString


    IDC_SSN


    m_nSsn


    int


    Min value = 0

    Max value = 999999999




    Add the message-handling function for the Special button. CEx07aDialog doesn't need many message-handling functions because the CDialog base class, with the help of Windows, does most of the dialog management. When you specify the ID IDOK for the OK button, for example, the virtual CDialog function OnOK gets called when the user clicks the button. For other buttons, however, you need message handlers.

    With the CEx07aDialog class selected in Class View, click the Events button at the top of the Properties window to add event handlers. The Properties window should contain an entry for IDC_SPECIAL. Expand the IDC_SPECIAL tree and click the BN_CLICKED message. Click the down arrow for the BN_CLICKED message, as shown here:

    Visual Studio invents a message handler named OnBnClickedSpecial. Click <Add> OnBnClickedSpecial to add the message handler. Visual Studio opens the file

    Ex07aDialog.cpp and moves to the OnBnClickedSpecial function. Insert a TRACE statement in the OnBnclickedSpecial function by typing in the following boldface code, which replaces the existing code:

    void CEx07aDialog:: OnBnClickedSpecial ()
    {
    TRACE("CEx07aDialog::OnBnClickedSpecial\n");
    }



    Add an OnInitDialog message-handling function. As you'll see in a moment, Visual Studio generates code that initializes a dialog box's controls. This DDX (Dialog Data Exchange) code won't initialize the list-box choices, however, so you must override the CDialog::OnInitDialog function. Although OnInitDialog is a virtual member function, Visual Studio generates the prototype and skeleton if you map the WM_INITDIALOG message in the derived dialog class. With the CEx07aDialog class selected in Class View, click the Overrides button at the top of the Properties window. In the list of overrides, select the OnInitDialog function and click the down arrow to select the method.

    Click <Add> OnInitDialog. Visual Studio will place the OnInitDialog function in

    Ex07aDialog.cpp and open the source code file so you can edit the function. Type in the boldface code shown here to replace the existing code:

    BOOL CEx07aDialog::OnInitDialog()
    {
    // Be careful to call CDialog::OnInitDialog
    // only once in this function
    CListBox* pLB = (CListBox*) GetDlgItem(IDC_DEPT);
    pLB->InsertString(-1, "Documentation");
    pLB->InsertString(-1, "Accounting");
    pLB->InsertString(-1, "Human Relations");
    pLB->InsertString(-1, "Security");
    // Call after initialization
    return CDialog::OnInitDialog();
    }

    This code initializes the Dept list box with four values. You can also use the same initialization technique for the combo boxes in place of setting the Data property in the resource.





Connecting the Dialog Box to the View


Now we've got the resource and the code for a dialog box, but it's not connected to the view. In most applications, you would probably use a menu command to display a dialog box, but we haven't studied menus yet. Here we'll use the familiar mouse-click message WM_LBUTTONDOWN to display the dialog box. The steps are as follows:



    Add the OnLButtonDown member function.You've done this in the examples in earlier chapters. Simply select the CEx07aView class in Class View, and at the top of the Properties window, click the Messages button to display the list of messages for CEx07aView. Select the WM_LBUTTONDOWN entry, click the down arrow, and select <Add> OnLButtonDown to add the OnLButtonDown member function to

    Ex07aView.cpp .



    Write the code for OnLButtonDown in file

    Ex07aView.cpp . Add the boldface code shown below. Most of the code consists of TRACE statements to print the dialog data members after the user exits the dialog box, but the CEx07aDialog constructor call and the DoModal call are the critical statements.

    void CEx07aView::OnLButtonDown(UINT nFlags, CPoint point)
    {
    CEx07aDialog dlg;
    dlg.m_strName = "Shakespeare, Will";
    dlg.m_nSsn = 307806636;
    dlg.m_nCat = 1; // 0 = hourly, 1 = salary
    dlg.m_strBio = "This person is not a well-motivated tech writer";
    dlg.m_bInsLife = TRUE;
    dlg.m_bInsDis = FALSE;
    dlg.m_bInsMed = TRUE;
    dlg.m_strDept = "Documentation";
    dlg.m_strSkill = "Writer";
    dlg.m_nLang = 0;
    dlg.m_strEduc = "College";
    dlg.m_nLoyal = dlg.m_nRely = 50;
    int ret = dlg.DoModal();
    TRACE("DoModal return = %d\n", ret);
    TRACE("name = %s, ssn = %d, hourly = %d salary = %d\n",
    dlg.m_strName, dlg.m_nSsn, dlg.m_nCat);
    TRACE("dept = %s, skill = %s, lang = %d, educ = %s\n",
    dlg.m_strDept, dlg.m_strSkill, dlg.m_nLang, dlg.m_strEduc);
    TRACE("life = %d, dis = %d, med = %d, bio = %s\n",
    dlg.m_bInsLife, dlg.m_bInsDis, dlg.m_bInsMed, dlg.m_strBio);
    TRACE("loyalty = %d, reliability = %d\n",
    dlg.m_nLoyal, dlg.m_nRely);
    }



    Add code to the virtual OnDraw function in the file

    Ex07aView.cpp . To prompt the user to press the left mouse button, code the CEx07aView::OnDraw function. (The skeleton was generated by MFC Application Wizard.) The boldface code shown here (which you type in) replaces the existing code:

    void CEx07aView::OnDraw(CDC* pDC)
    {
    CEx07aDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    pDC->TextOut(0, 0, "Press the left mouse button here.");
    }



    Add the dialog class include statement to

    Ex07aView.cpp .The OnLButtonDown function shown above depends on the declaration of class CEx07aDialog. You must insert the include statement

    #include "Ex07aDialog.h"

    at the top of the CEx07aView class source code file (

    Ex07aView.cpp ), after the following statement:

    #include "Ex07aView.h"



    Build and test the application.If you've done everything correctly, you should be able to build and run the Ex07a application through Visual C++. Try entering data in each control, and then click OK and observe the TRACE results in the Output window. Notice that the scroll bar controls don't do much yet; we'll attend to them later. Notice what happens when you press Enter while typing in text data in a control: The dialog box closes immediately. Here's an example of the TRACE results in the Output window:






Understanding the Ex07a Application


When your program calls DoModal, control is returned to your program only when the user closes the dialog box. If you understand that, you understand modal dialog boxes. When you start creating modeless dialog boxes, you'll begin to appreciate the programming simplicity of modal dialog boxes. A lot happens "out of sight" as a result of that DoModal call, however. Here's a "what calls what" summary:


CDialog::DoModal

CEx07aDialog::OnInitDialog

…additional initialization…

CDialog::OnInitDialog

CWnd::UpdateData(FALSE)

CEx07aDialog::DoDataExchange

user enters data…

user clicks the OK button

CEx07aDialog::OnOK

…additional validation…

CDialog::OnOK

CWnd::UpdateData(TRUE)

CEx07aDialog::DoDataExchange

CDialog::EndDialog(IDOK)


OnInitDialog and DoDataExchange are virtual functions overridden in the CEx07aDialog class. Windows calls OnInitDialog as part of the dialog box initialization process, and that results in a call to DoDataExchange, a CWnd virtual function that was overridden by Visual Studio. Here is a listing of that function:

void CEx07aDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_BIO, m_strBio);
DDV_MaxChars(pDX, m_strBio, 1000);
DDX_Radio(pDX, IDC_CAT, m_nCat);
DDX_LBString(pDX, IDC_DEPT, m_strDept);
DDX_Check(pDX, IDC_DIS, m_bInsDis);
DDX_CBString(pDX, IDC_EDUC, m_strEduc);
DDX_CBIndex(pDX, IDC_LANG, m_nLang);
DDX_Check(pDX, IDC_LIFE, m_bInsLife);
DDX_Scroll(pDX, IDC_LOYAL, m_nLoyal);
DDX_Check(pDX, IDC_MED, m_bInsMed);
DDX_Text(pDX, IDC_NAME, m_strName);
DDX_Scroll(pDX, IDC_RELY, m_nRely);
DDX_CBString(pDX, IDC_SKILL, m_strSkill);
DDX_Text(pDX, IDC_SSN, m_nSsn);
DDV_MinMaxInt(pDX, m_nSsn, 0, 999999999);
}

The DoDataExchange function and the DDX_ (exchange) and DDV_ (validation) functions are "bidirectional." If UpdateData is called with a FALSE parameter, the functions transfer data from the data members to the dialog box controls. If the parameter is TRUE, the functions transfer data from the dialog box controls to the data members. DDX_Text is overloaded to accommodate a variety of data types.

The EndDialog function is critical to the dialog box exit procedure. DoModal returns the parameter passed to EndDialog. IDOK accepts the dialog box's data, and IDCANCEL cancels the dialog box.





Tip

You can write your own "custom" DDX function and wire it into Visual C++. This feature is useful if you're using a unique data type throughout your application. For details, see the "TN026: DDX and DDV Routines" topic in the Visual Studio documentation.




/ 319