天天看點

Visual C++ 程式設計技巧之五和六

33、如何擷取一個對話控件的指針

34、如何禁止和使能控件

35、如何改變控件的字型

36、如何在OLE控件中使用OLE_COLOR資料類型

37、在不使用通用檔案打開對話的情況下如何顯示一個檔案清單

38、為什麼旋轉按鈕控件看起來倒轉

39 為什麼旋轉按鈕控件不能自動地更新它下面的編輯控件

40、如何用位圖顯示下壓按鈕

41、如何一個建立三态下壓按鈕

42、如何動态建立控件

43、如何限制編輯框中的準許字元

44、如何改變控件的顔色

45、當向清單框中添加多個項時如何防止閃爍

46、如何向編輯控件中添加文本

47、如何通路預定義的GDI對象

48、如何擷取GDI對象的屬性資訊

33、如何擷取一個對話控件的指針  

有兩種方法。其一,調用CWnd: : GetDlgItem,擷取一個CWnd*指針調用成員函數。下例調用GetDlgItem,将傳回值傳給一個CSpinButtonCtrl*以便調用CSpinButtonCtrl : : SetPos 函數:  

BOOL CSampleDialog : : OnInitDialog ( )  

{  

    CDialog : : OnInitDialog ( ) ;  

    //Get pointer to spin button .  

    CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem (IDC_SPIN) ;  

    ASSERT _ VALID (pSpin) ;  

    //Set spin button's default position .  

    pSpin —> SetPos (10) ;  

    return TRUE ; 

}  

其二, 可以使用ClassWizard将控件和成員變量聯系起來。在ClassWizard中簡單地選擇Member Variables标簽,然後選擇Add Variable …按鈕。如果在對話資源編輯器中,按下Ctrl鍵并輕按兩下控件即可轉到Add Member Variable對話。  

34、如何禁止和使能控件  

控件也是視窗,是以可以調用CWnd : : EnableWindow使能和禁止控件。  

//Disable button controls .  

m_wndOK.EnableWindow (FALSE ) ;  

m_wndApply.EnableWindow (FALSE ) ;  

35、如何改變控件的字型  

由于控件是也是視窗,使用者可以調用CWnd: : SetFont指定新字型。該函數用一個Cfont指針,要保證在控件撤消之前不能撤消字型對象。下例将下壓按鈕的字型改為8點Arial字型:  

//Declare font object in class declaration (.H file ).  

private :  

Cfont m_font ;  

// Set font in class implementation (.Cpp file ). Note m_wndButton is a  

//member variable added by ClassWizard.DDX routines hook the member  

//variable to a dialog button contrlo.  

BOOL CSampleDialog : : OnInitDialog ( )  

{  

    …  

    //Create an 8-point Arial font  

    m_font . CreateFont (MulDiv (8 , -pDC—> GetDeviceCaps (LOGPIXELSY) , 72).  

    0 , 0 , 0 , FW_NORMAL , 0 , 0, 0, ANSI_CHARSER, OUT_STROKE_PRECIS ,  

    CLIP_STROKE _PRECIS , DRAFT _QUALITY  

    VARIABLE_PITCH |FF_SWISS, _T ("Arial") );  

    //Set font for push button .  

    m_wndButton . SetFont (&m _font );  

    …  

}  

36、如何在OLE控件中使用OLE_COLOR資料類型  

諸如COleControl : : GetFortColor和COleControl : : GetBackColor等函數傳回OLE _COLOR資料類型的顔色,而GDI對象諸如筆和刷子使用的是COLORREF資料類型,調用COleControl : : TranslateColor可以很容易地将OLE_COLOR類型改為COLORREF類型。下例建立了一個目前背景顔色的刷子:  

void CSampleControl : : OnDraw (CDC* pdc ,const Crect& rcBounds , const Crect& rcInvalid )  

{  

    //Create a brush of the cuttent background color .  

    CBrush brushBack (TranslateColor (GetBackColor ( ) ) );  

    //Paint the background using the current background color .  

    pdc—> FilllRect (rcBounds , &brushBack) ; 

    //other drawign commands  

    …  

}  

