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;
}
-------------------------------------------------------------------------------------------------
通過上述程式碼,就可以得到彩色的文字以及透明的背景,但是,還存在一個問題,當該
解決方法是,讓父視窗進行重繪更新,對,不要看錯了,是控制元件所屬的父視窗,而不是控制元件本身,讓控制元件本身重繪也不會解決問題的,這裡還會引出一個問題,如果重繪整個父視窗,由於GDI並不內嵌雙緩衝,勢必造成嚴重的閃爍問題,解決辦法當然是只讓父視窗重繪控制元件所佔的部分,其他部分不進行重繪,程式碼如下:
C++程式碼
- void CSample::SetText( const TCHAR *pszText)
- {
- this ->SetWindowText(pszText);
- RECT stRect;
- // 獲取控制元件位置
- this ->GetWindowRect(&stRect);
- // 重要!呼叫父視窗的S2C函式進行座標轉換
- this ->GetParent()->ScreenToClient(&stRect);
- // 重繪控制元件所在區域,在這裡擦除背景
- this ->GetParent()->InvalidateRect(&stRect, true );
- }
這樣就能夠實現動態改變文字屬性而不出現重影現象,注意這裡呼叫了父視窗的ScreenToClient()函式來進行座標的轉換,呼叫控制元件本身的S2C函式的話,得到的座標無法用來進行下一步的重繪工作。
現在還有一個比較隱蔽的問題,就是文字字串的長度,如果新的字串的長度比原來的長,而之前拖放Static控制元件長度又不足的時候,就會造成超出的部分無法顯示,當然你大可以在拖放的時候就儘量弄得長一點,但是如果能隨著文字內容而自動調整控制元件長度,那不是會好得多麼。
為了實現這樣的效果,上面的程式碼要修改如下:
C++程式碼
- void CSample::SetText( const TCHAR *pszText)
- {
- CDC *pDC = this ->GetDC();
- // 獲取文字在當前繪圖環境下所佔的寬度和高度
- CSize clSize = pDC->GetTextExtent(pszText, _tcslen(pszText));
- RECT stRect;
- // 獲取控制元件當前矩形區域
- this ->GetWindowRect(&stRect);
- // 調整寬度為新文字所佔寬度
- stRect.right = stRect.left + clSize.cx;
- // 重要!呼叫父視窗S2C函式轉換座標
- this ->GetParent()->ScreenToClient(&stRect);
- // 調整控制元件大小以適應新文字
- this ->MoveWindow(&stRect);
- // 重繪控制元件以避免重影
- this ->GetWindowRect(&stRect);
- this ->GetParent()->ScreenToClient(&stRect);
- this ->GetParent()->InvalidateRect(&stRect, true );
- }
同樣,這裡也是呼叫父視窗的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後,如果nStart和nEnd,表明游標處於某個位置(直觀來看就是游標在閃動);如果nStart和nEnd不相等,表明使用者在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=0且nEndChar=-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屬性:Visible、Group、Tab stop、Auto
Radio2屬性:Visible、Tab stop、Auto
Radio3屬性:Visible、Tab stop、Auto
這樣的屬性設定就把三個單選按鈕分成了一組,它們一次只能有一個被選中,若對話方塊中還有其它成組的單選按鈕,使用時也會互不干擾。但這時還沒有使第一個按鈕處於選中狀態。接著就用ClassWizard為這組單選按鈕新增變數,這裡只需為第一個單選按鈕新增變數即可。設變數名為m_Radio,型別選為int型。在建構函式中ClassWizard把m_Radio的值設定為-1,我們把它改為0,這樣在執行程式時可以看到第一個單選按鈕處於選中狀態了。之後,還應該用ClassWizard為三個單選按鈕新增單擊響應函式,在裡面修改m_Radio的值對應三個單選按鈕就可以了。以上就是通常製作單選按鈕組的辦法,現我們欲改為動態生成,主要要解決按鈕分組和單擊控制問題。以下為製作步驟:
1.定義三個單選按鈕的ID:
開啟資源中的“String Table”,在其中新增三個ID值:第一個:ID為IDC_MYRADIO1,Caption為單選1
第二個:ID為IDC_MYRADIO2,Caption為單選2
第三個:ID為IDC_MYRADIO3,Caption為單選3
其中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()函式中設定了單選按鈕必須的屬性,其中就包括了Visible、Tab stop、Auto屬性。引數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;
在建構函式中設定其初值為0:m_SelRadio = 0;
在上面的建立按鈕的語句中,用SetCheck()函式設定初始選中的按鈕:
CButton *p_MyRadi