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

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

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

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

George Shepherd, David Kruglinski

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

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

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








The Ex12a Example Revisited


Now we'll add a property sheet to Ex12a that allows the user to change the rich edit control's font characteristics. Of course, we could use the standard MFC CFontDialog function, but then you wouldn't learn how to create property sheets. Figure 12-5 shows the property sheet that you'll build as you continue with Ex12a.

If you haven't built Ex12a, follow the instructions that begin on page 285 to build it. If you already have Ex12a working with the Transfer menu commands, just continue on with these steps:



  1. Use the resource editor to edit the application's main menu. In Resource View, edit the IDR_MAINFRAME menu resource to add a Format menu that looks like this.


    The MFC library has defined the following command IDs for the new Format menu commands.
















    Caption


    Command ID


    &Default


    ID_FORMAT_DEFAULT


    &Selection


    ID_FORMAT_SELECTION


    Add appropriate prompt strings for the two menu commands using the Properties window.



  2. Use Class View's Properties window to add the view class command and update command user interface message handlers. Select the CEx12aView class in Class View, and then add the following member functions.



















    Object ID


    Event


    Member Function


    ID_FORMAT_DEFAULT


    COMMAND


    OnFormatDefault


    ID_FORMAT_SELECTION


    COMMAND


    OnFormatSelection


    ID_FORMAT_SELECTION


    UPDATE_

    COMMAND_UI


    OnUpdateFormatSelection




  3. Use the resource editor to add four property page dialog templates. Right-click on the RC file in Resource View and choose Add Resource from the shortcut menu. In the Add Resource dialog box, select the small property page template. The templates are shown here with their associated IDs:


    Use the IDs listed below for the controls in the dialog boxes. Set the Auto Buddy and the Set Buddy Integer properties for the Spin control, and set the Group property for the IDC_FONT and IDC_COLOR radio buttons. Set the minimum value of IDC_FONTSIZE to 8 and its maximum value to 24.

    Use the MFC Class Wizard to create the classes CPage1, CPage2, CPage3, and CPage4. In each case, select CPropertyPage as the base class. Have the MFC Class Wizard generate the code for all these classes in the files

    Property.h and

    Property.cpp by changing the filenames within the text boxes for the header file and the CPP file. When Visual Studio .NET asks you whether you want to merge the files, click Yes. Then add the data members shown here:































    Dialog Box


    Control


    ID


    Type


    Data Member


    IDD_PAGE1


    First radio button


    IDC_FONT


    int


    m_nFont


    IDD_PAGE2


    Bold check

    box


    IDC_BOLD


    BOOL


    m_bBold


    IDD_PAGE2


    Italic check

    box


    IDC_ITALIC


    BOOL


    m_bItalic


    IDD_PAGE2


    Underline

    check box


    IDC_UNDERLINE


    BOOL


    m_bUnderline


    IDD_PAGE3


    First radio button


    IDC_COLOR


    int


    m_nColor


    IDD_PAGE4


    Edit control


    IDC_FONT

    SIZE


    int


    m_nFontSize


    IDD_PAGE4


    Spin control


    IDC_SPIN1


    Finally, use Class View's Properties window to override the OnInitDialog virtual function for CPage4.



  4. Use the MFC Class Wizard to create a class derived from CPropertySheet. Select the name CFontSheet. Generate the code in the files

    Property.h and

    Property.cpp , the same files you used for the property page classes. The following code shows these files with the added code in boldface:

    Property.h






    #pragma once
    // Property.h : header file
    //
    #define WM_USERAPPLY WM_USER + 5
    extern CView* g_pView;
    ////////////////////////////////////////////////////////////////////
    // CPage1 dialog
    class CPage1 : public CPropertyPage
    {
    DECLARE_DYNCREATE(CPage1)
    public:
    CPage1();
    virtual ~CPage1();
    // Dialog Data
    enum { IDD = IDD_PAGE1 };
    int m_nFont;
    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV
    virtual BOOL OnApply();
    virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
    };
    ////////////////////////////////////////////////////////////////////
    // CPage2 dialog
    class CPage2 : public CPropertyPage
    {
    DECLARE_DYNCREATE(CPage2)
    public:
    CPage2();
    virtual ~CPage2();
    // Dialog Data
    enum { IDD = IDD_PAGE2 };
    BOOL m_bBold;
    BOOL m_bItalic;
    BOOL m_bUnderline;
    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV
    virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
    };
    ////////////////////////////////////////////////////////////////////
    // CPage3 dialog
    class CPage3 : public CPropertyPage
    {
    DECLARE_DYNCREATE(CPage3)
    public:
    CPage3();
    virtual ~CPage3();
    // Dialog Data
    enum { IDD = IDD_PAGE3 };
    int m_nColor;
    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV
    virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
    };
    ////////////////////////////////////////////////////////////////////
    // CPage4 dialog
    class CPage4 : public CPropertyPage
    {
    DECLARE_DYNCREATE(CPage4)
    public:
    CPage4();
    virtual ~CPage4();
    // Dialog Data
    enum { IDD = IDD_PAGE4 };
    int m_nFontSize;
    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV
    // support
    virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
    public:
    virtual BOOL OnInitDialog();
    };
    ////////////////////////////////////////////////////////////////////
    // CFontSheet
    class CFontSheet : public CPropertySheet
    {
    DECLARE_DYNAMIC(CFontSheet)
    public:
    CPage1 m_page1;
    CPage2 m_page2;
    CPage3 m_page3;
    CPage4 m_page4;
    public:
    CFontSheet(UINT nIDCaption, CWnd* pParentWnd = NULL,
    UINT iSelectPage = 0);
    CFontSheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL,
    UINT iSelectPage = 0);
    virtual ~CFontSheet();
    protected:
    DECLARE_MESSAGE_MAP()
    };












    Property.cpp






    // Property.cpp : implementation file
    #include "stdafx.h"
    #include "Ex12a.h"
    #include "Property.h"
    CView* g_pView;
    ////////////////////////////////////////////////////////////////////
    // CPage1 dialog
    IMPLEMENT_DYNCREATE(CPage1, CPropertyPage)
    CPage1::CPage1() : CPropertyPage(CPage1::IDD)
    {
    m_nFont = -1;
    }
    CPage1::~CPage1()
    {
    }
    BOOL CPage1::OnApply()
    {
    TRACE("CPage1::OnApply\n");
    g_pView->SendMessage(WM_USERAPPLY);
    return TRUE;
    }
    BOOL CPage1::OnCommand(WPARAM wParam, LPARAM lParam)
    {
    SetModified(TRUE);
    return CPropertyPage::OnCommand(wParam, lParam);
    }
    void CPage1::DoDataExchange(CDataExchange* pDX)
    {
    TRACE("Entering CPage1::DoDataExchange -- %d\n",
    pDX->m_bSaveAndValidate);
    CPropertyPage::DoDataExchange(pDX);
    DDX_Radio(pDX, IDC_FONT, m_nFont);
    }
    BEGIN_MESSAGE_MAP(CPage1, CPropertyPage)
    END_MESSAGE_MAP()
    ////////////////////////////////////////////////////////////////////
    // CPage1 message handlers
    ////////////////////////////////////////////////////////////////////
    // CPage2 dialog
    IMPLEMENT_DYNCREATE(CPage2, CPropertyPage)
    CPage2::CPage2() : CPropertyPage(CPage2::IDD)
    {
    m_bBold = FALSE;
    m_bItalic = FALSE;
    m_bUnderline = FALSE;
    }
    CPage2::~CPage2()
    {
    }
    BOOL CPage2::OnCommand(WPARAM wParam, LPARAM lParam)
    {
    SetModified(TRUE);
    return CPropertyPage::OnCommand(wParam, lParam);
    }
    void CPage2::DoDataExchange(CDataExchange* pDX)
    {
    TRACE("Entering CPage2::DoDataExchange -- %d\n",
    pDX->m_bSaveAndValidate);
    CPropertyPage::DoDataExchange(pDX);
    DDX_Check(pDX, IDC_BOLD, m_bBold);
    DDX_Check(pDX, IDC_ITALIC, m_bItalic);
    DDX_Check(pDX, IDC_UNDERLINE, m_bUnderline);
    }
    BEGIN_MESSAGE_MAP(CPage2, CPropertyPage)
    END_MESSAGE_MAP()
    ////////////////////////////////////////////////////////////////////
    // CPage2 message handlers
    ////////////////////////////////////////////////////////////////////
    // CPage3 dialog
    IMPLEMENT_DYNCREATE(CPage3, CPropertyPage)
    CPage3::CPage3() : CPropertyPage(CPage3::IDD)
    {
    m_nColor = -1;
    }
    CPage3::~CPage3()
    {
    }
    BOOL CPage3::OnCommand(WPARAM wParam, LPARAM lParam)
    {
    SetModified(TRUE);
    return CPropertyPage::OnCommand(wParam, lParam);
    }
    void CPage3::DoDataExchange(CDataExchange* pDX)
    {
    TRACE("Entering CPage3::DoDataExchange -- %d\n",
    pDX->m_bSaveAndValidate);
    CPropertyPage::DoDataExchange(pDX);
    DDX_Radio(pDX, IDC_COLOR, m_nColor);
    }
    BEGIN_MESSAGE_MAP(CPage3, CPropertyPage)
    END_MESSAGE_MAP()
    ////////////////////////////////////////////////////////////////////
    // CPage3 message handlers
    ////////////////////////////////////////////////////////////////////
    // CPage4 dialog
    IMPLEMENT_DYNCREATE(CPage4, CPropertyPage)
    CPage4::CPage4() : CPropertyPage(CPage4::IDD)
    {
    m_nFontSize = 0;
    }
    CPage4::~CPage4()
    {
    }
    BOOL CPage4::OnCommand(WPARAM wParam, LPARAM lParam)
    {
    SetModified(TRUE);
    return CPropertyPage::OnCommand(wParam, lParam);
    }
    void CPage4::DoDataExchange(CDataExchange* pDX)
    {
    TRACE("Entering CPage4::DoDataExchange -- %d\n",
    pDX->m_bSaveAndValidate);
    CPropertyPage::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_FONTSIZE, m_nFontSize);
    DDV_MinMaxInt(pDX, m_nFontSize, 8, 24);
    }
    BEGIN_MESSAGE_MAP(CPage4, CPropertyPage)
    END_MESSAGE_MAP()
    ////////////////////////////////////////////////////////////////////
    // CPage4 message handlers
    BOOL CPage4::OnInitDialog()
    {
    CPropertyPage::OnInitDialog();
    ((CSpinButtonCtrl*) GetDlgItem(IDC_SPIN1))->SetRange(8, 24);
    return TRUE; // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
    }
    ////////////////////////////////////////////////////////////////////
    // CFontSheet
    IMPLEMENT_DYNAMIC(CFontSheet, CPropertySheet)
    CFontSheet::CFontSheet(UINT nIDCaption, CWnd* pParentWnd,
    UINT iSelectPage)
    :CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
    {
    }
    CFontSheet::CFontSheet(LPCTSTR pszCaption, CWnd* pParentWnd,
    UINT iSelectPage)
    :CPropertySheet(pszCaption, pParentWnd, iSelectPage)
    {
    AddPage(&m_page1);
    AddPage(&m_page2);
    AddPage(&m_page3);
    AddPage(&m_page4);
    }
    CFontSheet::~CFontSheet()
    {
    }
    BEGIN_MESSAGE_MAP(CFontSheet, CPropertySheet)
    END_MESSAGE_MAP()
    ////////////////////////////////////////////////////////////////////
    // CFontSheet message handlers













  5. Insert the following line in the

    Ex12aView.h file:

    #include "Property.h"



  6. Add two data members and two prototypes to the CEx12aView class:

    private:
    CFontSheet m_sh;
    BOOL m_bDefault; // TRUE default format, FALSE selection

    Now add the prototype for the private function Format:

    void Format(CHARFORMAT &cf);

    Insert the prototype for the protected function OnUserApply before the DECLARE_MESSAGE_MAP macro:

    afx_msg LRESULT OnUserApply(WPARAM wParam, LPARAM lParam);



  7. Edit and add code in the file

    Ex12aView.cpp .Map the user-defined WM_USERAPPLY message, as shown here:

    ON_MESSAGE(WM_USERAPPLY, OnUserApply)

    Add the following lines to the OnCreate function, just before the return 0 statement:

    CHARFORMAT cf;
    Format(cf);
    m_rich.SetDefaultCharFormat(cf);

    Edit the view constructor to set default values for the property sheet data members, as follows:

    CEx12aView::CEx12aView() : m_sh(")
    {
    m_sh.m_page1.m_nFont = 0;
    m_sh.m_page2.m_bBold = FALSE;
    m_sh.m_page2.m_bItalic = FALSE;
    m_sh.m_page2.m_bUnderline = FALSE;
    m_sh.m_page3.m_nColor = 0;
    m_sh.m_page4.m_nFontSize = 12;
    g_pView = this;
    m_bDefault = TRUE;
    }

    Edit the format command handlers, as shown here:

    void CEx12aView::OnFormatDefault()
    {
    m_sh.SetTitle("Default Format");
    m_bDefault = TRUE;
    m_sh.DoModal();
    }
    void CEx12aView::OnFormatSelection()
    {
    m_sh.SetTitle("Selection Format");
    m_bDefault = FALSE;
    m_sh.DoModal();
    }
    void CEx12aView::OnUpdateFormatSelection(CCmdUI* pCmdUI)
    {
    long nStart, nEnd;
    m_rich.GetSel(nStart, nEnd);
    pCmdUI->Enable(nStart != nEnd);
    }

    Add the following handler for the user-defined WM_USERAPPLY message:

    LRESULT CEx12aView::OnUserApply(WPARAM wParam, LPARAM lParam)
    {
    TRACE("CEx12aView::OnUserApply -- wParam = %x\n", wParam);
    CHARFORMAT cf;
    Format(cf);
    if (m_bDefault) {
    m_rich.SetDefaultCharFormat(cf);
    }
    else {
    m_rich.SetSelectionCharFormat(cf);
    }
    return 0;
    }

    Add the Format helper function, as shown below, to set a CHARFORMAT structure based on the values of the property sheet data members:

    void CEx12aView::Format(CHARFORMAT& cf)
    {
    cf.cbSize = sizeof(CHARFORMAT);
    cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE |
    CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE;
    cf.dwEffects = (m_sh.m_page2.m_bBold ? CFE_BOLD : 0) |
    (m_sh.m_page2.m_bItalic ? CFE_ITALIC : 0) |
    (m_sh.m_page2.m_bUnderline ? CFE_UNDERLINE : 0);
    cf.yHeight = m_sh.m_page4.m_nFontSize * 20;
    switch(m_sh.m_page3.m_nColor) {
    case -1:
    case 0:
    cf.crTextColor = RGB(0, 0, 0);
    break;
    case 1:
    cf.crTextColor = RGB(255, 0, 0);
    break;
    case 2:
    cf.crTextColor = RGB(0, 255, 0);
    break;
    }
    switch(m_sh.m_page1.m_nFont) {
    case -1:
    case 0:
    strncpy(cf.szFaceName, "Times New Roman" ,LF_FACESIZE);
    break;
    case 1:
    strncpy(cf.szFaceName, "Arial" ,LF_FACESIZE);
    break;
    case 2:
    strncpy(cf.szFaceName, "Courier New" ,LF_FACESIZE);
    break;
    }
    cf.bCharSet = 0;
    cf.bPitchAndFamily = 0;
    }



  8. Build and test the enhanced Ex12a application. Type some text, and then choose Default from the Format menu. Observe the TRACE messages in the Debug window as you click on property sheet tabs and click the Apply button. Try highlighting some text and then formatting the selection.




Apply Button Processing


You might be curious about the way the property sheet classes process the Apply button. In all the page classes, the overridden OnCommand functions enable the Apply button whenever a control sends a message to the page. This works fine for pages 1 through 3 in Ex12a, but for page 4, OnCommand is called during the initial conversation between the Spin control and its buddy.

The OnApply virtual override in the CPage1 class sends a user-defined message to the view. The function finds the view in an expedient way—by using a global variable set by the view class. A better approach would be to pass the view pointer to the sheet constructor and then to the page constructor.

The view class calls the property sheet's DoModal function for both default formatting and selection formatting. It sets the m_bDefault flag to indicate the mode. We don't need to check the return from DoModal because the user-defined message is sent for both the OK button and the Apply button. If the user clicks Cancel, no message is sent.



/ 319