1. 程式人生 > >MFC控制元件使用大全

MFC控制元件使用大全

Static Text

1. 透明背景、改變文字的字型顏色

最好做法當然是繼承CStatic然後過載OnPaint(),完全自己來畫,這樣能夠獲得最大的靈活性,但是比較麻煩。

可以使用以下方便的方法:

同樣建立一個CStatic的派生類,處理父視窗的反射訊息WM_CTLCOLOR,即新增HBRUSH CtlColor(CDC *pDC, UINT nCtlColor)這個訊息對映函式注意,不是HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINTnCtlColor)

其實還有一個方法,就是處理父視窗的OnCtlColor(),更簡單一點,但是不符合封裝的原則。

HBRUSH CStatic_bg_color_sizeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

{

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

       // TODO:  在此更改 DC 的任何特性

       if (nCtlColor == CTLCOLOR_STATIC)

       {

              pDC->SetBkMode(TRANSPARENT);   // 設定透明背景

              pDC->SetTextColor(RGB(0, 0, 255));   // 設定文字顏色

              return  (HBRUSH)GetStockObject(HOLLOW_BRUSH);  // 返回透明畫刷

       }     

       return hbr;

}

-------------------------------------------------------------------------------------------------

通過上述程式碼,就可以得到彩色的文字以及透明的背景,但是,還存在一個問題,當該

Static控制元件的文字內容或者屬性,在執行過程中發生變化的時候,由於背景一直沒有擦除(為了實現透明),會出現重影,導致文字模糊成一團。

解決方法是,讓父視窗進行重繪更新,對,不要看錯了,是控制元件所屬的父視窗,而不是控制元件本身,讓控制元件本身重繪也不會解決問題的,這裡還會引出一個問題,如果重繪整個父視窗,由於GDI並不內嵌雙緩衝,勢必造成嚴重的閃爍問題,解決辦法當然是只讓父視窗重繪控制元件所佔的部分,其他部分不進行重繪,程式碼如下:

C++程式碼

  1. void  CSample::SetText( const   TCHAR  *pszText)   
  2. {   
  3.      this ->SetWindowText(pszText);   
  4.     RECT stRect;   
  5.      // 獲取控制元件位置   
  6.      this ->GetWindowRect(&stRect);   
  7.      // 重要!呼叫父視窗的S2C函式進行座標轉換   
  8.      this ->GetParent()->ScreenToClient(&stRect);   
  9.      // 重繪控制元件所在區域,在這裡擦除背景   
  10.      this ->GetParent()->InvalidateRect(&stRect,  true );   
  11. }  

這樣就能夠實現動態改變文字屬性而不出現重影現象,注意這裡呼叫了父視窗的ScreenToClient()函式來進行座標的轉換,呼叫控制元件本身的S2C函式的話,得到的座標無法用來進行下一步的重繪工作。

現在還有一個比較隱蔽的問題,就是文字字串的長度,如果新的字串的長度比原來的長,而之前拖放Static控制元件長度又不足的時候,就會造成超出的部分無法顯示,當然你大可以在拖放的時候就儘量弄得長一點,但是如果能隨著文字內容而自動調整控制元件長度,那不是會好得多麼。

為了實現這樣的效果,上面的程式碼要修改如下:

C++程式碼

  1. void  CSample::SetText( const   TCHAR  *pszText)       
  2. {       
  3.     CDC *pDC =  this ->GetDC();       
  4.      // 獲取文字在當前繪圖環境下所佔的寬度和高度       
  5.     CSize clSize = pDC->GetTextExtent(pszText, _tcslen(pszText));       
  6.     RECT stRect;       
  7.      // 獲取控制元件當前矩形區域       
  8.      this ->GetWindowRect(&stRect);       
  9.      // 調整寬度為新文字所佔寬度       
  10.     stRect.right = stRect.left + clSize.cx;       
  11.      // 重要!呼叫父視窗S2C函式轉換座標       
  12.      this ->GetParent()->ScreenToClient(&stRect);       
  13.      // 調整控制元件大小以適應新文字       
  14.      this ->MoveWindow(&stRect);       
  15.      // 重繪控制元件以避免重影       
  16.      this ->GetWindowRect(&stRect);       
  17.      this ->GetParent()->ScreenToClient(&stRect);       
  18.      this ->GetParent()->InvalidateRect(&stRect,  true );       
  19. }   