37、在不使用通用檔案打開對話的情況下如何顯示一個檔案清單  

調用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox, Windows 将自動地向清單框或組合框填充可用的驅動器名或者指定目錄中的檔案,下例将Windows目錄中的檔案填充在組合框中:  

BOOL CSampleDig : : OnInitDialog ( )  

{  

    CDialog : : OnInitDialog ( )  

    TCHAR szPath [MAX_PATH] = {"c://windows"} ;  

    int nReslt = DlgDirListComboBox (szPath , IDC_COMBO , IDC_CURIDIR,  

    DDL_READWRITE |DDL_READONLY|DDL_HIDDEN| DDL_SYSTEM|DDL_ARCHIVE ) ;  

    return TRUE ;  

}  

38、為什麼旋轉按鈕控件看起來倒轉  

需要調用CSpinCtrl : : SetRange 設定旋轉按鈕控件的範圍,旋轉按鈕控件的預設上限為0,預設下限為100,這意味着增加時旋轉按控件的值由100變為0。下例将旋轉按鈕控件的範圍設定為0到100:  

BOOL CAboutDlg : : OnInitDialog ( )  

{  

    CDialog : : OnInitDialog ( )  

    //set the lower and upper limit of the spin button  

    m_wndSpin . SetRange ( 0 ,100 ) ;  

    return TRUE ;  

}  

Visual C++ 4.0 Print對話中的Copise旋轉按鈕控件也有同樣的問題:按下Up按鈕時拷貝的數目減少,而按下Down 按鈕時拷貝的數目增加。  

39為什麼旋轉按鈕控件不能自動地更新它下面的編輯控件  

如果使用旋轉按鈕的autu buddy特性, 則必須保證在對話的标記順序中buddy視窗優先于旋轉按鈕控件。從Layout菜單中選擇Tab Order菜單項(或者按下Crtl+D)可以設定對話的标簽順序。  

40、如何用位圖顯示下壓按鈕  

Windows 95按鈕有幾處新的建立風格,尤其是BS_BITMAP和BS_ICON,要想具有位圖按鈕,建立按鈕和調用CButton : : SetBitmap或CButton : : SetIcon時要指定BS_BITMAP或BS_ICON風格。  

首先,設定按鈕的圖示屬性。  

然後,當對話初始化時調用CButton: : SetIcon。注意:下例用圖示代替位圖,使用位圖時要小心,因為不知道背景所有的顔色——并非每個人都使用淺灰色。  

BOOL CSampleDlg : : OnInitDialog ( )  

{  

    CDialog : : OnInitDialog ( ) ;  

    //set the images for the push buttons .  

    m_wndButton1.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION1) )  

    m_wndButton2.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION2) )  

    m_wndButton3.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION3) )  

    return TRUE ;  

}  

41、如何一個建立三态下壓按鈕  

可以使用新的BS_PUSHBUTTON 風格位和檢測框以及按鈕來建立一個三态下壓按鈕。這很容易,隻需将檢測框和按鈕拖拉到對話中并指定屬性Push—like即可。不用任何附加程式就可以成為三态下壓按鈕。  

42、如何動态建立控件  

配置設定一個控件對象的執行個體并調用其Create成員函數。開發者最容易忽略兩件事:忘記指定WS_VISBLE标簽和在棧中配置設定控件對象。下例動态地建立一個下壓按鈕控件:  

//In class declaration (.H file ).  

private :  

CButton* m _pButton ;  

//In class implementation (.cpp file ) .  

m_pButton =new CButton ;  

ASSERT_VALID (m_pButton);  

m_pButton —>Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE |BS_PUSHBUTTON,Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )  

43、如何限制編輯框中的準許字元  