同樣,這裡也是呼叫父視窗的S2C函式,這樣得到的座標才能正確使用。程式碼經過上述修改,就實現了控制元件隨文字動態調整寬度的效果。

以上只是實現Static背景透明、更改文字顏色以及動態調整控制元件大小的簡單演示,實際的應用中可能還需要考慮很多情況,適當修改程式碼,但基本原理是不變的。當然要獲得最大的靈活性,還是得自己來繪製了

2. 靜態控制元件的風格 

 控制元件風格 

 含義 

 SS_BLACKFRAME 

 指定一個具有與視窗邊界同色的框(預設為黑色)。 

 SS_BLACKRECT 

 指定一個具有與視窗邊界同色的實矩形(預設為黑色)。 

 SS_CENTER 

 使顯示的正文居中對齊,正文可以迴繞。 

 SS_GRAYFRAME 

 指定一個具有與螢幕背景同色的邊框。 

 SS_GRAYRECT 

 指定一個具有與螢幕背景同色的實矩形。 

 SS_ICON 

 使控制元件顯示一個在資源中定義的圖示,圖示的名字有Create函式的lpszText引數指定。 

 SS_LEFT 

 左對齊正文,正文能迴繞。 

 SS_LEFTNOWORDWRAP 

 左對齊正文,正文不能迴繞。 

 SS_NOPREFIX 

 使靜態正文串中的&不是一個熱鍵提示符。 

 SS_NOTIFY 

 使控制元件能向父視窗傳送滑鼠事件訊息。 

 SS_RIGHT 

 右對齊正文,可以迴繞。 

 SS_SIMPLE 

 使靜態正文在執行時不能被改變並使正文顯示在單行中。 

 SS_USERITEM 

 指定一個使用者定義項。 

 SS_WHITEFRAME 

 指定一個具有與視窗背景同色的框(預設為白色)。 

 SS_WHITERECT 

 指定一個具有與視窗背景同色的實心矩形(預設為白色)。 

除了上表中的風格外,一般還要為控制元件指定WS_CHILD和WS_VISIBLE視窗風格。一個典型的靜態正文控制元件的風格為WS_CHILD|WS_VISIBLE|SS_LEFT。

3. CStatic類的主要成員函式 

 函式宣告 

 用途 

 HBITMAP SetBitmap( HBITMAP hBitmap ); 

 指定要顯示的點陣圖。 

 HBITMAP GetBitmap( ) const; 

 獲取由SetBitmap指定的點陣圖。 

 HICON SetIcon( HICON hIcon ); 

 指定要顯示的圖示。 

 HICON GetIcon( ) const; 

 獲取由SetIcon指定的圖示。 

 HCURSOR SetCursor( HCURSOR hCursor ); 

 指定要顯示的游標圖片。 

 HCURSOR GetCursor( ); 

 獲取由SetCursor指定的游標。 

 HENHMETAFILE SetEnhMetaFile( HENHMETAFILE hMetaFile ); 

 指定要顯示的增強圖元檔案。 

 HENHMETAFILE GetEnhMetaFile( ) const; 

 獲取由SetEnhMetaFile指定的圖元檔案。 

Edit

1. 訊息類別

 訊息 

 含義 

 EN_CHANGE 

 編輯框的內容被使用者改變了。與EN_UPDATE不同,該訊息是在編輯框顯示的正文被重新整理後才發出的。 

 EN_ERRSPACE 

 編輯框控制元件無法申請足夠的動態記憶體來滿足需要。 

 EN_HSCROLL 

 使用者在水平滾動條上單擊滑鼠。 

 EN_KILLFOCUS 

 編輯框失去輸入焦點。 

 EN_MAXTEXT 

 輸入的字元超過了規定的最大字元數。在沒有ES_AUTOHSCROLL或ES_AUTOVSCROLL的編輯框中,當正文超出了編輯框的邊框時也會發出該訊息。 

 EN_SETFOCUS 

 編輯框獲得輸入焦點。 

 EN_UPDATE 

 在編輯框準備顯示改變了的正文時傳送該訊息。 

 EN_VSCROLL 

 使用者在垂直滾動條上單擊滑鼠。

2. 編輯框控制元件的風格

 控制元件風格 

 含義 

 ES_AUTOVSCROLL 

 當用戶在最後一個可見行按回車鍵時,正文向上滾動一頁。 

 ES_CENTER 

 在多行編輯框中使正文居中。 

 ES_LEFT 

 左對齊正文。 

 ES_LOWERCASE 

 把使用者輸入的字母統統轉換成小寫字母。 

 ES_MULTILINE 

 指定一個多行編輯器。若多行編輯器不指定ES_AUTOHSCROLL風格,則會自動換行,若不指定ES_AUTOVSCROLL,則多行編輯器會在視窗中正文裝滿時發出警告聲響。 

 ES_NOHIDESEL 

 預設時,當編輯框失去輸入焦點後會隱藏所選的正文,當獲得輸入焦點時又顯示出來。設定該風格可禁止這種預設行為。 

 ES_OEMCONVERT 

 使編輯框中的正文可以在ANSI字符集和OEM字符集之間相互轉換。這在編輯框中包含檔名時是很有用的。 

 ES_PASSWORD 

 使所有鍵入的字元都用“*”來顯示。 

 ES_RIGHT 

 右對齊正文。 

 ES_UPPERCASE 

 把使用者輸入的字母統統轉換成大寫字母。 

 ES_READONLY 

 將編輯框設定成只讀的。 

 ES_WANTRETURN 

 使多行編輯器接收回車鍵輸入並換行。如果不指定該風格,按回車鍵會選擇預設的命令按鈕,這往往會導致對話方塊的關閉。 

除了上表中的風格外,一般還要為控制元件指定WS_CHILD、WS_VISIBLE、WS_TABSTOP和WS_BORDER視窗風格,WS_BORDER使控制元件帶邊框。建立一個普通的單行編輯框應指定風格為WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,這將建立一個帶邊框、左對齊正文、可水平滾動的單行編輯器。要建立一個普通多行編輯框,還要附加ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL|WS_HSCROLL| WS_VSCROLL風格,這將建立一個可水平和垂直滾動的,帶有水平和垂直滾動條的多行編輯器。 

3. 與剪下板有關的CEdit成員函式

 函式宣告 

 用途 

 void Clear( ) 

 清除編輯框中被選擇的正文。 

 void Copy( ) 

 把在編輯框中選擇的正文拷貝到剪貼簿中。 

 void Cut( ) 

 清除編輯框中被選擇的正文並把這些正文拷貝到剪貼簿中。 

 void Paste( ) 

 將剪貼簿中的正文插入到編輯框的當前插入符處。 

 BOOL Undo( ) 

 撤消上一次鍵入。對於單行編輯框,該函式總返回TRUE,對於多行編輯框,返回TRUE表明操作成功,否則返回FALSE。 

       m_edit.Clear(); 

       m_edit.Copy();

       m_edit.Paste();

       m_edit.Undo();

       m_edit.Cut();

Rich Edit 2.0 Control

1. 常用操作

1. 設定edit只讀屬性

方法一:
               m_edit1.SetReadOnly(TRUE);
   
方法二:
               ::SendMessage(m_edit1.m_hWnd, EM_SETREADONLY, TRUE, 0);