如果使用者在編輯控件中隻允許接收數字,可以使用一個标準的編輯控件并指定新的建立标志ES_NUMBERS,它是Windows 95新增加的标志,該标志限制 編輯控件隻按收數字字元。如果使用者需要複雜的編輯控件,可以使用Microsoft 的屏蔽編輯控件,它是一個很有用的OLE定制控件。  

如果希望不使用OLE 定制控件自己處理字元,可以派生一個CEdit 類并處理WM_CHAR消息,然後從編輯控件中過濾出特定的字元。首先,使用ClassWizard 建立一個 CEdit的派生類,其次,在對話類中指定一個成員變量将編輯控件分類在OnInitdialog 中調用CWnd: : SubclassDlgItem .  

//In your dialog class declaration (.H file )  

private :  

CMyEdit m_wndEdit ; // Instance of your new edit control .  

//In you dialog class implementation (.CPP file )  

BOOL CSampleDialog : : OnInitDialog ( )  

{  

    …  

    //Subclass the edit lontrod .  

    m_wndEdit .SubclassDlgItem (IDC_EDIT,this );  

    …  

}  

使用ClassWizard處理WM_CHAR消息,計算nChar參量并決定所執行的操作,使用者可以确定是否修改、傳送字元。下例說明了如何顯示字母字元,如果字元是字母字元,則調用CWnd ; OnChar,否則不調用OnChar.  

//Only display alphabetic dharacters .  

void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags )  

{  

    //Determine if nChar is an alphabetic character .  

    if (: : IsCharAlpha ( ( TCHAR) nChar ) )  

    CEdit : : OnChar (nChar, nRepCnt , nFlags );  

}  

如果要修改字元,則不能僅僅簡單地用修改過的nChar調用CEdit : : OnChar,然後CEdit: : OnChar調用CWnd: : Default擷取原來的wParam 和lParam 的值 ,這樣是不行的。要修改一個字元,需要首先修改nChar,然後用修改過的nChar調用CWnd: : DefWindowProc。下例說明了如何将字元轉變為大寫:  

//Make all characters uppercase  

void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags )  

{  

    //Make sure character is uppercase .  

    if (: : IsCharAlpha ( .( TCHAR) nChar)  

    nChar=: : CharUpper (nChar ) ;  

    //Bypass default OnChar processing and directly call  

    //default window proc.  

    DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ;  

}  

44、如何改變控件的顔色  

有兩種方法。其一,可以在父類中指定控件的顔色,或者利用MFC4.0新的消息反射在控件類中指定顔色。當控件需要重新着色時,工作框調用父視窗(通常是對話框)的CWnd: : OnCrtlColor,可以在父視窗類中重置該函數并指定控件的新的繪畫屬性。例如,下述代碼将對話中的所有編輯控件文本顔色改為紅色:  

HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor)  

{  

    HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor );  

    //Draw red text for all edit controls .  

    if (nCtlColor= = CTLCOLOR_EDIT )  

    pDC —> SetTextColor (RGB (255 , 0 , 0 , ) ) ;  

    return hbr ;  

}  

然而,由于每個父視窗必須處理通知消息并指定每個控件的繪畫屬性,是以,這種方法不是完全的面向對象的方法。控件處理該消息并指定繪畫屬性更合情合理。消息反射允許使用者這樣做。通知消息首先發送給父視窗,如果父視窗沒有處理則發送給控件。建立一個定制彩色清單框控件必須遵循下述步驟。  

首先,使用ClassWizard 建立一個CListBox 的派生類并為該類添加下述資料成員。  

class CMyListBox ; publilc CListBox  

{  

    …  

    private;  

    COLORREF m_clrFor ; // foreground color  

    COLORREF m_clrBack ; //background color  

    Cbrush m_brush ; //background brush  

    …  

} ;  

其次,在類的構造函數中,初始化資料中。  

CMyListBox : : CMyListBox ()  

{  

    //Initialize data members .  

    m_clrFore =RGB (255 , 255 , 0) ; // yellow text  

    m_clrBack=RGB (0 , 0 , 255) ; // blue background  

    m_brush . CreateSolidBrush (m _clrBack );  

}  