2. 判斷edit中游標狀態並得到選中內容(richedit同樣適用)

       int nStart, nEnd;
        CString strTemp;

        m_edit1.GetSel(nStart, nEnd);
        if(nStart == nEnd)
        {
           strTemp.Format(_T("
游標在%d"),nStart);
           AfxMessageBox(strTemp);
        }
        else
        {
            //
得到edit選中的內容     
           m_edit1.GetWindowText(strTemp);
            strTemp =strTemp.Mid(nStart) - strTemp.Mid(nEnd);
           AfxMessageBox(strTemp); 
        }
   
注:GetSel後,如果nStartnEnd,表明游標處於某個位置(直觀來看就是游標在閃動);如果nStartnEnd不相等,表明使用者在edit中選中了一段內容。

3. 在edit最後新增字串

       CString str;
        m_edit1.SetSel(-1, -1);
        m_edit1.ReplaceSel(str);

CEdit::SetSel

voidSetSel(DWORD dwSelection, BOOL bNoScroll = FALSE);

void SetSel(intnStartChar, int nEndChar, BOOL bNoScroll = False);

引數: dwSelection 低位字指定起始位置,高位字為結束位置。如果低位為0,高位為-1,則編輯控制元件中的全部文字被選中;如果低位字為-1,則任何當前選定內容被去掉選定狀態。

bNoScroll 指示是否顯示脫字元是滾動可見的。如果值為FALSE,則顯示,TRUE不顯示。

nStartChar 指出當前選中部分的開始位置。如果nStartChar=0nEndChar=-1,則編輯控制元件的文字被全選;如果nStartChar=-1,則任何當前選定內容被去掉選定狀態。

nEndChar 指出結束位置。

4. 隨輸入自動滾動到最後一行(richedit同樣適用)

方法一:(摘自msdn
        // The pointer to my edit.
        extern CEdit* pmyEdit;
        int nFirstVisible = pmyEdit->
GetFirstVisibleLine();

        // Scroll the edit control so thatthe first visible line
        // is the first line of text.
        if (nFirstVisible > 0)
        {
            pmyEdit->
LineScroll(-nFirstVisible,0);
        }
   
方法二:
        m_richedit.PostMessage(WM_VSCROLL,SB_BOTTOM, 0);

5. 如何限制edit輸入指定字元

可以從CEdit派生一個類,新增WM_CHAR訊息對映。下面一個例子實現了限定輸入16進位制字元的功能。

   void CMyHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINTnFlags) 
   { 
        if ( (nChar >= '0' &&nChar <= '9') || 
             (nChar>= 'a' && nChar <= 'f') || 
         (nChar >= 'A' && nChar<= 'F') || 
              nChar== VK_BACK || 
             nChar == VK_DELETE)    //msdn
virtual key
       { 
           CEdit::OnChar(nChar, nRepCnt, nFlags); 
        }    
   }

我自己建立LimitedTextEdit。新增以上訊息處理函式即可。

使用:

       LimitedTextEdit m_edit;    //第一步

       DDX_Control(pDX, IDC_EDIT1, m_edit);  //第二步

6. 如何使用richedit2.0 or richedit3.0

使用原因:由於RichEdit2.0A自動為寬字元(WideChar),所以它可以解決中文亂碼以及一些漢字問題方法一:(msdn上的做法,適用於用VC.NET及以後版本建立的工程)

BOOL CMFCApplication1App::InitInstance()

{

       .....................

       CWinApp::InitInstance();

       AfxInitRichEdit2();

       AfxEnableControlContainer();

       // 建立shell 管理器,以防對話方塊包含

       // 任何shell 樹檢視控制元件或 shell 列表檢視控制元件。

       .....................

       return FALSE;

}

方法二:以對話方塊為例:
       (1)   
增加一全域性變數 HMODULE hMod;
       (2)   
CxxxApp::InitInstance()中新增一句hMod = LoadLibrary(_T("riched20.dll"));
           
CxxxApp::ExitInstance()中新增一句FreeLibrary(hMod);
       (3)   
在對話方塊上放一個richedit,文字方式開啟.rc檔案修改該richedit控制元件的類名"RICHEDIT"to "RichEdit20a".
       (4)   
在對話方塊標頭檔案新增 CRichEditCtrl m_richedit;
           
OnInitDialog中新增m_richedit.SubclassDlgItem(IDC_RICHEDIT1, this);

7. 改變richedit指定區域的顏色及字型

       CHARFORMAT cf;
        ZeroMemory(&cf, sizeof(CHARFORMAT));
        cf.cbSize = sizeof(CHARFORMAT);
        cf.dwMask = CFM_BOLD | CFM_COLOR |CFM_FACE |
                           CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE;
        cf.dwEffects = 0;
        cf.yHeight = 12*12;//
文字高度
        cf.crTextColor = RGB(200, 100, 255);//
文字顏色
        strcpy(cf.szFaceName ,_T("
隸書"));//設定字型
     
        m_richedit1.SetSel(1, 5); //
設定處理區域
        m_richedit1.
SetSelectionCharFormat(cf);

8. 設定行間距(只適用於richedit2.0)

PARAFORMAT2 pf;
        pf2.cbSize = sizeof(PARAFORMAT2);
        pf2.dwMask = PFM_LINESPACING |PFM_SPACEAFTER;
        pf2.dyLineSpacing = 200;
        pf2.bLineSpacingRule = 4;
        m_richedit.SetParaFormat(pf2);

2. 在RichEdit中插入Bitmap

COleDataSourcesrc;

STGMEDIUMsm;

sm.tymed=TYMED_GDI;

sm.hBitmap=hbmp;

sm.pUnkForRelease=NULL;

src.CacheData(CF_BITMAP,&sm);

LPDATAOBJECTlpDataObject =

(LPDATAOBJECT)src.GetInterface(&IID_IDataObject);

pRichEditOle->ImportDataObject(lpDataObject,0, NULL);

lpDataObject->Release();

字型設定程式碼

最後新增字型變換函式:

CHARFORMATcf;

LOGFONTlf;

memset(&cf,0, sizeof(CHARFORMAT));

memset(&lf,0, sizeof(LOGFONT));

//判斷是否選擇了內容

BOOLbSelect = (GetSelectionType() != SEL_EMPTY) ? TRUE : FALSE;

if(bSelect)

{

             GetSelectionCharFormat(cf);

}

else

{

             GetDefaultCharFormat(cf);

}

//得到相關字型屬性

BOOLbIsBold = cf.dwEffects & CFE_BOLD;

BOOLbIsItalic = cf.dwEffects & CFE_ITALIC;

BOOLbIsUnderline = cf.dwEffects & CFE_UNDERLINE;

BOOLbIsStrickout = cf.dwEffects & CFE_STRIKEOUT;

//設定屬性

lf.lfCharSet= cf.bCharSet;

lf.lfHeight= cf.yHeight/15;

lf.lfPitchAndFamily= cf.bPitchAndFamily;

lf.lfItalic= bIsItalic;

lf.lfWeight= (bIsBold ? FW_BOLD : FW_NORMAL);

lf.lfUnderline= bIsUnderline;

lf.lfStrikeOut= bIsStrickout;

sprintf(lf.lfFaceName,cf.szFaceName);

CFontDialogdlg(&lf);

dlg.m_cf.rgbColors= cf.crTextColor;

if (dlg.DoModal()== IDOK)

{

             dlg.GetCharFormat(cf);//獲得所選字型的屬性

             if (bSelect)

                        SetSelectionCharFormat(cf);     //為選定的內容設定所選字型

             else

                        SetWordCharFormat(cf);         //為將要輸入的內容設定字型

}

3. 在RichEdit中實現超連結

首先在Form上放置一個RichEdit。

在窗體的建構函式中新增以下程式碼:

__fastcallTMainForm::TMainForm(TComponent* Owner)

         : TForm(Owner)

{

     unsigned mask =SendMessage(RichEdit1->Handle, EM_GETEVENTMASK, 0, 0);

     SendMessage(RichEdit1->Handle,EM_SETEVENTMASK, 0, mask | ENM_LINK);

     SendMessage(RichEdit1->Handle,EM_AUTOURLDETECT, true, 0);   //自動檢測URL

     RichEdit1->Text = "歡迎訪問C++ Builder\n"

                       "偶的信箱:\n"

                       "嘿嘿\n";

}

過載窗體的WndProc

1。在.h中新增:

    protected:

       virtual void __fastcall WndProc(Messages::TMessage&Message);

2。在.cpp中新增:

//---------------------------------------------------------------------------

void__fastcall TMainForm::WndProc(Messages::TMessage &Message)

{

     if (Message.Msg == WM_NOTIFY)

     {

         if (((LPNMHDR)Message.LParam)->code== EN_LINK)

         {

             ENLINK* p = (ENLINK*)Message.LParam;

             if (p->msg == WM_LBUTTONDOWN)

             {

                SendMessage(RichEdit1->Handle, EM_EXSETSEL, 0,(LPARAM)&(p->chrg));

                 ShellExecute(Handle,"open", RichEdit1->SelText.c_str(), 0, 0, SW_SHOWNORMAL);

             }

         }

     }

     TForm::WndProc(Message);

}

Button

1. 直接呼叫SetBitmap顯示圖片按鈕

首先確定你要顯示在按鈕控制元件的圖片型別是什麼,這裡我是ico圖示,由於要在按鈕裡顯示ico圖示,所以要把按鈕控制元件的屬性改一下,方法是右擊按鈕控制元件,選擇屬性,單擊樣式選項卡,把圖示這一項給勾上。

按鈕控制元件類(CButton)類裡有個成員函式SetIcon可以設定按鈕顯示的圖示,該函式只有一個引數,那就是圖示控制代碼。

然後在對話方塊類的初始化函式(CFirstDlg::OnInitDialog)新增如下語句:

m_Quit.SetIcon((HICON)::LoadImage(NULL,”e:\i.ico”,IMAGE_ICON,48,48,LR_LOADFROMFILE));//假設E盤下有一個i.ico圖示

第二種根據圖示ID載入:

m_Quit.SetIcon(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_ICON1)));

記住語句新增的位置是在OnInitDialog函式所有程式碼之後,return TRUE;之前

2. 實現滑鼠停留在按鈕上時顯示提示資訊

首先在對話方塊類(CFirstDlg)裡新增一個m_ToolTip類物件(public:公有),如:CToolTipCtrlm_ToolTip;然後在對話方塊類裡的OnInitDialog函式新增以下語句:
m_ToolTip.Create(this);
m_ToolTip.AddTool(&m_Quit,”
文字資訊”); //其中m_Quit為按鈕控制元件關聯的變數接著往對話方塊類新增一個虛擬函式 PreTranslateMessage,這個虛擬函式有一個引數MSG *pMsg;MSG這個結構在API常用函式裡有解釋。這個函式會截獲所有傳送到對應視窗的訊息在這個函式新增這個語句:m_ToolTip.RelayEvent(pMsg);
完整的就是:
BOOL CFirstDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
m_ToolTip.RelayEvent(pMsg);
return CDialog::PreTranslateMessage(pMsg);
}

3. 建立動態控制元件

正確做法是用new呼叫CButton建構函式生成一個例項: 
CButton *p_MyBut = new CButton(); 
然後用CButton類的Create()函式建立,該函式原型如下: 
BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd*pParentWnd, UINT nID ); 
lpszCaption
是按鈕上顯示的文字; 
dwStyle
指定按鈕風格,可以是按鈕風格與視窗風格的組合,取值有:視窗風格: 
WS_CHILD
子視窗,必須有 
WS_VISIBLE
視窗可見,一般都有 
WS_DISABLED
禁用視窗,建立初始狀態為灰色不可用的按鈕時使用 
WS_TABSTOP
可用Tab鍵選擇 
WS_GROUP
成組,用於成組的單選按鈕中的第一個按鈕按鈕風格:

 控制元件風格 

 含義 

 BS_AUTOCHECKBOX 

 同BS_CHECKBOX,不過單擊滑鼠時按鈕會自動反轉。 

 BS_AUTORADIOBUTTON 

 同BS_RADIOBUTTON,不過單擊滑鼠時按鈕會自動反轉。 

 BS_AUTO3STATE 

 同BS_3STATE,不過單擊按鈕時會改變狀態。 

 BS_CHECKBOX 

 指定在矩形按鈕右側帶有標題的選擇框。 

 BS_DEFPUSHBUTTON 

 指定預設的命令按鈕,這種按鈕的周圍有一個黑框,使用者可以按回車鍵來快速選擇該按鈕,一個對話方塊中只能指定一個預設按鈕。 

 BS_GROUPBOX 

 指定一個組框。 

 BS_LEFTTEXT 

 使控制元件的標題顯示在按鈕的左邊。 

 BS_OWNERDRAW 

 指定一個自繪式按鈕。 

 BS_PUSHBUTTON 

 指定一個命令按鈕。 

 BS_RADIOBUTTON 

 指定一個單選按鈕,在圓按鈕的右邊顯示正文。 

 BS_3STATE 

 同BS_CHECKBOX,不過控制元件有三種狀態:選擇、未選擇和變灰。 

除了上表中的風格外,一般還要為控制元件指定WS_CHILD、WS_VISIBLE和WS_TABSTOP視窗風格,WS_TABSTOP使控制元件具有Tabstop屬性。建立一個普通按鈕應指定的風格為WS_CHILD|WS_VISIBLE|WS_TABSTOP。建立一個普通檢查框應指定風格WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX。建立組中第一個單選按鈕應指定風格WS_CHILD| WS_VISIBLE | WS_TABSTOP | WS_GROUP| BS_AUTORADIOBUTTON,組中其它單選按鈕應指定風格則不應該包括WS_TABSTOP和WS_GROUP。 
BS_BITMAP
按鈕上將顯示點陣圖-------------------------------------------------------------------------------------------------

rect指定按鈕的大小和位置; 
pParentWnd
指示擁有按鈕的父視窗,不能為NULL 
nID
指定與按鈕關聯的ID號,用上一步建立的ID號。

-------------------------------------------------------------------------------------------------

例:p_MyBut->Create("動態按鈕", WS_CHILD| WS_VISIBLE | BS_PUSHBUTTON, CRect(20,10,80,40), this, IDC_MYBUTTON ); 
這樣,我們就在當前對話方塊中的(20,10)處建立了寬60,高30,按鈕文字為動態按鈕的下壓式按鈕。