最後,使用ClassWizard處理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新的繪畫屬性。  

HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor )  

{  

    pDC—>SetTextColor (m_clrFore);  

    pDC—>SetBkColor (m_clrBack);  

    return (HBRUSH) m_brush.GetSafeHandle ()  

}  

現在,控件可以自己決定如何繪畫,與父視窗無關。  

45、當向清單框中添加多個項時如何防止閃爍  

調用CWnd::SetRedraw 清除重畫标志可以禁止CListBox(或者視窗)重畫。當向清單框添加幾個項時,使用者可以清除重畫标志,然後添加項,最後恢複重畫标志。為確定重畫清單框的新項,調用SetRedraw (TRUE) 之後調用CWnd::Invalidate。  

//Disable redrawing.  

pListBox->SetRedraw (FALSE);  

//Fill in the list box gere  

//Enable drwing and make sure list box is redrawn.  

pListBox->SetRedraw (TRUE);  

pListBox->Invalidate ();  

46、如何向編輯控件中添加文本  

由于沒有CEdit:: AppendText函數,使用者隻好自己做此項工作。調用CEdit:: SetSel移動到編輯控件末尾,然後調用CEdit:: ReplaceSel添加文本。下例是AppendText 的一種實作方法:  

void CMyEdit:: AppendText (LPCSTR pText)  

{  

    int nLen=GetWindowTextLength ();  

    SetFocus ();  

    SetSel (nLen, nLen);  

    ReplaceSel (pText);  

}  

47、如何通路預定義的GDI對象  

可以通過調用CDC:: SlectStockObject使用Windows的幾個預定義的對象,諸如刷子、筆以及字型。下例使用了Windows預定義的筆和刷子GDI對象在視窗中畫一個橢圓。  

//Draw ellipse using stock black pen and gray brush.  

void CSampleView:: OnDraw (CDC* pDC)  

{  

    //Determine size of view.  

    CRect rcView;  

    GetClientRect (rcView);  

    //Use stock black pen and stock gray brush to draw ellipse.  

    pDC->SelectStockObject (BLACK_PEN);  

    pDC->SelectStockObject (GRAY_BRUSH)  

    //Draw the ellipse.  

    pDC->Ellipse (reView);  

}  

也可以調用新的SDK函數GetSysColorBrush擷取一個系統顔色刷子,下例用背景色在視窗中畫一個橢圓:  

void CsampleView:: OnDraw (CDC* pDC)  

{  

    //Determine size of view.  

    CRect rcView;  

    GetClientRect (rcView);  

    //Use background color for tooltips brush.  

    CBrush * pOrgBrush=pDC->SelectObject (  

    CBrush::FromHandle (::GetSysColorBrush (COLOR_INFOBK)));  

    //Draw the ellipse.  

    pDC->Ellipse (rcView);  

    //Restore original brush.  

    pDC->SelectObject (pOrgBrush);  

}  

48、如何擷取GDI對象的屬性資訊  

可以調用GDIObject:: GetObject。這個函數将指定圖表裝置的消息寫入到緩沖區。下例建立了幾個有用的輔助函數。  

//Determine if font is bold.  

BOOL IsFontBold (const CFont&font)  

{  

    LOGFONT stFont;  

    font.GetObject (sizeof (LOGFONT), &stFont);  

    return (stFont.lfBold)? TRUE: FALSE;  

}  

//Return the size of a bitmap.  

CSize GetBitmapSize (const CBitmap&bitmap)  

{  

    BITMAP stBitmap;  

    bitmap.GetObject (sizeof (BITMAP), &stBitmap);  

    return CSize (stBitmap.bmWidth, stBitmap. bmHeight);  

}  

//Create a pen with the same color as a brush.  

BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush)  

{  

    LOGBRUSH stBrush;  

    brush.Getobject (sizeof (LOGBRUSH), &stBrush);  

    return pen. Createpen (PS_SOLID, 0, stBrush.ibColor);  

}