為了使建立過程更方便易用,我定義瞭如下函式:

CButton* CTextEditorView::NewMyButton(int nID,CRectrect,int nStyle) 

CString m_Caption; 
m_Caption.LoadString( nID ); //
取按鈕標題 
CButton *p_Button = new CButton(); 
ASSERT_VALID(p_Button); 
p_Button->Create( m_Caption, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | nStyle,rect, this, nID ); //
建立按鈕 
return p_Button; 
}

其中m_Caption.LoadString(nID )是從字串表中讀取按鈕文字,這樣在建立按鈕ID時,應該把文字設定好,引數nStyle為除必須風格外的額外風格。以下,我呼叫該函式建立三個按鈕,並指定第一個按鈕為預設按鈕,按鈕的ID已預先設定好了: 
CButton *p_MyBut[3]; 
p_MyBut[0] = NewMyButton( ID_MYBUT1, CRect(10,20,50,35), BS_DEFPUSHBUTTON); 
p_MyBut[1] = NewMyButton( ID_MYBUT2, CRect(55,20,95,35), 0 ); 
p_MyBut[2] = NewMyButton( ID_MYBUT3, CRect(100,20,140,35), 0 );

-------------------------------------------------------------------------------------------------

4. 動態控制元件的響應

動態控制元件的響應函式不能用ClassWizard新增,只能手動新增。仍以上面的按鈕為例,我們製作按鈕的單擊響應函式。

1.MESSAGE_MAP中新增響應函式:

MESSAGE_MAP表中定義了訊息響應函式,其格式為:訊息名(ID,函式名),當我們用ClassWizard新增函式時,會自動新增在AFX_MSG_MAP括起的區間內,如:

BEGIN_MESSAGE_MAP(CTextEditorView, CFormView) 
//{{AFX_MSG_MAP(CTextEditorView) 
ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0) 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP()

手工新增時不要新增到AFX_MSG_MAP區間內,以防ClassWizard不能正常工作,如: 
BEGIN_MESSAGE_MAP(CTextEditorView, CFormView) 
//{{AFX_MSG_MAP(CTextEditorView) 
ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0) 
//}}AFX_MSG_MAP 
ON_BN_CLICKED(ID_MYBUT1, OnMybut1) 
ON_BN_CLICKED(ID_MYBUT2, OnMybut2) 
ON_BN_CLICKED(ID_MYBUT3, OnMybut3) 
END_MESSAGE_MAP()

其中ON_BN_CLICKED是按鈕單擊訊息。 
2.
在標頭檔案中新增函式定義:

ClassWizard新增函式時,會在標頭檔案的AFX_MSG區間內新增函式定義,如:

protected: 
//{{AFX_MSG(CTextEditorView) 
afx_msg void OnIconbut0(); 
//}}AFX_MSG 
DECLARE_MESSAGE_MAP()

我們模仿這種形式,只是把函式定義新增到AFX_MSG區間外就行了: 
protected: 
//{{AFX_MSG(CTextEditorView) 
afx_msg void OnIconbut0(); 
//}}AFX_MSG 
afx_msg void OnMybut1(); 
afx_msg void OnMybut2(); 
afx_msg void OnMybut3(); 
DECLARE_MESSAGE_MAP()

3.編寫訊息響應函式:以上是把訊息和函式關聯起來了,具體在單擊按鈕後應做的工作在函式中完成:

void CTextEditorView::OnMybut1() 

MessageBox( "
哈!你單擊了動態按鈕。" ); 

void CTextEditorView::OnMybut2() 

…… 

void CTextEditorView::OnMybut3() 

…… 
}

除了按鈕的響應函式外,你還可以用上面獲得的指標訪問按鈕,如:修改按鈕的大小和位置:p_MyBut[0]->MoveWindow(……); 
修改按鈕文字:p_MyBut[0]->SetWindowText(……); 
顯示/隱藏按鈕:p_MyBut[0]->ShowWindow(……);等等。三、回收資源:

由於動態控制元件物件是由new生成的,它不會被程式自動釋放,所以需手工釋放。在控制元件不再使用時可以刪除它:

if( p_MyBut[0] ) 
delete p_MyBut[0];

以上就是按鈕控制元件動態生成的方法。下面,再看一下單選按鈕的動態生成問題。四、例項:單選按鈕組的動態生成

單選按鈕也屬於CButton類,但由於單選按鈕總是成組使用的,所以它在製作和使用上與普通按鈕有一定區別。

假設有三個單選按鈕組成一組,初始時,第一個單選按鈕處於選中狀態。

我們先來看靜態製作方法:在對話方塊中放置三個單選按鈕,設定屬性如下: 
Radio1
屬性:VisibleGroupTab stopAuto 
Radio2
屬性:VisibleTab stopAuto 
Radio3
屬性:VisibleTab stopAuto 
這樣的屬性設定就把三個單選按鈕分成了一組,它們一次只能有一個被選中,若對話方塊中還有其它成組的單選按鈕,使用時也會互不干擾。但這時還沒有使第一個按鈕處於選中狀態。接著就用ClassWizard為這組單選按鈕新增變數,這裡只需為第一個單選按鈕新增變數即可。設變數名為m_Radio,型別選為int型。在建構函式中ClassWizardm_Radio的值設定為-1,我們把它改為0,這樣在執行程式時可以看到第一個單選按鈕處於選中狀態了。之後,還應該用ClassWizard為三個單選按鈕新增單擊響應函式,在裡面修改m_Radio的值對應三個單選按鈕就可以了。以上就是通常製作單選按鈕組的辦法,現我們欲改為動態生成,主要要解決按鈕分組和單擊控制問題。以下為製作步驟:

1.定義三個單選按鈕的ID

開啟資源中的“String Table”,在其中新增三個ID值:第一個:IDIDC_MYRADIO1Caption為單選
第二個:IDIDC_MYRADIO2Caption為單選
第三個:IDIDC_MYRADIO3Caption為單選
其中Caption為按鈕上要顯示的文字,可根據需要設定。

2.CButton類的Create()函式生成三個單選按鈕:

為方便起見,先定義一個函式生成單選按鈕:

CButton* CTextEditorView::NewMyRadio(int nID,CRectrect,int nStyle) 

CString m_Caption; 
m_Caption.LoadString( nID ); //
取按鈕標題 
CButton *p_Radio = new CButton(); 
ASSERT_VALID(p_Radio); 
p_Radio->Create( m_Caption, WS_CHILD | WS_VISIBLE | nStyle | WS_TABSTOP |BS_AUTORADIOBUTTON, rect, this, nID ); //
建立按鈕 
return p_Radio; 
}

函式LoadString()用於從“String Table”中讀取按鈕文字,Create()函式中設定了單選按鈕必須的屬性,其中就包括了VisibleTab stopAuto屬性。引數nID為單選按鈕ID號,rect為單選按鈕尺寸,nStyle為除必要屬性外的其它屬性。返回值為指向新建按鈕的指標。有了這個函式後,建立單選按鈕組時只要依次呼叫該函式即可,其中單選按鈕組的第一個單選按鈕必須指定WS_GROUP屬性。

CButton *p_MyRadio[3]; 
p_MyRadio[0] = NewMyRadio( IDC_MYRADIO1, CRect(15,90,60,105), WS_GROUP ); 
p_MyRadio[1] = NewMyRadio( IDC_MYRADIO2, CRect(15,108,60,123), 0 ); 
p_MyRadio[2] = NewMyRadio( IDC_MYRADIO3, CRect(15,126,60,141), 0 );

3.定義單選按鈕組的控制變數,設定第一個單選按鈕為選中狀態:這裡不能用ClassWizard新增變數,也不要在DoDataExchange()中新增控制變數,因為動態控制元件一開始並不存在,在DoDataExchange()中新增控制變數會造成執行錯誤。這裡我們只需在標頭檔案中隨意定義一個int型變數作為控制變數即可,如: 
int m_SelRadio; 
在建構函式中設定其初值為0m_SelRadio = 0; 
在上面的建立按鈕的語句中,用SetCheck()函式設定初始選中的按鈕:

CButton *p_MyRadi