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++程式碼
- 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 |
當使用者在最後一個可見行按Enter鍵時,正文向上滾動一頁。 |
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 |
使多行編輯器接收Enter鍵輸入並換行。如果不指定該風格,按Enter鍵會選擇預設的命令按鈕,這往往會導致對話方塊的關閉。 |
除了上表中的風格外,一般還要為控制元件指定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"
"網址: http://www.ccrun.com\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 |
指定預設的命令按鈕,這種按鈕的周圍有一個黑框,使用者可以按Enter鍵來快速選擇該按鈕,一個對話方塊中只能指定一個預設按鈕。 |
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_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 );
p_MyRadio[m_SelRadio]->SetCheck(1); //設定第一個單選為選中狀態
在SetCheck()函式中,引數為1表示設定為選中狀態,為0表示未選中狀態。
4.新增滑鼠單擊響應函式:
滑鼠單擊某單選按鈕後,其狀態已經能自動改變,這裡我們還需修改控制變數m_SelRadio的值,以便跟蹤選中的單選按鈕。
首先在MESSAGE_MAP中把滑鼠單擊訊息與響應函式聯絡起來:
BEGIN_MESSAGE_MAP(CTextEditorView, CFormView)
//{{AFX_MSG_MAP(CTextEditorView)
ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0) //ClassWizard在此處新增
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_MYRADIO1, OnMyRadio1) //單選按鈕1
ON_BN_CLICKED(IDC_MYRADIO2, OnMyRadio2) //單選按鈕2
ON_BN_CLICKED(IDC_MYRADIO3, OnMyRadio3) //單選按鈕3
END_MESSAGE_MAP()
然後在標頭檔案的MESSAGE_MAP中定義單擊函式:
protected:
//{{AFX_MSG(CTextEditorView)
afx_msg void OnIconbut0(); //ClassWizard在此處新增
//}}AFX_MSG
afx_msg void OnMyRadio1(); //單選按鈕1
afx_msg void OnMyRadio2(); //單選按鈕2
afx_msg void OnMyRadio3(); //單選按鈕3
DECLARE_MESSAGE_MAP()
這裡注意不要把函式加在AFX_MSG區間內,以防影響ClassWizard的使用。
定義具體的響應函式(這裡是用手工加入的,不是用ClassWizard加入的):
//單擊單選按鈕1
void CTextEditorView::OnMyRadio1()
{
m_SelRadio=0;
}
//單擊單選按鈕2
void CTextEditorView::OnMyRadio2()
{
m_SelRadio=1;
}
//單擊單選按鈕3
void CTextEditorView::OnMyRadio3()
{
m_SelRadio=2;
}
5.回收資源:
在解構函式中,回收建立的單選按鈕(也可以在不使用單選按鈕時立即回收):
CTextEditorView::~CTextEditorView()
{
int i;
for( i=0; i<3; i++)
{
if(p_MyRadio[i])
delete p_MyRadio[i];
}
}
以上就是動態控制元件的生成和響應方法,各種不同的控制元件做法略有不同,但思路和步驟都是類似的,希望以上例項對你能夠有所幫助。
//-------------以下是文自己總結--------------
其實拖動控制元件到視窗就可以。
說下這裡的基本思路;
1、在標頭檔案中宣告控制元件執行方法。
public:
afx_msg void OnBnClickedCheck();
2、在程式檔案中實現這個方法。
void OnBnClickedCheck()
{
//在這裡實現,點選button後相應的實現
}
3、在程式檔案中註冊這個控制元件和這個方法之間的關係,就是所謂的註冊訊息
ON_BN_CLICKED(IDC_Check,OnBnClickedCheck) //這裡後面沒有分號;
5.按鈕按下和釋放時圖片的切換
VC為按鈕控制元件新增圖片的方法有很多種:
直接呼叫SetBitmap; CButton pButton->SetBitmap(hBitmap);
使用CButtonST控制元件;
使用CDC;
使用CBitmapButton;
這裡主要講解CBitmapButton的使用,CBitmapButton作為MFC的控制元件類,具體使用如下:
建立一個新的基於對話方塊的MFC工程首先新增按鈕控制元件,將屬性Owner Draw設為True,按鈕ID: IDC_BUTTON1
新增點陣圖資源ID:IDB_BITMAP_CLOSE IDB_BITMAP_RED
在對話方塊類中新增private成員變數: CBitmapButton m_button; bool LedFlag;
private:
CBitmapButton m_button;
boolLedFlag;
在初始化函式OnInitDialog裡新增圖片載入:
m_button.LoadBitmaps(IDB_BITMAP1);
m_button.SubclassDlgItem(IDC_BUTTON2,this);
m_button.SizeToContent();
使用CBitmapButton::LoadBitmaps裝載各種狀態的圖片,再用SubclassDlgItem關聯到想要的按鈕,使用CBitmapButton::SizeToContent函式使按鈕適合圖片大小。注意Loadbitmaps一定要在關聯到按鈕之前進行!
為按鈕控制元件新增單擊事件處理函式,輸入如下程式碼:
LedFlag = !LedFlag;
if (LedFlag)
{
m_button.LoadBitmaps(IDB_BITMAP1);
m_button.Invalidate();
}
else
{
m_button.LoadBitmaps(IDB_BITMAP2);
m_button.Invalidate();
}
按理來說,寫上m_ctrlButton.LoadBitmaps(圖片ID);就可以了,可是這樣做之後,發現按鍵了沒反應。無意中將對話方塊最小化再還原,發現圖片變了。所以實際上是沒有進行重新整理導致的。在後面加上m_button.Invalidate()就可以了。
List Box
1. 宣告CListBox變數和連線控制元件(Listbox Control)
(1) 在Dialog類中,宣告CListBox型別的成員變數.
例如在listDlg.h 檔案中:
- class ClistDlg : public CDialog{
- ...
- public:
- CListBox m_list1;
- };
(2) DoDataExchang函式中,把m_list1成員變數連線到控制元件.
在listDlg.cpp檔案中
- void Clist1Dlg::DoDataExchange(CDataExchange* pDX){
- CDialog::DoDataExchange(pDX);
- DDX_Control(pDX, IDC_LIST1, m_list1);
- }
2. 向Listbox中新增資料
在 listDlg.cpp 檔案中:
- BOOL Clist1Dlg::OnInitDialog(){
- ....
- m_list1.AddString(_T("Item A"));
- m_list1.AddString(_T("Item B"));
- }
//備註: 也可以定義個控制元件物件的指標,對物件進行操作: 如下: (這樣就不需要上述的第一步了)
- CListBox *pCtrl = (CListBox *)GetDlgItem(IDC_LIST1);
- pCtrl->AddString(_T("A"));
- pCtrl->AddString(_T("B"));
3. 從Listbox 中獲取資料
- CString s;
- m_list1.GetText(1,s);
- MessageBox(s,_T("取得第2行資料"),MB_OK);
- s.ReleaseBuffer();
4. 獲取選擇的資料
首先要將Listbox的Selection屬性設定為Multiple;
- int nSel;
- nSel=m_ListBox_Content.GetCurSel();
- CString s;
- m_ListBox_Content.GetText(nSel,s);
- MessageBox(s,_T("您選擇的是"),MB_OK);
- s.ReleaseBuffer();
5. 獲取選擇ListBox項的多個資料
首先要將ListBox的Selection的屬性設定為Multiple
- int nSel = m_ListBox_Content.GetSelCount();
- CArray< int,int& > arrayListSel;
- arrayListSel.SetSize(nSel);
- m_ListBox_Content.GetSelItems(nSel,arrayListSel.GetData());
- CString s = _T("");
- for( int i=0; i< nSel; i++ )
- {
- m_ListBox_Content.GetText( arrayListSel[i], s);
- MessageBox(s,_T("您選擇的是"),MB_OK);
- }
6. 雙擊刪除所選項
新增一個Listbox的雙擊事件
- m_ListBox_Content.DeleteString(m_ListBox_Content.GetCurSel());
7. 通過物件指標來操作Listbox Control
OnInitDialog();函式裡初始化
- // TODO: 在此新增額外的初始化程式碼
- CListBox *pCtrl = (CListBox *)GetDlgItem(IDC_LIST1);
- pCtrl->AddString(_T("A"));
- pCtrl->AddString(_T("B"));
對CListBox的操作
- void CUseControlDlg::OnBnClickedButtonOk()
- {
- // TODO: 在此新增控制元件通知處理程式程式碼
- CListBox *m_lstInfo = (CListBox *)GetDlgItem(IDC_LIST1);
- //那麼你可以用一個迴圈取出裡面的值:
- /*
- CString str; //臨時變數用來接收項的字串
- CString strAll=_T(""); //所有項
- int nCount = m_lstInfo->GetCount();//得到專案總數
- for(int i = 0; i< nCount; ++i)
- {
- m_lstInfo->GetText(i,str);
- strAll = strAll + str + _T("\r\n");
- }
- AfxMessageBox(strAll);
- */
- //取出單選選中的值
- /*
- int index;
- CString selectStr;
- index = m_lstInfo->GetCurSel();
- m_lstInfo->GetText(index,selectStr);
- AfxMessageBox(selectStr);
- */
- //多選,設定selection為Multiple
- int nCount = m_lstInfo->GetSelCount();
- CString cCount;
- CArray<int,int> aryListBoxSel;
- aryListBoxSel.SetSize(nCount);
- m_lstInfo->GetSelItems(nCount, aryListBoxSel.GetData());
- //得到總數
- cCount.Format(_T("%d"),nCount);
- AfxMessageBox(cCount);
- //得到選中的多項
- for (int i=0;i<nCount;i++)
- {
- CString selStr;
- m_lstInfo->GetText(aryListBoxSel[i],selStr);
- AfxMessageBox(selStr);
- }
List Control
3.1 ClistCtrl風格
1. CListCtrl 風格
LVS_ICON: 為每個item顯示大圖示
LVS_SMALLICON: 為每個item顯示小圖示
LVS_LIST: 顯示一列帶有小圖示的item
LVS_REPORT: 顯示item詳細資料
直觀的理解:windows資源管理器,"檢視"標籤下的"大圖示,小圖示,列表,詳細資料
LVS_ALIGNLEFT |
當顯示格式是大圖示或小圖示時,標題放在圖示的左邊.預設情況下標題放在圖示的下面. |
LVS_ALIGNTOP |
當顯示格式是大圖示或小圖示時,標題放在圖示的上邊. |
LVS_AUTOARRANGE |
當顯示格式是大圖示或小圖示時,自動排列控制元件中的表項. |
LVS_EDITLABELS |
使用者可以修改標題. |
LVS_ICON |
指定大圖示顯示格式. |
LVS_LIST |
指定列表顯示格式. |
LVS_NOCOLUMNHEADER |
在報告格式中不顯示列的表頭. |
LVS_NOLABELWRAP |
當顯示格式是大圖示時,使標題單行顯示.預設時是多行顯示. |
LVS_NOSCROLL |
列表檢視無滾動條. |
LVS_NOSORTHEADER |
報告列表檢視的表頭不能作為排序按鈕使用. |
LVS_OWNERDRAWFIXED |
由控制元件的擁有者負責繪製表項. |
LVS_REPORT |
指定報告顯示格式. |
LVS_SHAREIMAGELISTS |
使列表檢視共享影象序列. |
LVS_SHOWSELALWAYS |
即使控制元件失去輸入焦點,仍顯示出項的選擇狀態. |
LVS_SINGLESEL |
指定一個單選擇列表檢視.預設時可以多項選擇. |
LVS_SMALLICON |
指定小圖示顯示格式. |
LVS_SORTASCENDING |
按升序排列表項. |
LVS_SORTDESCENDING |
按降序排列表項. |
除上表的風格外,一般還要指定WS_CHILD和WS_VISIBLE視窗風格.風格組合WS_CHILD| WS_VISIBLE|LVS_REPORT|LVS_AUTOARRANGE|LVS_EDITLABLES|LVS_SINGLESEL將指定一個自動排列的、可編輯標題的、單選擇報告式列表檢視控制元件.要指定大圖示、小圖示或列表式的列表檢視控制元件,則應該把LVS_REPORT換成LVS_ICON、LVS_SMALLICON或LVS_LIST.
對於用對話方塊模板建立的列表檢視控制元件,可以在控制元件的屬性對話方塊中指定上表中列出的控制元件風格。例如,在屬性對話方塊的Styles頁的View欄中選擇Icon,相當於指定了LVS_ICON風格.
--------------------------------------------------------------------------------
2. 設定listctrl 風格及擴充套件風格
LONG lStyle;
lStyle = GetWindowLong(m_list.m_hWnd,GWL_STYLE);//獲取當前視窗style
lStyle &= ~LVS_TYPEMASK; //清除顯示方式位
lStyle |= LVS_REPORT; //設定style
SetWindowLong(m_list.m_hWnd, GWL_STYLE,lStyle);//設定style
DWORD dwStyle =m_list.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//選中某行使整行高亮(只適用與report風格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//網格線(只適用與report風格的listctrl)
dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控制元件
m_list.SetExtendedStyle(dwStyle); //設定擴充套件風格
--------------------------------------------------------------------------------
3. 一直選中item
選中style中的Show selection always,或者在上面第2點中設定LVS_SHOWSELALWAYS
3.2 插入資料
m_list.InsertColumn(0, "ID", LVCFMT_LEFT, 40 );//插入列
m_list.InsertColumn( 1, "NAME",LVCFMT_LEFT, 50 );
//新插入的在上面
int nRow = m_list.InsertItem(0,"11");// 插入行
m_list.SetItemText(nRow, 1,"jacky");//設定其它列資料
//新插入的資料在下面
int nIndex =m_list.GetItemCount();
LV_ITEM lvItem;
lvItem.mask = LVIF_TEXT ;
lvItem.iItem = nIndex; //行數
lvItem.iSubItem = 0;
lvItem.pszText = (char*)(LPCTSTR)strCount; //第一列
//在最後一行插入記錄值.
m_list.InsertItem(&lvItem);
//插入其它列
m_list.SetItemText(nIndex,1,strLat);
--------------------------------------------------------------------------------
3.3 選中和取消選中一行
int nIndex = 0;
//選中
m_list.SetItemState(nIndex, LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
//取消選中
m_list.SetItemState(nIndex, 0,LVIS_SELECTED|LVIS_FOCUSED);
--------------------------------------------------------------------------------
3.4 得到listctrl中所有行的checkbox的狀態得到listctrl中所有選中行的序號
m_list.SetExtendedStyle(LVS_EX_CHECKBOXES);
CString str;
for(int i=0; i<m_list.GetItemCount(); i++)
{
if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED ||m_list.GetCheck(i))
{
str.Format(_T("第%d行的checkbox為選中狀態"),i);
AfxMessageBox(str);
}
}
--------------------------------------------------------------------------------
3.5 得到listctrl中所有選中行的序號
方法一:
CString str;
for(int i=0; i<m_list.GetItemCount();i++)
{
if(m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )
{
str.Format(_T("選中了第%d行"), i);
AfxMessageBox(str);
}
}
方法二:
POSITION pos =m_list.GetFirstSelectedItemPosition();
if (pos == NULL)
TRACE0("Noitems were selected!/n");
Else
{
while (pos)
{
int nItem = m_list.GetNextSelectedItem(pos);
TRACE1("Item %d was selected!/n", nItem);
// you could do your own processing on nItem here
}
}
--------------------------------------------------------------------------------
3.6 得到item的資訊
TCHAR szBuf[1024];
LVITEM lvi;
lvi.iItem = nItemIndex;
lvi.iSubItem = 0;
lvi.mask = LVIF_TEXT;
lvi.pszText = szBuf;
lvi.cchTextMax = 1024;
m_list.GetItem(&lvi);
--------------------------------------------------------------------------------
3.7 得到listctrl的所有列的header字串內容
LVCOLUMN lvcol;
char str[256];
int nColNum;
CString strColumnName[4];//假如有4列
nColNum = 0;
lvcol.mask = LVCF_TEXT;
lvcol.pszText = str;
lvcol.cchTextMax = 256;
while(m_list.GetColumn(nColNum,&lvcol))
{
strColumnName[nColNum] = lvcol.pszText;
nColNum++;
}
--------------------------------------------------------------------------------
3.8 使listctrl中一項可見,即滾動滾動條
m_list.EnsureVisible(i, FALSE);
--------------------------------------------------------------------------------
3.9 得到listctrl列數
int nHeadNum =m_list.GetHeaderCtrl()->GetItemCount();
--------------------------------------------------------------------------------
3.10 刪除所有行列
//首先刪除所有行
m_ListCtrl.DeleteAllItems();
//得到列數
intnItmcount = m_ListCtrl.GetHeaderCtrl()->GetItemCount();
//刪除所有列
for(int i = 0; i<nItmcount; i++)
{
m_ListCtrl.DeleteColumn(0);
}
--------------------------------------------------------------------------------
3.11 得到單擊的listctrl的行列號
新增listctrl控制元件的NM_CLICK訊息相應函式
void CTest6Dlg::OnClickList1(NMHDR*pNMHDR, LRESULT* pResult)
{
// 方法一:
/*
DWORD dwPos =GetMessagePos();
CPoint point(LOWORD(dwPos), HIWORD(dwPos) );
m_list.ScreenToClient(&point);
LVHITTESTINFOlvinfo;
lvinfo.pt =point;
lvinfo.flags =LVHT_ABOVE;
int nItem =m_list.SubItemHitTest(&lvinfo);
if(nItem !=-1)
{
CString strtemp;
strtemp.Format("單擊的是第%d行第%d列",lvinfo.iItem,
lvinfo.iSubItem);
AfxMessageBox(strtemp);
}
*/
// 方法二:
/*
NM_LISTVIEW*pNMListView = (NM_LISTVIEW*)pNMHDR;
if(pNMListView->iItem != -1)
{
CString strtemp;
strtemp.Format("單擊的是第%d行第%d列",
pNMListView->iItem, pNMListView->iSubItem);
AfxMessageBox(strtemp);
}
*/
*pResult =0;
}
--------------------------------------------------------------------------------
3.12 判斷是否點選在listctrl的checkbox上
新增listctrl控制元件的NM_CLICK訊息相應函式
void CTest6Dlg::OnClickList1(NMHDR* pNMHDR,LRESULT* pResult)
{
DWORD dwPos = GetMessagePos();
CPoint point(LOWORD(dwPos), HIWORD(dwPos) );
m_list.ScreenToClient(&point);
LVHITTESTINFOlvinfo;
lvinfo.pt =point;
lvinfo.flags =LVHT_ABOVE;
UINT nFlag;
int nItem =m_list.HitTest(point, &nFlag);
//判斷是否點在checkbox上
if(nFlag ==LVHT_ONITEMSTATEICON)
{
AfxMessageBox("點在listctrl的checkbox上");
}
*pResult =0;
}
--------------------------------------------------------------------------------
3.13 右鍵點選listctrl的item彈出選單
新增listctrl控制元件的NM_RCLICK訊息相應函式
void CTest6Dlg::OnRclickList1(NMHDR*pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW*pNMListView = (NM_LISTVIEW*)pNMHDR;
if(pNMListView->iItem != -1)
{
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
CMenu menu;
VERIFY( menu.LoadMenu( IDR_MENU1 ) );
CMenu* popup = menu.GetSubMenu(0);
ASSERT( popup != NULL );
popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
*pResult =0;
}
--------------------------------------------------------------------------------
3.14 item切換焦點時(包括用鍵盤和滑鼠切換item時),狀態的一些變化順序
新增listctrl控制元件的LVN_ITEMCHANGED訊息相應函式
void CTest6Dlg::OnItemchangedList1(NMHDR*pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW*pNMListView = (NM_LISTVIEW*)pNMHDR;
// TODO: Add yourcontrol notification handler code here
CStringsTemp;
if((pNMListView->uOldState & LVIS_FOCUSED) == LVIS_FOCUSED &&(pNMListView->uNewState & LVIS_FOCUSED) == 0)
{
sTemp.Format("%d losted focus",pNMListView->iItem);
}
elseif((pNMListView->uOldState & LVIS_FOCUSED) == 0 &&
(pNMListView->uNewState & LVIS_FOCUSED) == LVIS_FOCUSED)
{
sTemp.Format("%d got focus",pNMListView->iItem);
}
if((pNMListView->uOldState & LVIS_SELECTED) == LVIS_SELECTED&&
(pNMListView->uNewState & LVIS_SELECTED) == 0)
{
sTemp.Format("%d losted selected",pNMListView->iItem);
}
else if((pNMListView->uOldState & LVIS_SELECTED) == 0 &&(pNMListView->uNewState & LVIS_SELECTED) == LVIS_SELECTED)
{
sTemp.Format("%d got selected",pNMListView->iItem);
}
*pResult = 0;
--------------------------------------------------------------------------------
3.15 listctrl的subitem新增圖示
m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);
m_list.SetItem(..); //具體引數請參考msdn
--------------------------------------------------------------------------------
Combo Box
1. 向控制元件新增 Items
1) 在Combo Box控制元件屬性的Data標籤裡面新增,一行表示Combo Box下拉選單中的一行。換行用ctrl+回車。
2) 利用函式 AddString() 向 Combo Box 控制元件新增 Items,如:
m_cbExample.AddString(“StringData1”);
m_cbExample.AddString(“StringData2”);
m_cbExample.AddString(“StringData3”);
3) 也可以呼叫函式 InsertString() 將 Item 插入指定位置 nIndex,如:
m_cbExample.InsertString(nIndex, “StringData” );
--------------------------------------------------------------------------------
2. 從控制元件得到選定的Item
int nIndex =m_cbExample.GetCurSel();
CStringstrCBText;
m_cbExample.GetLBText(nIndex, strCBText);
這樣,得到的內容就儲存在 strCBText 中。
--------------------------------------------------------------------------------
3. 在控制元件中查詢給定Item
這種操作一般用於在程式中動態修改控制元件中該項的值,可以用函式FindStringExact()精確匹配,如:
int nIndex =m_cbExample.FindStringExact( nStartAfter, “value to be found”);
nStartAfter指明從哪一行開始查詢。如果查詢成功,返回的是該項的位置;否則,返回CB_ERR。
也可以選中包含指定字串的項,如:
int nIndex =m_cbExample.SelectString( nStartAfter, “value to be selected”);
--------------------------------------------------------------------------------
4. 刪除控制元件中的Item
該操作可以利用函式DeleteString(),需要指定被刪除項的位置,如:
m_cbExample.DeleteString(nIndex);
也可以使用函式ResetContent(),清除目前的所有項,如:
m_cbExample.ResetContent()
--------------------------------------------------------------------------------
5. 顯示控制元件中的某項
int nIndex =m_cbExample.GetCurSel(); //當前選中的項
m_cbExample.SetCurSel(nIndex);//設定第nIndex項為顯示的內容
--------------------------------------------------------------------------------
6. 得到或設定輸入框中被選中的字元位置
DWORDGetEditSel( ) /BOOL SetEditSel( int nStartChar, int nEndChar );
BOOL LimitText(int nMaxChars ); 設定輸入框中可輸入的最大字元數。
--------------------------------------------------------------------------------
7. 列表框常用訊息對映巨集
ON_CBN_DBLCLK 滑鼠雙擊
ON_CBN_DROPDOWN 列表框被彈出
ON_CBN_KILLFOCUS/ ON_CBN_SETFOCUS 在輸入框失去/得到輸入焦點時產生
ON_CBN_SELCHANGE列表框中選擇的行發生改變
ON_CBN_EDITUPDATE輸入框中內容被更新
--------------------------------------------------------------------------------
8. 補充:如何新增/刪除Combo Box內容
1,在Combo Box控制元件屬性的Data標籤裡面新增,一行表示Combo Box下拉選單中的一行。換行用ctrl+回車。
2,在程式初始化時動態新增
如: //控制元件內容初始化
CString strTemp;
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->ResetContent();//消除現有所有內容
for(inti=1;i<=100;i++)
{
strTemp.Format("%d",i);
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->AddString(strTemp);
}
3,下拉的時候新增
如: CStringstrTemp;
intiCount=((CComboBox*)GetDlgItem(IDC_COMBO_CF))->GetCount();//取得目前已經有的行數
if(iCount<1)//防止重複多次新增
{
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->ResetContent();
for(inti=1;i<=100;i++)
{
strTemp.Format("%d",i);
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->AddString(strTemp);
}
}
4,刪除
DeleteString(UINT nIndex )//刪除指定行,
5,插入
InsertString(int nIndex, LPCTSTR lpszItem )//將行插入到指定位置
6,查詢
FindString( intnStartAfter, LPCTSTR lpszItem )//可以在當前所有行中查詢指定的字元傳的位置,nStartAfter指明從那一行開始進行查詢。
intSelectString( int nStartAfter, LPCTSTR lpszItem )//可以選中包含指定字串的行
--------------------------------------------------------------------------------
9. 補充:選擇其中的某行
1,選中:
intiPos=((CComboBox*)GetDlgItem(IDC_COMBO_CF))->GetCurSel();//當前選中的行。
2,設定
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->SetCurSel(n)//設定第n行內容為顯示的內容。
--------------------------------------------------------------------------------
10. 補充:取得Combo Box框內容
1取當前內容
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->GetWindowText(strTemp);
2取其他行內容
((CComboBox*)GetDlgItem(IDC_COMBO_CF))->GetLBText(n,strTemp);
--------------------------------------------------------------------------------
11. 獲得焦點
通常要判斷控制元件是否獲得了焦點,可以用GetFocus()函式
例如:if(GetFocus()==GetDlgItem(IDC_EDIT_VALUE2))//判斷焦點是否在編輯框IDC_EDIT_VALUE2內。
但是combobox 的焦點不同,因為它是由edit和listbox兩部分組成的
所以獲得焦點要用GetParent():if((GetFocus()->GetParent())==GetDlgItem(IDC_COMBO_CF))
--------------------------------------------------------------------------------
12. 如何控制Combo Box的下拉長度
1,首先要知道兩點:一、那就是在設計介面裡,點選一下Combo Box的下拉箭頭,此時出現的調整框就是Combo Box的下拉調整框。
2,二、屬性裡有個 No integral height 鉤選項,表示最大長度為設計長度,如果實際內容比設計長度多,就出現滾動條,少就以實際長度顯示。
--------------------------------------------------------------------------------
13. 組合框的風格
控制元件風格 |
含義 |
CBS_AUTOHSCROLL |
使編輯框元件具有水平滾動的風格. |
CBS_DROPDOWN |
指定一個下拉式組合框. |
CBS_DROPDOWNLIST |
指定一個下拉選單式組合框. |
CBS_HASSTRINGS |
指定一個含有字串的自繪式組合框. |
CBS_OEMCONVERT |
使編輯框元件中的正文可以在ANSI字符集和OEM字符集之間相互轉換。這在編輯框中包含檔名時是很有用的。 |
CBS_OWNERDRAWFIXED |
指定自繪式組合框,即由父視窗負責繪製列表框的內容,並且列表項有相同的高度. |
CBS_OWNERDRAWVARIABLE |
指定自繪式組合框,並且列表項有不同的高度. |
CBS_SIIMPLE |
指定一個簡易式組合框. |
CBS_SORT |
自動對列表框元件中的項進行排序. |
CBS_DISABLENOSCROLL |
使列表框在不需要滾動時顯示一個禁止的垂直滾動條. |
CBS_NOINTEGRALHEIGHT |
組合框的尺寸由應用程式而不是Windows指定.通常,由Windows指定尺寸會使列表項的某些部分隱藏起來. |
CBS_SIMPLE、CBS_DROPDOWN和CBS_DROPDOWNLIST分別用來將組合框指定為簡易式、下拉式和下拉選單式.一般還要為組合框指定WS_CHILD、WS_VISIBLE、WS_TABSTOP、WS_VSCROLL和CBS_AUTOHSCROLL風格.如果要求自動排序,還應指定CBS_SORT風格.
對於用對話方塊模板編輯器建立的組合框控制元件,可以在控制元件的屬性對話方塊中指定上表中列出的控制元件風格。例如,在屬性對話方塊中選擇Dropdown,相當於指定了CBS_DROPDOWN.
Group Box
1. 組合框 Group Box作用
在MFC基於對話方塊的應用程式中,Group Box組合框就是將組合框內的控制元件標識為一組控制元件來使用:只能選擇其中的一個控制元件(如性別選擇,當選擇男時,女不被選擇;當選擇女時男不被選擇)。
GroupBox屬性設定也有多種。在直接使用Group Box本身時,一般將Group Box拖進對話方塊後需要重新設定的屬性就是標題。如用Group Box做性別選擇之用需要將其標題修改為“性別選擇”時則需要進行如下操作:選中組合框-->右鍵-->Caption:性別選擇。
2. 組合框 Group Box及內控制元件屬性設定
當把Group Box拉進對話方塊後需要對Group Box的屬性進行設定,使之具有組合框的功能。除了修改其標題之外,還需要將Group Box的Group屬性設定為true。同時對組合框內的控制元件的group屬性不可設定為true。
例:MFC對話方塊中拖進Group Box,將其標題修改為“性別選擇”,並再拖進兩個Radio Button按鈕進去,一個作為“男”,一個作為“女”,使之使用者在同一時刻只能選擇“男”或者“女”按鈕。
圖1 Group Box 及 其內控制元件屬性設定
GroupBox 、Radio Button等控制元件的屬性都是通過選中其本身後通過右鍵選擇屬性來進行設定的。其它的屬性可根據實際需要再進行設定。
3. Group Box內控制元件的預設設定
程式執行後,在未對Group Box內控制元件進行選擇時需要對Group Box內的控制元件進行一個預設的選擇。這個只需要在程式執行時新增一條語句即可:
[cpp] view plaincopyprint?
- ( ( CButton *)GetDlgItem(IDC_GG ) )-->SetCheck( TRUE );
CWnd* GetDlgItem(
intnID
) const;
GetDlgItem函式功能:根據控制元件的ID返回一個指向此ID控制元件的指標。
GetDlgItem引數含義:nID表示在一個對話方塊內的子控制元件的ID。
void SetCheck(
intnCheck
);
SetCheck函式功能:設定或者重置Radio 按鈕或者Check 按鈕被選擇與否的狀態。
SetCheck函式引數功能:指定按鈕的狀態,具體巨集值可在VS2010中按下F1檢視。
4. 判斷GroupBox內哪個控制元件已被選擇
Group Box內控制元件的狀態隨時都有可能被更改。那麼如何檢測當前狀態時哪一個按鈕被選擇了呢?在Group Box中,往往不同的按鈕被選擇對應著不同執行的程式段。
可以使用CWnd類中的GetChecedRadioButton方法來判斷Group Box內控制元件的選擇與否。
intGetCheckedRadioButton(
intnIDFirstButton,
intnIDLastButton
);
函式功能:檢測當前被選中radio按鈕的id.
函式引數含義:nIDFirstButton表示Group Box內的第一個控制元件的ID,nIDLastButton表示在Group Box中最後一個按鈕的ID。
函式返回值:返回當前被選中radio的ID值。如果木有被選中的按鈕就返回0.
最簡單的一個應用就是上面提到的組合框中選中了“女”點選確定後判斷選擇的性別:
圖2 選擇
然後彈出選擇了女的標題框( 作為以下訊息框的標題 )
圖3 判斷選擇了女
那麼“主角資訊確定”按鈕對應的訊息響應函式程式碼為:
[cpp] view plaincopyprint?
- void CDMarriageMatchDlg::OnBnClickedConfirm()
- {
- BOOL m_Value;
- if( ( m_Value = UpdateData( TRUE ) ) ){
- UINT nSex;
- nSex = GetCheckedRadioButton( IDC_GG, IDC_MM );
- switch ( nSex ){
- case IDC_GG:
- MessageBox( NULL, _T("GG"), MB_OK );
- break;
- case IDC_MM:
- MessageBox( NULL, _T("MM"), MB_OK );
- break;
- default:
- MessageBox( NULL, _T("GGMM"), MB_OK );
- }
- }
- }
“主角資訊確定”按鈕訊息響應(函式)是通過GetCheckedRadioButton函式來實現。UpdateData(TRUE )是用來判斷訊息是否更新成功,可不管這個語句的含義
Note Over。
PictureControl
一、建立MFC
1 首先建立一個MFC對話方塊應用程式(Dialog-based Application);
2 點選OK -- Next進入下一步,在這裡我們建立一個Dialog-based Application,大部分選項按預設設定就行,不過最下面的“Use Unicodelibraries”最好去掉。如果勾選了這
個選項,程式程式碼就會使用16bit的Unicode字符集來編碼,但是很多函式雖然使用 char* (ASCIIstings) 型別字元,而將字串從 Unicode 轉換到 ASCII 是非常麻煩的。使用 Unicode 在編譯時可能會遇到下列錯誤:
cannot convert parameter 1 from 'CString' to 'const char *'
cannot convert from 'const char [11]' to 'LPCWSTR'這意味著在Unicode和Multi-byte字串的轉換中出現了問題。
故這裡的去掉“Use Unicodelibraries”選項。
二、編寫程式碼
1 開啟工程檔案,進入資源檢視:testPicControl(工程名稱)->testPicControl.rc->Dialog雙擊IDD_TESTPICCONTROL_DIALOG,可以看到一個初始的GUI介面,往裡面新增兩個 Button 和一個 Picture 控制元件
選中單個控制元件、右擊選擇屬性(Properties),可以看到控制元件的ID號,這個號可以自行編輯,例如 Picture 控制元件的 ID 號我設定為 IDC_SHOWIMAGE,這個 ID 號在後面的影象顯示函式中要用到。
2 在專案屬性中載入lib檔案:選單Project -> Properties ->Configuration Properties -> Linker –> Input -> additional dependencies中加入 cxcore200.libcv200.lib highgui200.lib。
3 然後在testPicControl.h 的 #include"resource.h" 程式碼行下面加入如下程式碼:
#include "cv.h"
#include "highgui.h"
#define IMAGE_WIDTH 256
#define IMAGE_HEIGHT 256
#define IMAGE_CHANNELS 3
4 在類檢視皮膚右擊 CtestPicControlDlg,選擇 Add –> Add Variable,新增一個 IplImage* 型別的變數 TheImage;再點選CtestPicControlDlg,在下面視窗的列表中雙擊 OnInitDialog,在“// TODO: Add extra initialization here”下面新增 TheImage 的初始化程式碼:
CvSize ImgSize;
ImgSize.height = IMAGE_HEIGHT;
ImgSize.width = IMAGE_WIDTH;
TheImage = cvCreateImage( ImgSize,IPL_DEPTH_8U, IMAGE_CHANNELS );
5 然後雙擊 OnPaint,在 if(IsIconic())…的 else 裡新增以下程式碼,用來重繪視窗:
CDialog::OnPaint(); // 重繪對話方塊
CDialog::UpdateWindow(); // 更新windows視窗,如果無這步呼叫,圖片顯示還會出現問題 ShowImage( TheImage, IDC_ShowImg); // 重繪圖片函式
接著在CtestPicControlApp 下面的成員列表中雙擊 InitInstance,在兩個“// TODO: Place code here to handle whenthe dialog is…”下面新增:
cvReleaseImage( &dlg.TheImage );
即按下“OK”或“Cancel”時,釋放TheImage佔用的記憶體。
6 寫讀取和處理圖片的功能函式。
回到資源檢視,右鍵按鈕 ReadImage,選擇 Add Event Handler,建立按鈕點選的訊息響應程式:OnBnClickedReadimage,主要的響應操作包括彈出對話方塊選擇圖片檔案、讀入圖片檔案、對圖片統一縮放至256*256的大小、顯示影象,程式碼如下:
// TODO: 在此新增控制元件通知處理程式程式碼
CFileDialog dlg(
TRUE, _T("*.bmp"),NULL,
OFN_FILEMUSTEXIST |OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
_T("image files (*.bmp;*.jpg) |*.bmp; *.jpg | All Files (*.*) |*.*||"), NULL
); // 選項圖片的約定
dlg.m_ofn.lpstrTitle = _T("Open Image"); // 開啟檔案對話方塊的標題名
if( dlg.DoModal() != IDOK ) // 判斷是否獲得圖片
return;
CString mPath = dlg.GetPathName(); // 獲取圖片路徑
IplImage* ipl = cvLoadImage( mPath, 1 ); // 讀取圖片、快取到一個區域性變數 ipl 中
if( !ipl ) // 判斷是否成功讀取圖片
return;
if( TheImage ) // 對上一幅顯示的圖片資料清零
cvZero( TheImage );
ResizeImage( ipl ); // 對讀入的圖片進行縮放,使其寬或高最大值者剛好等於 256,再複製到 TheImage 中
ShowImage( TheImage, IDC_SHOWIMAGE); // 呼叫顯示圖片函式
cvReleaseImage( &ipl ); // 釋放 ipl 佔用的記憶體
7 在上面的程式碼中包含了兩個新的成員函式 ResizeImage 和 ShowImage,前者的作用是對讀入的不同大小的影象進行縮放,再通過設定 ROI 的方式將影象存入 256*256 的 TheImage 中;後者是將影象 TheImage 顯示到圖片顯示控制元件 IDC_ShouImg 視窗的正中部位。為了實現這兩個功能,首先在類檢視皮膚右擊CtestPicControlDlg,選擇 Add –> AddFunction,建立兩個函式:void ShowImage(IplImage* img, UINT ID ) 和 voidResizeImage(IplImage* img)。以下是這兩個函式的實現程式碼:
void CtestPicControlDlg::ShowImage(IplImage*img, UINT ID)// ID 是Picture Control控制元件的ID號
{
CDC* pDC=GetDlgItem(ID)->GetDC();// 獲得顯示控制元件的 DC
HDC hDC=pDC->GetSafeHdc();// 獲取 HDC(裝置控制程式碼) 來進行繪圖操作
CRect rect;
GetDlgItem(ID)->GetClientRect(&rect);
int rw=rect.right-rect.left; // 求出picture control的寬和高
int rh=rect.bottom-rect.top;
int iw=img->width; // 讀取圖片的寬和高
int ih=img->height;
int tx = (int)(rw - iw)/2; // 使圖片的顯示位置正好在控制元件的正中
int ty = (int)(rh - ih)/2;
SetRect( rect, tx, ty, tx+iw, ty+ih );
CvvImage cimg;
cimg.CopyOf(img); // 複製圖片
cimg.DrawToHDC(hDC,&rect);
ReleaseDC(pDC);
}
void CtestPicControlDlg::ResizeImage(IplImage*img)
{
// 讀取圖片的寬和高
int w = img->width;
int h = img->height;
// 找出寬和高中的較大值者
int max = (w > h)? w: h;
// 計算將圖片縮放到TheImage區域所需的比例因子
float scale = (float) ( (float) max / 256.0f );
// 縮放後圖片的寬和高
int nw = (int)( w/scale );
int nh = (int)( h/scale );
// 為了將縮放後的圖片存入 TheImage 的正中部位,需計算圖片在 TheImage 左上角的期望座標值
int tlx = (nw > nh)? 0: (int)(256-nw)/2;
int tly = (nw > nh)? (int)(256-nh)/2: 0;
// 設定 TheImage 的 ROI 區域,用來存入圖片 img
cvSetImageROI( TheImage, cvRect( tlx, tly, nw, nh) );
// 對圖片 img 進行縮放,並存入到 TheImage 中
cvResize( img, TheImage );
// 重置 TheImage 的 ROI 準備讀入下一幅圖片
cvResetImageROI( TheImage );
}
程式碼中所用到的一些MFC相關知識(待續)
1 OnInitDialog();
2 CDialog::OnPaint(); // 重繪對話方塊
CDialog::UpdateWindow(); // 更新windows視窗,如果無這步呼叫,圖片顯示還會出現問題
3 CFileDialog dlg(TRUE, _T("*.bmp"), NULL,
OFN_FILEMUSTEXIST |OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
_T("image files (*.bmp;*.jpg) |*.bmp; *.jpg | All Files (*.*) |*.*||"), NULL
);
dlg.m_ofn.lpstrTitle = _T("Open Image"); // 開啟檔案對話方塊的標題名
if( dlg.DoModal() != IDOK ) // 判斷是否獲得圖片
CString mPath = dlg.GetPathName();
4 CDC* pDC=GetDlgItem(ID)->GetDC();// 獲得顯示控制元件的 DC
HDC hDC=pDC->GetSafeHdc();// 獲取 HDC(裝置控制程式碼) 來進行繪圖操作
CRect rect;
GetDlgItem(ID)->GetClientRect(&rect);
SetRect( rect, tx, ty, tx+iw, ty+ih );
5 CvvImage cimg;
cimg.CopyOf(img); // 複製圖片
cimg.DrawToHDC(hDC,&rect);
6 cvSetImageROI( TheImage, cvRect( tlx,tly, nw, nh) );
cvResize( img, TheImage );
cvResetImageROI( TheImage );
RadioButton
基礎介紹:
radio button通常都是成組使用的,在一組裡面是互斥的。
分組的原則是:
1、首先將RadioButton控制元件定好Tab順序,具體方法:工具欄“格式”—>“Tab鍵順序”選項選中,然後按照預定的順序依次點選對話方塊上面的RadioButton按鈕,Tab鍵順序設定完成。
2、按照上面的Tab鍵順序進行分組,然後設定每組第一個RadioButton的Group屬性為TRUE,分組完成,即從當前設定Group屬性為TRUE的RadioButton開始直到碰到下一個選上Group屬性的RadioButton的前一個RadioButton為一個組。
3、為單選控制元件定義Control變數或Value變數,每組只能定義一個,通過設定值來確定哪一個RadioButton被選中,其中-1表示該組均不被選中,0表示該組第一個RadioButton被選中,1表示第二個……)。
環境:Visual Studio2010
以對話方塊為例,工程名稱為:RadioButtonInstance。此工程中,共建立四組RadioButton,記著設定Tab鍵順序以及為每組第一個RadioButton設定Group屬性。初始化對話方塊為下圖:
為該工程中的RadioButton設定下面若干變數:(為單選控制元件定義Control變數或Value變數,每組只能定義一個)
BOOL m_Radio1;//對應於組 1 1
BOOLm_Radio3; //對應於組 2 1
BOOLm_Radio7; //對應於組 3 1
BOOLm_Radio9; //對應於組 4 1
CButtonm_RBtGroup1; //對應於組 11
CButton m_RBtGroup2; //對應於組 2 1
CButtonm_RBtGroup3; //對應於組 3 1
CButtonm_RBtGroup4; //對應於組 4 1
新增變數
方法一:利用類嚮導方法新增變數(略)
方法二:直接程式設計如下
RadioButtonInstanceDlg.h檔案中:
程式碼部分如下
classCRadioButtonInstanceDlg : public CDialogEx
{
// 構造
public:
CRadioButtonInstanceDlg(CWnd*pParent = NULL); // 標準建構函式
// 對話方塊資料
enum{ IDD = IDD_RADIOBUTTONINSTANCE_DIALOG };
protected:
virtualvoid DoDataExchange(CDataExchange*pDX); // DDX/DDV 支援
// 實現
protected:
HICONm_hIcon;
// 生成的訊息對映函式
virtualBOOL OnInitDialog();
afx_msgvoid OnSysCommand(UINT nID, LPARAM lParam);
afx_msgvoid OnPaint();
afx_msgHCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
BOOL m_Radio1;
BOOLm_Radio3;
BOOLm_Radio7;
BOOLm_Radio9;
CButtonm_RBtGroup1;
CButtonm_RBtGroup2;
CButtonm_RBtGroup3;
CButtonm_RBtGroup4;
};
RadioButtonInstanceDlg.cpp檔案中:
voidCRadioButtonInstanceDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Radio(pDX, IDC_RADIO1, m_Radio1);
DDX_Radio(pDX,IDC_RADIO3, m_Radio3);
DDX_Radio(pDX,IDC_RADIO7, m_Radio7);
DDX_Radio(pDX,IDC_RADIO9, m_Radio9);
DDX_Control(pDX,IDC_RADIO1, m_RBtGroup1);
DDX_Control(pDX,IDC_RADIO3, m_RBtGroup2);
DDX_Control(pDX,IDC_RADIO7, m_RBtGroup3);
DDX_Control(pDX,IDC_RADIO9, m_RBtGroup4);
}
問題一:如何更改RadioButton預設值???
方法1
在定義控制元件變數時,預設變數初值為-1,表示此組的任何RadioButton均不被選中,如果需要改變初始預設按鈕的設定情況,只需要在對話方塊的建構函式中把變數初值設為相應的變數值即可。下面附程式碼和效果圖
例如 建構函式:
CRadioButtonInstanceDlg::CRadioButtonInstanceDlg(CWnd* pParent )
:CDialogEx(CRadioButtonInstanceDlg::IDD, pParent)
{
m_hIcon= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//設定RadioButton初始預設值。如果此處不設定,那麼預設值均為-1,即任何一個RadioButton均不被選中
m_Radio1=-1;
m_Radio3=3;
m_Radio7=1;
m_Radio9=0;
}
效果圖如下:
方法2
只需要在對話方塊的OnInitDialog()方法中新增下面程式碼中綠色的部分即可。
BOOLCRadioButtonInstanceDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關於...”選單項新增到系統選單中。
//IDM_ABOUTBOX 必須在系統命令範圍內。
ASSERT((IDM_ABOUTBOX& 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX< 0xF000);
CMenu*pSysMenu = GetSystemMenu(FALSE);
if(pSysMenu != NULL)
{
BOOLbNameValid;
CStringstrAboutMenu;
bNameValid= strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if(!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX, strAboutMenu);
}
}
// 設定此對話方塊的圖示。當應用程式主視窗不是對話方塊時,框架將自動
// 執行此操作
SetIcon(m_hIcon,TRUE); // 設定大圖示
SetIcon(m_hIcon,FALSE); // 設定小圖示
//TODO: 在此新增額外的初始化程式碼
//此種方法可以為任何一個RadioButton設定其“是否check”狀態,未指定的均為不選上狀態
((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);//選上
((CButton*)GetDlgItem(IDC_RADIO2))->SetCheck(FALSE);// 不選上
((CButton*)GetDlgItem(IDC_RADIO4))->SetCheck(TRUE);//選上
((CButton*)GetDlgItem(IDC_RADIO8))->SetCheck(TRUE);//選上
((CButton*)GetDlgItem(IDC_RADIO9))->SetCheck(TRUE);//選上
returnTRUE; // 除非將焦點設定到控制元件,否則返回 TRUE
}
效果圖如下:
方法3
單選控制元件每組只能定義個Control變數或Value變數。首先為每一組RadioButton關聯一個Control變數,名字分別為m_RBtGroup1、m_RBtGroup2、m_RBtGroup3、m_RBtGroup4。然後設定RadioButton初始狀態。
程式碼如下:
BOOLCRadioButtonInstanceDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關於...”選單項新增到系統選單中。
//IDM_ABOUTBOX 必須在系統命令範圍內。
ASSERT((IDM_ABOUTBOX& 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX< 0xF000);
CMenu*pSysMenu = GetSystemMenu(FALSE);
if(pSysMenu != NULL)
{
BOOLbNameValid;
CStringstrAboutMenu;
bNameValid= strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if(!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX, strAboutMenu);
}
}
// 設定此對話方塊的圖示。當應用程式主視窗不是對話方塊時,框架將自動
// 執行此操作
SetIcon(m_hIcon,TRUE); // 設定大圖示
SetIcon(m_hIcon,FALSE); // 設定小圖示
//TODO: 在此新增額外的初始化程式碼
// //此種方法只能為每一組的第一個RadioButton設定其“是否check”狀態
m_RBtGroup1.SetCheck(FALSE);
m_RBtGroup2.SetCheck(TRUE);
m_RBtGroup3.SetCheck(TRUE);
m_RBtGroup4.SetCheck(TRUE);
returnTRUE; // 除非將焦點設定到控制元件,否則返回 TRUE
}
效果圖如下:
問題二:如何獲取RadioButton當前狀態???
獲取RadioButton是否選中的狀態方法如下:
方法一:可以使用GetCheck()獲取狀態。
例如:
((CButton *)GetDlgItem(IDC_RADIO2))->GetCheck();//返回1表示選上,0表示沒選上
方法二:獲取狀態很簡單,UpdateData(TRUE)後判斷m_nRadio1的值即可。
例如:
UpdateData(TRUE);
CString m_R1;
m_R1.Format(_T("thevalue of m_Radio1 is %d"),m_Radio1);
AfxMessageBox(m_R1);
可以根據需要為RadioButton新增滑鼠單擊事件
問題三:如何為RadioButton新增單擊訊息函式???
方法一:雙擊RadioButton按鈕,進入訊息函式,然後新增相應的程式碼。
方法二:用ClassWizard生成各單選按鈕的單擊訊息函式,然後新增相應的程式碼。
例如:
voidCRadioButtonInstanceDlg::OnBnClickedRadio1()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio1=0;//選中此組的第一個RadioButton
CStringm_R1;
m_R1.Format(_T("thevalue of m_Radio1 is %d"),m_Radio1);
AfxMessageBox(m_R1);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio2()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio1=1;//選中此組的第二個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio3()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio3=0;//選中此組的第一個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio4()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio3=1;//選中此組的第二個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio5()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio3=2;//選中此組的第三個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio6()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio3=3;//選中此組的第四個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio7()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio7=0;//選中此組的第一個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio8()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio7=1;//選中此組的第二個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio9()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio9=0;//選中此組的第一個RadioButton
UpdateData(FALSE);
}
voidCRadioButtonInstanceDlg::OnBnClickedRadio10()
{
//TODO: 在此新增控制元件通知處理程式程式碼
m_Radio9=1;//選中此組的第二個RadioButton
UpdateData(FALSE);
}
其實MFC的單選控制元件radio button是可以通過關聯成員變數來操控的,但是由於使用類嚮導有些程式碼是自動生成的,有時會出現莫名的錯誤。當然如果對MFC的機制很清楚,可以手動寫程式碼關聯。現在個人比較傾向於使用Cwnd的成員函式來操控單選控制元件。
一、設定Radio button控制元件選中不選中
IDC_RADIO1為控制元件的ID,如果需要設定IDC_RADIO1控制預設為選擇或者不選中就需要在OnInitDialog()函式呼叫下面的函式。
((CButton *)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);//選上
((CButton *)GetDlgItem(IDC_RADIO1))->SetCheck(FALSE);//不選上
二、Radio button控制元件分組
每組的第一個單選按鈕設定屬性Group設定為true,從第1個Group屬性為true的Radio button控制元件到下一個group屬性為true的單選按鈕的前一個單選按鈕為一組(按照Tab順序)。每一組可以設定一個成員變數與之關聯。
每組的第一個單選按鈕設定屬性:Group,Tabstop,Auto;其餘按鈕設定屬性Tabstop,Auto。如:
Radio1、Radio2、Radio3為一組,Radio4、Radio5為一組
設定Radio1屬性:Group,Tabstop,Auto
設定Radio2屬性:Tabstop,Auto
設定Radio3屬性:Tabstop,Auto
設定Radio4屬性:Group,Tabstop,Auto
設定Radio5屬性:Tabstop,Auto
三、用CWnd成員函式同時設定組和預設選中按鈕
使用CWnd成員函式CheckRadioButton既可以設定組也可以同時設定預設選中項。
void CheckRadioButton( int nIDFirstButton, intnIDLastButton, intnIDCheckButton )
引數:
nIDFirstButton 指定組中第一個單選按鈕的整數識別符號。
nIDLastButton 指定組中最後一個單選按鈕的整數識別符號。
nIDCheckButton 指定了要選中的單選按鈕的整數識別符號。
說明:
從一組按鈕中選擇(加入檢查標記)一個單選按鈕並清除(清除檢查標記)同組中其它單選按鈕。CheckRadioButton函式向指定的單選按鈕傳送一條BM_SETCHECK訊息。
四、獲取單選按鈕狀態
呼叫類CWnd的成員函式GetCheckedRadioButton可以獲取Radio button的狀態
int GetCheckedRadioButton( int nIDFirstButton, intnIDLastButton )
第一個引數nIDFirstButton是同一組中的第一個單選鈕控制元件的ID
第二個引數nIDLastButton是同一組中最後一個單選鈕控制元件的ID
成員函式GetCheckedRadioButton返回指定組中第一個所選中的單選鈕(在正常情況下僅應當有一個單鈕被選中)的ID,如果沒有按鈕被選中,則返回0。這裡需要注意的是,成員函式GetCheckedRadioButton被沒有要求兩個引數nIDFirstButton和nIDLastButton所指定的控制元件一定位於同一組中。
若干個單選鈕是否屬於同一組是以其Tab順序來排定的,而GetCheckedRadioButton函式是以ID順序來檢查按鈕的選定狀態的。因此,如果傳遞給函式GetCheckedRadioButton的第一個引數的值大於第二個引數的值時,其返回值總是為0,而事實上,由這兩個引數指定的單選鈕的TAB順序可能恰恰相反。因此,一般情況下我們應該儘量保證同一組單選鈕的資源ID是連續遞增的。通常這些資源ID是在標頭檔案Resource.h中定義的。如果你同一組的單選鈕不是一次建立的,那麼它們的資源ID可能不是連續遞增的,甚至可能是相反的。這時我們可以手動的修改資源標頭檔案中的巨集定義,以保證如GetCheckedRadioButton之類的成員函式得到正確的結果。
同時,這也說明一點,即使用GetCheck一個一個控制元件的檢查各單選鈕的選中狀態要安全得多。
int i_check = ((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck();//獲取IDC_RADIO1控制元件選擇狀態
返回值(i_check的值):
0 按鈕處於未選中狀態
1 按鈕處於選中狀態
2 按鈕狀態不定(僅當按鈕風格為BS_3STATE或BS_AUTO3STATE時)如果按鈕是其它風格,則返回0。
五、關聯成員變數
強調一點Radio button控制元件要與int型變數相連前必須對其進行分組。關於Radio button和int型變數相連的方法簡單介紹如下。
對Radio button控制元件 Radio1,Radio2,Radio3 ……分組後,假設與int成員變數 m_nRadio 關聯,如果您是用類嚮導完成關聯,那麼對話方塊的建構函式會把 m_nRadio 值初始化為0.
假設 Radio1,Radio2,Radio3 …… tab鍵順序是由小到大,那麼 m_nRadio 值為1 就是 Radio1 被選中,依次類推。切記控制元件與變數之間值的更新需要利用 UpdateData() 函式。
CheckBox
MFC中核取方塊checkbox控制元件,至少有三種方法對其進行操作,他們是利用Cbutton成員函式GetCheck和SetCheck,第二種是利用CWnd成員函式IsDlgButtonChecked,最後就是把checkbox核取方塊控制元件與BOOL型變數相關聯。
一、用CButton成員函式
MFC中核取方塊CheckBox的基類是CButton。那麼就可以用GetDlgItem來獲取核取方塊的指標,再用Cbutton成員函式GetCheck和SetCheck來獲取和設定選中狀態。
得到核取方塊狀態的函式:
CButton*pBtn = (CButton*)GetDlgItem(IDC_CHECK_MIXI);
intstate = pBtn->GetCheck();
當state == 0時表示該核取方塊沒有被選中;
當state == 1時表示該核取方塊被選中;
當state == 2時表示不確定(applies only if the button hasthe BS_3STATE or BS_AUTO3STATE style);
設定核取方塊狀態的函式:
CButton*pBtn = (CButton*)GetDlgItem(IDC_CHECK_MIXI);
pBtn->SetCheck(1);
SetCheck(1)表示設定核取方塊為“選中”狀態;
SetCheck(0)表示設定核取方塊為“未選中”狀態;
SetCheck(2)設定核取方塊為不確定狀態(This value can be used onlyif the button has the BS_3STATE or BS_AUTO3STATE style.);
二、用CWnd成員函式
CButton是從CWnd繼承來,那麼就可以用IsDlgButtonChecked來獲取和設定check box的狀態。另外MSDN上海說明IsDlgButtonChecked還可以用於單選框Radio button。
UINTIsDlgButtonChecked( int nIDButton ) const;
nIDButton為控制元件ID
函式功能:
該函式可以確定某個按鈕控制是否有選中標誌,或者三態按鈕控制是否為灰色的、選中的、或兩者都不是。
返回值:
使用BS_AUTOCHECKBOX、BS_AUTORADIOBUTTON、BS_AUTO3STATE、BS_CHECKBOX、BS_RADIOBUTION或BS_3STATE樣式建立的按鈕的返回值可以是如下值之一:
BST_CHECKED:表示按鈕被選中。
BST_INDETERMINATE:表示按鈕是灰色的,即為不確定狀態(只有具有BS_3STATE或BS_AUTO3STATE樣式的按鈕才使用該值)。
BST_UNCHECKED:表示該按鈕未選中(unckecked)。如果該按鈕用其他任何樣式,那麼返回值為零。
if (BST_CHECKED == IsDlgButtonChecked( IDC_CHECK1 ) )
{
//IDC_CHECK1是CheckBox控制元件。
//checkbox 被選中執行相關動作
}
三、關聯BOOL型成員變數
核取方塊CheckBox控制元件新增一個控制元件型別的BOOL值變數如:BOOL m_delete;
voidcalcuArea::DoDataExchange (CDataExchange *pDX)
{
//此程式碼利用類嚮導可以自動生成
CAcUiDialog::DoDataExchange(pDX) ;
DDX_Check(pDX,IDC_CHECK1, m_delete);
}
TabControl
1. 新建一個MFC工程,取名xyTabControl,選擇Dialog based,然後Finish。
2. 刪除對話方塊上預設新增的三個控制元件。新增Tab Control控制元件並在Property屬性中設定ID為IDC_TAB1,新增變數m_tabctrl,型別為CTabCtrl。
3. 在對話方塊的初始化函式OnInitDialog裡面新增如下程式碼:
m_tabctrl.InsertItem(0,"memo0"); //新增引數一選項卡
m_tabctrl.InsertItem(1,"memo1"); //新增引數二選項卡
4.在對話方塊資源裡面新增兩個對話方塊資源, ID分別命名為IDD_PARA1,IDD_PARA2。字型為宋體, 字號為9, style為Child, Border為None, 調整高度寬度到適中尺寸。再分別為其新增對應的基於CDialog類CPara1, CPara2。
5. 在CxyTabControlDlg類中新增兩個成員變數m_para1,m_para2, 分別是兩個子對話方塊的例項. 程式碼如下:
CPara2 m_para2;
CPara1 m_para1;
6. 佈置IDD_PARA1和IDD_PARA2對話方塊 如下圖:
7. 在IDD_xyTabControl_DIALOG對話方塊的初始化函式OnInitDialog裡面新增如下程式碼:
//關聯對話方塊,並且將IDC_TABTEST控制元件設為父視窗
m_para1.Create(IDD_PARA1,GetDlgItem(IDC_TAB1));
m_para2.Create(IDD_PARA2,GetDlgItem(IDC_TAB1));
//獲得IDC_TABTEST客戶區大小
CRect rs;
m_tabctrl.GetClientRect(&rs);
//調整子對話方塊在父視窗中的位置
rs.top += 20;
rs.bottom -=20;
rs.left += 1;
rs.right -= 2;
//設定子對話方塊尺寸並移動到指定位置
m_para1.MoveWindow(&rs);
m_para2.MoveWindow(&rs);
//分別設定隱藏和顯示
m_para1.ShowWindow(1);
m_para2.ShowWindow(0);
//設定預設的選項卡
m_tabctrl.SetCurSel(0);
8. 新增Tab Control控制元件的TCN_SELCHANGE事件響應函式OnSelchangeTabtest(NMHDR*
pNMHDR, LRESULT* pResult) ,函式體程式碼如下:
int CurSel =m_tabctrl.GetCurSel();
switch(CurSel)
{
case 0:
m_para1.ShowWindow(true);
m_para2.ShowWindow(false);
break;
case 1:
m_para1.ShowWindow(false);
m_para2.ShowWindow(true);
break;
default:
;
*pResult = 0;
}
9.好了,完成,這個小程式很簡單,效果如下圖:
TreeControl
1. InsertItem 新增節點
引數: 文字,圖示,父節點
返回: HTREEITEM
示例: 新增一系列節點
HTREEITEM hItem= m_Tree.InsertItem("root",NULL,NULL);///root就是節點的標題
int i,j;
for(i=0;i<4;i++)
{
HTREEITEMhSubItem = m_Tree.InsertItem("item",NULL,NULL,hItem);
for(j=0;j<3;j++)
{
m_Tree.InsertItem("subitem",NULL,NULL,hSubItem);
}
}
InsertItem函式的第一個引數就是設定他的節點標題
2. ModifyStyle 設定風格
引數: 取消的風格,增加的風格
示例: 在對話方塊初始化時設定風格
BOOLCMfc1Dlg::OnInitDialog(){
//...
m_Tree.ModifyStyle(NULL,TVS_HASBUTTONS| TVS_HASLINES | TVS_LINESATROOT);
}
控制元件風格 |
含義 |
TVS_HASLINES |
在父項與子項間連線以清楚地顯示結構. |
TVS_LINESATROOT |
只在根部畫線. |
TVS_HASBUTTONS |
顯示帶有"+"或"-"的小方框來表示某項能否被展開或已展開. |
TVS_EDITLABELS |
使用者可以編輯表項的標題. |
TVS_SHOWSELALWAYS |
即使控制元件失去輸入焦點,仍顯示出項的選擇狀態. |
TVS_DISABLEDRAGDROP |
不支援拖動操作. |
3. DeleteItem 刪除節點
4. DeleteAllItems 刪除全部節點
5. Expand 展開/收縮節點
引數: 節點HTREEITEM,展開/收縮
示例:
m_Tree.Expand(hItem,TVE_EXPAND);
/////////////////////////////////////////////////////////
6. CTreeCtrl的概述cc++vc
CTreeCtrl在三種不同情況下建立的方式
1、如果要在對話方塊視窗上建立樹形控制元件,你需要在對話方塊類中定義一個CTreeCtrl型別的成員變數。
2、如果樹形控制元件是一個子視窗,你可以使用CTreeCtrl::Create()來構建樹形空間物件。
3、如果你使用了CViewTree物件,那麼你需要使用CViewTree::GetTreeCtrl()獲得對樹形控制元件的引用
如果你想在你的控制元件中使用影象,需要通過CImageList::SetImageList()來設定一個影象列表。你也可以通過使用CTreeCtrl::SetIndent()設定子項縮排的寬度。一個最好的使用這些函式的時機是在CDialog::OnInitDialog()或CView::OnInitalUpdate()中。
可以通過呼叫CTreeCtrl::InsertItem()向樹形控制元件中新增資料,每次新增一個資料項。這個函式將返回一個指向這個資料項的控制程式碼,這個控制程式碼在後面會使用到,例如在後面新增這個資料項的子資料項的時候。一個最好的使用這個函式的時機是在CDialog::OnInitDialog()或CView::OnInitalUpdate()中。
當使用者和樹形控制元件互動時,它將會傳送不同的通知訊息。你可以通過在控制元件視窗的訊息對映表中新增ON_NOTIFY_REFLECT巨集或在控制元件視窗的父視窗的訊息對映表中新增ON_NOTIFY來指定一個函式處理每個你想處理的訊息。
通過呼叫樹形控制元件不同的Set成員函式去設定它的值,包括子資料項縮排寬度、文字、影象或者和控制元件相關的資料。
使用不同的Get成員函式來檢查控制元件的內容。你也可以用允許你接受指定資料項的父項、子項和兄弟項的函式得到樹形控制元件的內容。你甚至可以儲存某一結點的子項。
當你在處理這個控制元件時,確定它確實被銷燬。如果樹形控制元件是在一個對話方塊中或檢視中,它和CTreeCtrl物件會自動被銷燬,如果不是,你需要保證銷燬控制元件和CTreeCtrl物件
//////////////////////////////////////////////////////////
7. CTreeCtrl的一些操作
樹形控制元件可以用於樹形的結構,其中有一個根接點(Root)然後下面有許多子結點,而每個子結點上有允許有一個或多個或沒有子結點。MFC中使用CTreeCtrl類來封裝樹形控制元件的各種操作。通過呼叫
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );建立一個視窗,dwStyle中可以使用以下一些樹形控制元件的專用風格:
TVS_HASLINES 在父/子結點之間繪製連線
TVS_LINESATROOT 在根/子結點之間繪製連線
TVS_HASBUTTONS 在每一個結點前新增一個按鈕,用於表示當前結點是否已被展開
TVS_EDITLABELS 結點的顯示字元可以被編輯
TVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點
TVS_DISABLEDRAGDROP 不允許Drag/Drop
TVS_NOTOOLTIPS 不使用ToolTip顯示結點的顯示字元
在樹形控制元件中每一個結點都有一個控制程式碼(HTREEITEM),同時新增結點時必須提供的引數是該結點的父結點控制程式碼,(其中根Root結點只有一個,既不可以新增也不可以刪除)利用
HTREEITEMInsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEMhInsertAfter = TVI_LAST );可以新增一個結點,pszItem為顯示的字元,hParent代表父結點的控制程式碼,當前新增的結點會排在hInsertAfter表示的結點的後面,返回值為當前建立的結點的控制程式碼。下面的程式碼會建立一個如下形式的樹形結構:
+--- Parent1
+---Child1_1
+---Child1_2
+---Child1_3
+--- Parent2
+--- Parent3
/*假設m_tree為一個CTreeCtrl物件,而且該視窗已經建立*/
HTREEITEMhItem,hSubItem;
hItem =m_tree.InsertItem("Parent1",TVI_ROOT);
在根結點上新增Parent1
hSubItem =m_tree.InsertItem("Child1_1",hItem);
//在Parent1上新增一個子結點
hSubItem =m_tree.InsertItem("Child1_2",hItem,hSubItem);
//在Parent1上新增一個子結點,排在Child1_1後面
hSubItem =m_tree.InsertItem("Child1_3",hItem,hSubItem);
hItem =m_tree.InsertItem("Parent2",TVI_ROOT,hItem);
hItem =m_tree.InsertItem("Parent3",TVI_ROOT,hItem);
如果你希望在每個結點前新增一個小圖示,就必需先呼叫CImageList*SetImageList( CImageList * pImageList, int nImageListType );指明當前所使用的ImageList,nImageListType為TVSIL_NORMAL。在呼叫完成後控制元件中使用圖片以設定的ImageList中圖片為準。然後呼叫
HTREEITEMInsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent= TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);新增結點,nImage為結點沒被選中時所使用圖片序號,nSelectedImage為結點被選中時所使用圖片序號。下面的程式碼演示了ImageList的設定。
/*m_list 為CImageList物件
IDB_TREE 為16*(16*4)的點陣圖,每個圖片為16*16共4個圖示*/
m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem("Parent1",0,1);
//新增,選中時顯示圖示1,未選中時顯示圖示0
此外CTreeCtrl還提供了一些函式用於得到/修改控制元件的狀態。
HTREEITEMGetSelectedItem( );將返回當前選中的結點的控制程式碼。BOOL SelectItem(HTREEITEM hItem );將選中指明結點。
BOOLGetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) /BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用於得到/修改某結點所使用圖示索引。
CStringGetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTRlpszItem );用於得到/修改某一結點的顯示字元。
BOOL DeleteItem(HTREEITEM hItem );用於刪除某一結點,BOOL DeleteAllItems();將刪除所有結點。
此外如果想遍歷樹可以使用下面的函式:
HTREEITEMGetRootItem( );得到根結點。
HTREEITEMGetChildItem( HTREEITEM hItem );得到子結點。
HTREEITEMGetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結點的上/下一個兄弟結點。
HTREEITEMGetParentItem( HTREEITEM hItem );得到父結點。
樹形控制元件的訊息對映使用ON_NOTIFY巨集,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode為通知程式碼,id為產生該訊息的視窗ID,memberFxn為處理函式,函式的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT*pResult),其中pNMHDR為一資料結構,在具體使用時需要轉換成其他型別的結構。對於樹形控制元件可能取值和對應的資料結構為:
TVN_SELCHANGED 在所選中的結點發生改變後傳送,所用結構:NMTREEVIEW
TVN_ITEMEXPANDED 在某結點被展開後傳送,所用結構:NMTREEVIEW
TVN_BEGINLABELEDIT 在開始編輯結點字元時傳送,所用結構:NMTVDISPINFO
TVN_ENDLABELEDIT 在結束編輯結點字元時傳送,所用結構:NMTVDISPINFO
TVN_GETDISPINFO 在需要得到某結點資訊時傳送,(如得到結點的顯示字元)所用結構:NMTVDISPINFO
關於ON_NOTIFY有很多內容,將在以後的內容中進行詳細講解。
關於動態提供結點所顯示的字元:首先你在新增結點時需要指明lpszItem引數為:LPSTR_TEXTCALLBACK。在控制元件顯示該結點時會通過傳送TVN_GETDISPINFO來取得所需要的字元,在處理該訊息時先將引數pNMHDR轉換為LPNMTVDISPINFO,然後填充其中item.pszText。但是我們通過什麼來知道該結點所對應的資訊呢,我的做法是在新增結點後設定其lParam引數,然後在提供資訊時利用該引數來查詢所對應的資訊。下面的程式碼說明了這種方法:
char szOut[8][3]={"No.1","No.2","No.3"};
//新增結點
HTREEITEM hItem= m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem,0 );
hItem =m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem,1 );
//處理訊息
voidCParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO*pTVDI = (TV_DISPINFO*)pNMHDR;
pTVDI->item.pszText=szOut[pTVDI->item.lParam];
//通過lParam得到需要顯示的字元在陣列中的位置
*pResult = 0;
}
關於編輯結點的顯示字元:首先需要設定樹形控制元件的TVS_EDITLABELS風格,在開始編輯時該控制元件將會傳送TVN_BEGINLABELEDIT,你可以通過在處理函式中返回TRUE來取消接下來的編輯,在編輯完成後會傳送TVN_ENDLABELEDIT,在處理該訊息時需要將引數pNMHDR轉換為LPNMTVDISPINFO,然後通過其中的item.pszText得到編輯後的字元,並重置顯示字元。如果編輯在中途中取消該變數為NULL。下面的程式碼說明如何處理這些訊息:
//處理訊息 TVN_BEGINLABELEDIT
voidCParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO*pTVDI = (TV_DISPINFO*)pNMHDR;
if(pTVDI->item.lParam==0);//判斷是否取消該操作
*pResult= 1;
else
*pResult= 0;
}
//處理訊息 TVN_BEGINLABELEDIT
voidCParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO*pTVDI = (TV_DISPINFO*)pNMHDR;
if(pTVDI->item.pszText==NULL);//判斷是否已經取消取消編輯
m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText);
//重置顯示字元
*pResult = 0;
}
上面講述的方法所進行的訊息對映必須在父視窗中進行(同樣WM_NOTIFY的所有訊息都需要在父視窗中處理)。
/************************示例程式碼*************************/
image.Create(IDB_BITMAP,16,10,RGB(255,0,255));//CImageListimage;
m_Tree.SetImageList(&image,TVSIL_NORMAL);
//CTreeCtrlm_Tree;
HTREEITEMhItem=m_Tree.InsertItem(_TEXT("中國"),0,1,TVI_ROOT);
HTREEITEMhSub=m_Tree.InsertItem(_TEXT("河北"),0,2,hItem);
m_Tree.InsertItem(_TEXT("石家莊"),2,3,hSub);
m_Tree.InsertItem(_TEXT("唐山"),2,4,hSub);
m_Tree.InsertItem(_TEXT("邢臺"),2,5,hSub);
hSub=m_Tree.InsertItem(_TEXT("河南"),0,3,hItem);
m_Tree.InsertItem(_TEXT("少林寺"),3,4,hSub);
m_Tree.InsertItem(_TEXT("嵩山"),3,5,hSub);
hSub=m_Tree.InsertItem(_TEXT("湖北"),0,4,hItem);
m_Tree.InsertItem(_TEXT("武漢"),4,6,hSub);
hSub=m_Tree.InsertItem(_TEXT("湖南"),0,5,hItem);
m_Tree.InsertItem(_TEXT("經濟改革"),5,6,hSub);
hSub=m_Tree.InsertItem(_TEXT("山西"),0,6,hItem);
m_Tree.InsertItem(_TEXT("板面"),6,7,hSub);
8.成員函式
CTreeCtrl類提供了大量的成員函式.對於常用的函式,這裡結合實際應用的需要,介紹如下:
向樹形檢視中插入新的表項.首先應提供一個TV_INSERTSTRUCT結構並在該結構中對插入項進行描述.如果要在樹形檢視中顯示圖象,則應該先建立一個CImageList物件並使該物件包含一個點陣圖序列,然後呼叫SetImageList為樹形檢視設定點陣圖序列.然後呼叫InsertItem函式把新項插入到樹形檢視中.函式的宣告為
CImageList* SetImageList( CImageList * pImageList, intnImageListType );
引數pImageList指向一個CImageList物件,引數nImageListType一般應為TVSIL_NORMAL.
HTREEITEM InsertItem( LPTV_INSERTSTRUCT lpInsertStruct );
引數lpInsertStruct指向一個TV_INSERTSTRUCT結構.函式返回新插入項的控制程式碼.
用DeleteItem來刪除指定項,用DeleteAllItems刪除所有項.函式的宣告為
BOOL DeleteItem( HTREEITEM hItem );
BOOL DeleteAllItems( );
操作成功則函式返回TRUE,否則返回FALSE.
樹形檢視控制元件會根據使用者的輸入自動展開或摺疊子項.但有時需要在程式中展開或摺疊指定項,則應該呼叫Expand,該函式的宣告為
BOOL Expand( HTREEITEM hItem, UINT nCode );
引數hItem指定了要展開或摺疊的項.引數nCode是一個標誌,指定了函式應執行的操作,它可以是TVE_COLLAPSE(摺疊)、TVE_COLLAPSERESET(摺疊並移走所有的子項)、TVE_EXPAND(展開)或TVE_TOGGLE(在展開和摺疊狀態之間翻轉).
要查詢或設定選擇項,應呼叫GetSelectedItem或SelectItem.函式的宣告為
HTREEITEM GetSelectedItem( );
BOOL SelectItem( HTREEITEM hItem );
要對指定的項查詢或設定,可呼叫GetItem和SetItem.用這兩個功能強大的函式,幾乎可以查詢和設定項的所有屬性,包括表項的正文、影象及選擇狀態.函式的宣告為
BOOL GetItem( TV_ITEM* pItem );
BOOL SetItem( TV_ITEM* pItem );
引數pItem是指向TV_ITEM結構的指標,函式是通過該結構來查詢或設定指定項的,在呼叫函式前應該使該結構的hItem成員有效以指定表項.CTreeCtrl還提供了一系列函式可完成GetItem和SetItem的部分功能,其中GetItemState、GetItemText、GetItemData、GetItemImage和ItemHasChildren函式用於查詢,SetItemState、SetItemText、SetItemData和SetItemImage函式用於設定.
在使用樹形檢視控制元件時,一個經常遇到的問題是對於一個已知表項,如何找到與該項有某種關係的項,例如,父項、子項、兄弟項、下一個或前一個可見的項.利用功能強大的GetNextItem函式,可以解決這個問題.該函式也可以用來搜尋具有某種狀態的表項.GetNextItem在遍歷樹形檢視時是很有用的,它的宣告為
HTREEITEM GetNextItem( HTREEITEM hItem, UINT nCode );
引數hItem指定了一個項.引數nCode是一個標誌,標明瞭與指定項的關係,nCode可以是如表6.27所示的各種標誌.如果找到相關的項,函式返回該項的控制程式碼,否則函式返回NULL.
關係標誌
標誌 |
含義 |
TVGN_CARET |
返回當前的選擇項. |
TVGN_CHILD |
返回指定表項的子項. |
TVGN_DROPHILITE |
返回拖動操作的目標項. |
TVGN_FIRSTVISIBLE |
返回第一個可見項. |
TVGN_NEXT |
返回指定項的下一個兄弟項(Sibling Item). |
TVGN_NEXTVISIBLE |
返回指定項的後一個可見項. |
TVGN_PARENT |
返回指定項的父項. |
TVGN_PREVIOUS |
返回指定項的前一個兄弟項. |
TVGN_PREVIOUSVISIBLE |
返回指定項的前一個可見項. |
TVGN_ROOT |
返回位於最高層(根位置)的第一個表項. |
CTreeCtrl類提供了一系列的成員函式來完成GetNextItem的某一項功能,包括GetRootItem、GetFirstVisibleItem、GetNextVisibleItem、GetPrevVisibleItem、GetChildItem、GetNextSiblingItem、GetPrevSiblingItem、GetParentItem、GetSelectedItem和GetDropHilightItem.
ProgressControl
1.簡單應用
m_progress->GetPos(); //獲取進度條的當前位置
m_progress->GetRange(int min,intmax); //獲取進度條控制元件的範圍的下限和上限
m_progress->OffsetPos(int nPos); //用指定的增量推進進度條控制元件的當前位置,重繪進度條反映新位置
m_progress->SetBkColor(COLORREFclrNew); //設定進度條的背景顏色
m_progress->SerPos(int nPos); //設定進度條控制元件的當前位置,重繪進度條反映新位置
m_progress->SetRange(int min,intmax); //設定進度條控制元件的範圍的下限和上限
m_progress->SetRange32(int min,intmax); //設定進度條控制元件的範圍的下限和上限
m_progress->SetStep(int nStep); //指定進度條控制元件的步進增量
m_progress->StepIt(); //通過步進增量,推進進度條控制元件的當前位置,重繪進度條反映新位置
應用:
CProgressCtrl *m_progress; //標頭檔案中宣告
在OnInitDialog初始化
{
m_progress = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
m_progress->SetRange(0,1000);
m_progress->SetPos(0);
UINT m_timer =(UINT) SetTimer(1,200,NULL);
}
採用在定時器的訊息處理函式WM_TIMER內新增不斷更新進度條介面的方法
OnTimer (nIDEvent)
{
pos = pos + 50;
if(pos>500)
pos = 0;
m_Progress->SetPos(pos);
}
或者採用在某種迴圈體內新增不斷更新進展條介面的方法
2.實現像xp啟動一樣的不斷滾動的進度條
//當程式執行到一個地方
const int TIMER_ID=1;
SetTimer(TIMER_ID,200,NULL);
//程式繼續執行,執行完某一段
//KillTimer(TIMER_ID);
int m_iProgress;
void CDlgDlg::OnTimer(UINT nIDEvent)
{
CDialog::OnTimer(nIDEvent);
if(m_iProgress<100)
{
m_iProgress+=20;
}
CProgressCtrl *pProgressCtrl =(CProgressCtrl*)this->GetDlgItem(IDC_PROGRESS1);
pProgressCtrl->SetPos(m_iProgress);
if(m_iProgress==100)
{
m_iProgress=0;
}
}
追問:
不行,只能顯示3格進度~
追答:
應該是KillTimer之前,進度條不停地從0到100,你再調一下
Monthcalendar Control
這個控制元件跟Date Time Picker控制元件蠻類似.實際應該是Date Time Picker把它整合進去了,只有當點一下才出來.而
Month control直接顯示在頁面上.當然了它還有其他一些不一樣的設定資訊了.
現在來講下常用的兩個用法:設定當前選中項, 獲取當前選中日期
如果什麼設定也不做預設選中的是當前日期.那怎麼指定選中某個日期呢.
CMonthCalCtrl m_montCtrl;
DDX_Control(pDX, IDC_MONTHCALENDAR1, m_montCtrl);
m_montCtrl.SetCurSel(CTime(2008,8,8,0,0,0,0));//指定選中2008/8/8
獲取當前選中日期
//當在控制元件中選不同的日期時可以用如下訊息來處理
ON_NOTIFY(MCN_SELCHANGE, IDC_MONTHCALENDAR1,OnMcnSelchangeMonthcalendar1)
void CMFC_Ctrl_TimeDlg::OnMcnSelchangeMonthcalendar1(NMHDR*pNMHDR, LRESULT *pResult)
{
LPNMSELCHANGE pSelChange = reinterpret_cast<LPNMSELCHANGE>(pNMHDR);
CTime month;
m_montCtrl.GetCurSel(month); //獲取當前日期資訊
//根據日期資訊做其他操作,比如可以顯示不同的頁面資訊
*pResult = 0;
}
DateTime Picker
使用DateTimePicker控制元件一般是獲取其時間替代手工輸入帶來的不便,而DateTimePicker控制元件既可以獲取日期(2010-03-05)也可以獲取時間(16:27:33),要獲取日期只需要更改控制元件屬性的格式為長日期或短日期,要獲取時間則將格式更改為時間即可!
在新增控制元件變數時,選擇其變數型別為CDateTimeCtrl(類如m_DateCtrl);在程式中定義CTime物件用來儲存獲取的時間,然後可以將其轉換為CString型別;具體實現:
1 CTime time;
2 m_DateCtrl.GetTime(time);
3 CString strTime=time.Format("%Y-%m-%d")
//獲取到的為日期如:2010-03-05
4
5 CTime time;
6 m_DateCtrl.GetTime(time);
7 CString strTime=time.Format("%H:%M:%S")
//獲取到的為時間如:16:27:33
VC2005中DateTimePicker控制元件的使用
11顯示年月日時分秒的當前時間
2 CDateTimeCtrlm_DateItmeCtrl_Time;
3m_DateItmeCtrl_Time.SetFormat(_T("yyyy-MM-dd HH:mm:ss"));
4 CTimeTimeTemp=TimeTemp.GetCurrentTime();
5m_DateItmeCtrl_Time.SetTime(&TimeTemp);
6
7其中HH表示24小時制,hh表示12小時制
8 2如果宣告一個控制元件型別為CTime的變數,那麼時間將顯示1970-01-01
08:00:00.
9
10 3將DateTimePicker控制元件宣告變數型別為COleDateTime
11 COleDateTime轉CString
12 CString strTime;
13 COleDateTime dtTime;
14 strTime =dtTime.Format(_T("%Y-%m-%d%H:%M:%S"));
4 CString轉COleDateTime(因為VS2005時間日期控制元件關聯的Value變數預設是COleDateTime型別)
1 CString strTime =_T("2009-08-1111:22:33");
2 COleVariant VariantTime;
3 VariantTime = strTime;
4 VariantTime.ChangeType(VT_DATE);
5 COleDateTime DataTime = VariantTime;
SetTime時引數需要為指標
1 m_ctrlMachineDeliveryDate.SetTime(&CTime::GetCurrentTime());
//將控制元件顯示當前日期
2 m_ctrlMachineInstallDate.SetTime(&CTime::GetCurrentTime());
3
4
5
6 CTime tDeliveryDate;
7 m_ctrlMachineDeliveryDate.GetTime(tDeliveryDate);
//獲取發貨日期
8 pMachineInfoSet->m_MACHINE_DELIVERYDATE =tDeliveryDate;
9
10
11
12 CTime tDeliveryDate;
13 tDeliveryDate = pMachineInfoSet->m_MACHINE_DELIVERYDATE;
//獲取記錄中的日期
14 m_ctrlMachineDeliveryDate.SetTime(&tDeliveryDate);
//將記錄中的日期賦值到DateTime控制元件中顯示
// 設定時間日期控制元件允許選擇的範圍
1 CTime tCurrentTime= CTime::GetCurrentTime();
2 CTimeSpan timespanOneMonth(30,0,0,0);
//這裡設定為當前日期推後30天
3 CTime tEndTime = tCurrentTime +timespanOneMonth;
4 m_ctrlADTipsDaysDate.SetRange(&tCurrentTime,&tEndTime);
5 /*
6 m_dtcTm:這個是DATE TIME PICKER控制元件變數
7 CTimebegin_tm(1970,1,1,8,0,0),end_tm(2038,1,19,3,14,7);
8 m_dtcTm.SetRange(&begin_tm,&end_tm);
9 m_tmClock=CTime::GetCurrentTime();//設定初始值為當前時間
10 m_dtcTm.SetTime(&m_tmClock);
11 //m_dtcTm.SetFormat("yyyy-MM-dd HH'時'mm'分'"); //設定字串格式
12 m_dtcTm.SetFormat("yyyy-MM-ddHH:mm:ss");
13 */
Date Time Picker控制元件的使用例子
http://blog.163.com/zy_tommy/blog/static/86926777201032191719177/
今天要做一個獲取時間,然後可以分別修改年月日,小時,分鐘,秒的一個程式...
雖然用COleDateTime類可以實現。但是我還是特別想用DateTimePicker控制元件,因為用這個介面問題不用考慮,而且可以彈出對話方塊,進行修改....
關鍵問題是怎麼把該控制元件裡的數字進行儲存,而且修改後,下次開啟能顯示新的時間,日期呢?
我是要在手持儀表裡實現該功能,開發環境是EVC....
經驗總結:
MFC中的一些控制元件總是用起來不怎麼爽,下面我結合自己的經驗與大家分享一下Date Time Picker控制元件的操作。
首先,不管怎麼樣,控制元件是要往視窗上拖的,所以你得準備一個對話方塊。
然後,把Date Time Picker拖放到對話方塊上。
接下來設定它的屬性,右鍵單擊該控制元件,彈出屬性對話方塊。
在General屬性頁中,給它取個名字,其它預設就可以了。
在Styles屬性頁中,Format下拉框中,選擇Long Date。至於為什麼要選這個,根據個人需要了,它的格式是:****年**月**日;而Short
Date的格式如:2007-6-7。
Right Align是預設的對齊屬性,我們不管它。
另外鉤上Show None和Use Spin Control屬性。Show None屬性,用於將日期值設為空的操作,也就是我們以後從空間得到的是空值。Use Spin Control屬性,就是給你提供一個調整時間的按鈕,一個上(增加),一個下(減少)。
至於Allow Edit,我的看法是有了之前的設定,這個可以不要。因為它可以編輯整行,這不是我所需要的,最好只允許使用者對數字操作。
第三個屬性頁,如果你有興趣,可以試試,是一些擴充套件的屬性。
接下來,我們需要給該控制元件繫結一個變數,如m_leveldate,注意,該變數的種類(category)選(Control),變數型別選CDateTimeCtrl。
假如SQL資料庫裡有一個datetime型別的欄位,我們要把它顯示到控制元件上。
首先,把該欄位讀出來,儲存在CString strDate變數中。
接下來的問題就是如何將這個字串顯示到 Date TimePicker中了?我們可以用一個函式來解決這個問題。設為這個函式voidSetLevelDate(CString strdatetime),先在標頭檔案中宣告,再在CPP檔案中實現。函式體如下:
{
CString year,month,day;
year=strdatetime.Left(4);
strdatetime=strdatetime.Right(strdatetime.GetLength()-strdatetime.Find("-")-1);
month=strdatetime.Left(strdatetime.Find ("-"));
day=strdatetime.Right(strdatetime.GetLength()-strdatetime.Find("-")-1);
inty=atoi(year); //將字串轉換為整形
int m=atoi(month);
int d=atoi(day);
CTime time(y,m,d,0,0,0);
m_leveldate.SetTime(&time);
}
這裡需要注意的是,SQL資料庫裡的datetime型別的格式如:1900-01-0100:00:000,而我們只要年月日,所以得分別提取出來。
另外,MFC中對時間的處理,我們需要用到幾個類,如:CTime和COleDateTime,具體怎麼用可以到MSDN中查。
顯示實現了,那如何將Date Time Picker中的日期讀到字串中呢?我們同樣利用一個函式:CStringGetLevelDate(int nID),注意這個函式是有引數,並有返回值的。引數的作用是,傳遞該控制元件的ID,也就是命名,如上面圖中的IDC_19_LEVELDATE。函式體實現如下:
{
CDateTimeCtrl *pWndTemp = (CDateTimeCtrl*)GetDlgItem(nID);
CTime tempTime;
pWndTemp->GetTime(tempTime);
CString strTemp1 =tempTime.Format("%Y-%m-%d");
return strTemp1;
}
同樣,函式返回值的格式如:2007-6-7,這樣可以方便的插入資料庫中。
那麼如何使得該控制元件傳遞空值呢?我們用這樣一個函式voidSetLevelDateNull(),函式實現如下:
{
COleDateTimeletimeTime = COleDateTime::GetCurrentTime();
m_leveldate.SetTime(oletimeTime); //設定為當前時間
oletimeTime.SetStatus(COleDateTime::null);//核取方塊不打勾
m_leveldate.SetTime(oletimeTime); //使核取方塊不打勾生效
}
使用該函式,可以使核取方塊不打鉤,後面的日期為灰色不可更改的。這時,如果我們用GetLevelDate(intnID)的話,將返回一個空字串。
那麼如何檢測控制元件是否為空呢?可以用這個函式intCheckLevelDateNull(),該函式用來得到控制元件的狀態,返回列舉型別的值,valid = 0,invalid = 1,NULL=2。當然我們也可以把函式的返回值型別設為整形。函式實現如下:
{
COleDateTimeoletimeTime;
m_leveldate.GetTime(oletimeTime);
COleDateTime::DateTimeStatus status = oletimeTime.GetStatus();
return status;
}
SliderControl
1.控制元件風格
控制元件風格 |
含義 |
TBS_HORZ |
指定一個水平軌道條.該風格是預設的. |
TBS_VERT |
指定一個垂直軌道條. |
TBS_AUTOTICKS |
在範圍設定後,自動為軌道條加上刻度. |
TBS_NOTICKS |
軌道條無刻度. |
TBS_BOTTOM |
在水平軌道條的底部顯示刻度,可與TBS_TOP一起使用. |
TBS_TOP |
在水平軌道條的頂部顯示刻度,可與TBS_BOTTOM一起使用. |
TBS_RIGHT |
在垂直軌道條的右側顯示刻度,可與TBS_LEFT一起使用. |
TBS_LEFT |
在垂直軌道條的左側顯示刻度,可與TBS_RIGHT一起使用. |
TBS_BOTH |
在軌道條的上下部或左右兩側都顯示刻度. |
TBS_ENABLESELRANGE |
在軌道條中顯示一個選擇範圍. |
除上表的風格外,一般還要為軌道條指定WS_CHILD和WS_VISIBLE風格.要建立一個具有刻度的水平軌道條,一般應指定風格為WS_CHILD|WS_VISIBLE|TBS_HORZ| TBS_AUTOTICKS.對於用對話方塊模板建立的軌道條控制元件,可以在控制元件的屬性對話方塊中指定上表中列出的控制元件風格。例如,在屬性對話方塊中選擇Autoticks,相當於指定了TBS_AUTOTICKS風格.
2.成員函式
用GetRange和SetRange來查詢和設定軌道條的範圍,預設的範圍是0-100.函式的宣告為
void GetRange( int& nMin, int& nMax ) const;
void SetRange( int nMin, int nMax, BOOL bRedraw = FALSE );
引數nMin和nMax分別是最小和最大值,引數bRedraw為TRUE時將重繪控制元件.
用GetPos和SetPos來查詢和設定軌道條的當前值.函式的宣告為
int GetPos( ) const;
void SetPos( int nPos );
用GetLineSize和SetLineSize來查詢和設定在按一下左箭頭鍵或右箭頭鍵時滑尺的移動量,該移動量的預設值是1個單位.函式的宣告為
int GetLineSize( ) const;
int SetLineSize( int nSize );
用GetPageSize和SetPageSize來查詢和設定滑尺的塊移動量,塊移動量是指當按下PgUp或PgDown鍵時滑尺的移動量.函式的宣告為
int GetPageSize( ) const;
int SetPageSize( int nSize );
用SetTicFreq設定軌道條的刻度的頻度.預設的頻度是每個單位都有一個刻度,在範圍較大時,為了使刻度不至於過密,需要呼叫該函式設定一個合理的頻度.函式的宣告為
void SetTicFreq( int nFreq );
引數nFreq說明了兩個刻度之間的間隔.
用函式SetTic來在指定位置設定刻度.Windows自動顯示的刻度是均勻的,利用該函式可以人為設定不均勻的刻度,該函式的宣告為
BOOL SetTic( int nTic );
用函式ClearTics來清除所有的刻度.該函式的宣告為
void ClearTics( BOOL bRedraw = FALSE );
所有的控制元件的建立基本都是同一套道路;
第一步:.h中建立一個CSliderCtrl 類的物件;
CSliderCtrl m_ctrlSlider;
第二步:.cpp中的void CMyDlg::DoDataExchange(CDataExchange*pDX)函式進行初始化控制元件;//初始化控制元件
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
//這個函式是控制元件與類成員交換資料用的
CDialog::DoDataExchange(pDX);
//滑塊專用
DDX_Control(pDX, IDC_SLIDER1,m_ctrlSlider);
}
第三步:在BOOL CMyDlg::OnInitDialog()函式裡面進行初始化的設定;//初始化設定
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
.........
m_ctrlSlider.SetRange(0,100); //設定滑塊位置的最大值和最小值
m_ctrlSlider.SetPos(30); //設定滑塊的預設當前位置
}
第三步:新增事件處理函式;
初始化完畢後最後新增一個事件處理函式當調節滑塊位置的時候能得到相應的資料;
1 .h中新增函式宣告
afx_msg void OnNMCustomdrawSlider1(NMHDR *pNMHDR, LRESULT *pResult);
2 新增訊息:
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
.........
ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER1, OnNMCustomdrawSlider1)
.........
3 函式定義;//當調節滑塊的時候通過(2)就會呼叫這個函式;
//主視窗滑塊
void CMyDlg::OnNMCustomdrawSlider1(NMHDR*pNMHDR, LRESULT *pResult)
{
int nPos = m_ctrlSlider.GetPos(); //獲得滑塊的當前位置
//另外做一個編輯框顯示所調節的資料;
CString str="";
str.Format("%d%%",nPos);
SetDlgItemText(IDC_EDIT13,str);
}
完成
//==================================================================================
滑動條控制元件 (CSliderCtrl)使用說明
滑動條控制(Slider Control)也叫軌道條控制,其主要是用一個帶有軌道和滑標的小視窗以及視窗上的刻度,來讓使用者選擇一個離散資料或一個連續的數值區間。通過滑鼠或鍵盤來進行資料的選擇操作,這在WIN98/95中的很多應用程式中都可以看到,如控制皮膚中的滑鼠等,滑動條既可以是水平方式的也可以是垂直方式的。滑動條控制的風格如下:
TBS_HORZ 滑動條是水平方向的
TBS_VERT 滑動條是垂直方向的
TBS_LEFT 滑動條位於視窗左側
TBS_RIGHT 滑動條位於視窗右側
TBS_TOP 滑動條位於視窗頂部
TBS_BOTTOM 滑動條位於視窗底部
TBS_BOTH 滑動條位於視窗兩側
TBS_AUTOTICKS滑動條具有刻度,預設
TBS_NOTICKS 滑動條不具有刻度
滑動條的刻度條在每一個數值位置顯示一個刻度標記,如果在滑動條上顯示某一數值選擇區間,則應使用風格TBS_ENABLESELRANGE,此時選擇區間兩個不再是刻度標記,而是一個小的三角形符號。另外,使用風格TBS_NOTHUMB會使滑標消隱起來。
滑動條控制在MFC類庫中被封裝為CSliderCtrl控制,其主要操作是設定刻度範圍、繪製刻度標記、設定選擇範圍和當前滑標位置等。當使用者進行互動操作時,滑動條控制將向其父視窗傳送訊息WM_HSCROLL,所以在應用程式中應過載父視窗的OnHScroll()成員函式,以便對訊息進行正確處理系統傳送的通知程式碼、滑標位置和指向CSliderCtrl物件的指標等。由於考慮到和水平捲動杆公用同一個成員函式,OnHScroll()函式參數列中的指標變數被定義為CScrollBar*型別,由於實際上訊息是由滑動條產生的,所以在程式中必須把這個指標變數強制轉換為CSliderCtrl*型別。滑動條和捲動杆的訊息程式碼和含義都非常類似如TB_BOTTOM等,所以這種處理方法比較合理。SetRange()函式用來設定範圍,SetPos()函式用來設定當前位置。
(二)滑動條控制的物件結構
滑動條控制的建立方法
CsliderCtrl&SliderCtrl 建立滑動條控制物件結構
Create 建立滑動條控制物件並繫結物件
滑動條控制類CSliderCtrl::Create的呼叫格式如下:
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
其中引數dwStyle用來確定滑動條控制風格;引數rect用來確定滑動條控制的大小和位置;引數pParentWnd用來確定滑動條控制的父視窗指標;引數nID用來確定滑動條控制的控制符ID值。
2、滑動條控制的類屬性
滑動條控制物件的類屬性包括取得滑動條大小GetLineSize、設定滑動條大小SetLineSize、取得滑動條頁大小 GetPageSize、設定滑動條頁大小SetPageSize、取得滑動條最大位置GetRangeMax、取得滑動條最小位置 GetRangeMin、取得滑動條範圍GetRange、設定滑塊最小位置SetRangeMin、設定滑塊最大位置SetRangeMax、設定滑動條範圍SetRange、取得滑塊當前位置GetSelection、設定滑塊當前位置SetSelection、取得滑動條當前位置GetPos和設定滑動條當前位置SetPos等。
3、滑動條控制的操作方法
滑動條控制的操作方法包括清除滑動條當前選擇ClearSel、驗證滑動條當前位置是否在最大最小位置之間VerifyPos和清除當前刻度標誌ClearTics。
滑動條控制的應用技巧示例
1、利用應用程式嚮導AppWizard生成基於物件框的應用程式CSlidDlg;
2、在對話方塊中設定滑動條控制,其ID為IDC_SLIDER;
3、在對話方塊初始程式碼中增加控制的範圍和位置:
(1)在SlidDlg.h中設定資料成員,用來表示滑動條的當前值:
//SlidDlg.h
class CSlidDlg:public Cdialog
{ ......//其它程式碼
public:
int m_nCur;
......//其它程式碼
}
(2)在SlidDlg.cpp中設定初始狀態
BOOL CSlidDlg::OnInitDialog()
{ Cdialog::OnInitDialog();
......//其它程式碼
//TODO:Add extra initialization here
CSliderCtrl*pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLLIDER);
pSlidCtrl->SetRange(1,5,TRUE);//設定滑動條範圍
pSlidCtrl->SetPos(2);//設定滑動條位置
......//其它程式碼
return TRUE;
}
(3)完善滑動條的訊息處理,利用類嚮導ClassWizard增加對話方塊視窗的WM_HSCROLL訊息處理函式,並取得滑標所指位置值:
void CSlidDlg::OnHScroll(UINTnSBCode,UINT nPos,CScrollBar *pScrollBar)
{ //TODO:Add your message handler?
Cdialog::OnHScroll(nSBCode,nPos,pScrollBar);
CSliderCtrl*pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLLIDER);
m_nCur=pSlidCtrl->GetPos();//取得當前位置值
ScrollBarControl
滾動條控制元件簡介
滾動條大家也很熟悉了,Windows視窗中很多都有滾動條。前面講的列表框和組合框設定了相應屬性後,如果列表項顯示不下也會出現滾動條。滾動條分為水平滾動條(HorizontalScroll Bar)和垂直滾動條(Vertical ScrollBar)兩種。滾動條中有一個滾動塊,用於標識滾動條當前滾動的位置。我們可以拖動滾動塊,也可以用滑鼠點選滾動條某一位置使滾動塊移動。
從滾動條的建立形式來分,有標準滾動條和滾動條控制元件兩種。像列表框和組合框設定了WS_HSCROLL 或WS_VSCROLL風格以後出現的滾動條,不是一個獨立的視窗,而是這些視窗的一部分,這就是標準滾動條。而滾動條控制元件是一個獨立的視窗,它可以獲得焦點,響應某些操作。
滾動條控制元件的建立
MFC 也為滾動條控制元件的操作提供了類,即為CScrollBar類。
滾動條控制元件的建立依然有兩種方式,一種是直接在Toolbox中將滾動條控制元件拖入對話方塊模板,然後新增控制元件變數使用,另一種就是用CScrollBar類的Create成員函式動態建立。這兩種方式適用於不同的場合。
CScrollBar類的成員函式Create的函式原型如下:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);
此函式與其他控制元件類的Create函式原型基本相同。引數dwStyle指定滾動條控制元件的風格,rect指定滾動條控制元件的位置和尺寸,pParentWnd為指向滾動條控制元件父視窗的指標,nID指定滾動條控制元件的ID。下面雞啄米簡單介紹幾個主要的滾動條控制元件風格,更加具體的可以查閱MSDN。
SBS_HORZ:指定滾動條為水平滾動條。如果沒有指定SBS_BOTTOMALIGN或SBS_TOPALIGN風格,則滾動條的高度、寬度和位置由Create函式的rect引數給出。
SBS_VERT:指定滾動條為垂直滾動條。如果沒有指定SBS_RIGHTALIGN或SBS_LEFTALIGN風格,則滾動條的高度、寬度和位置由Create函式的rect引數給出。
SBS_TOPALIGN:與SBS_HORZ配合使用。滾動條的上邊緣與Create函式的rect引數指定矩形的上邊緣對齊。滾動條高度為系統滾動條的預設高度。
SBS_BOTTOMALIGN:與SBS_HORZ配合使用。滾動條的下邊緣與Create函式的rect引數指定矩形的下邊緣對齊。滾動條高度為系統滾動條的預設高度。
SBS_LEFTALIGN:與SBS_VERT配合使用。滾動條的左邊緣與Create函式的rect引數指定矩形的左邊緣對齊。滾動條寬度為系統滾動條的預設寬度。
SBS_RIGHTALIGN:與SBS_VERT配合使用。滾動條的右邊緣與Create函式的rect引數指定矩形的右邊緣對齊。滾動條寬度為系統滾動條的預設寬度。
dwStyle引數可以是以上風格中某幾個的組合,另外一般也會用到WS_CHILD、WS_VISIBLE風格。例如,建立一個水平滾動條控制元件,dwStyle引數應該為WS_CHILD|WS_VISIBLE|SBS_HORZ,建立垂直滾動條控制元件時dwStyle引數應該為WS_CHILD|WS_VISIBLE|SBS_VERT。
CScrollBar類的主要成員函式
BOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo, UINT nMask = SIF_ALL);
獲取的滾動條的引數資訊,該資訊為SCROLLINFO結構體的形式。引數lpScrollInfo為指向SCROLLINFO結構體變數的指標。SCROLLINFO結構體的定義如下:
C++程式碼
1. typedef struct tagSCROLLINFO {
2. UINT cbSize; // 結構的尺寸(位元組為單位)
3. UINT fMask; // 說明結構中的哪些引數是有效的,可以是遮蔽值的組合,如SIF_POS|SIF_PAGE,若為SIF_ALL則整個結構都有效
4. int nMin; // 滾動範圍最大值,當fMask 中包含SIF_RANGE 時有效
5. int nMax; // 滾動範圍最小值,當fMask 中包含SIF_RANGE 時有效
6. UINT nPage; // 頁尺寸,用來確定比例滾動框的大小,當fMask中包含SIF_PAGE時有效
7. int nPos; // 滾動框的位置,當fMask 中包含SIF_POS 有效
8. int nTrackPos; // 滾動時滾動框的位置,當fMask 中包含SIF_TRACKPOS 時有效,該引數只能查詢,不能設定,最好不要用該引數來查詢拖動時滾動框的位置
9. } SCROLLINFO, *LPSCROLLINFO;
10. typedef SCROLLINFO CONST *LPCSCROLLINFO;
引數nMask 的含義與SCROLLINFO 結構體中的fMask一樣。該函式在獲取資訊成功則返回TRUE,否則返回FALSE。
BOOL SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE);
用於設定滾動條的各種引數資訊。引數lpScrollInfo為指向SCROLLINFO結構體變數的指標,引數bRedraw表示是否需要重繪滾動條,如果為TRUE,則重繪。該函式操作成功則返回TRUE,否則返回FALSE。
int GetScrollPos( ) const;
獲取滾動塊的當前位置。如果失敗則返回0。
int SetScrollPos(int nPos, BOOL bRedraw = TRUE);
將滾動塊移動到指定位置。引數nPos指定了滾動塊的新位置,引數bRedraw 表示是否需要重繪滾動條,如果為TRUE,則重繪。函式返回滾動框原來的位置,若操作失敗則返回0。
void GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const;
獲取滾動條的滾動範圍。引數lpMinPos指向滾動條滾動範圍的最小值,引數lpMaxPos指向滾動條滾動範圍的最大值。
void SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE);
用於指定滾動條的滾動範圍。引數nMinPos 和nMaxPos 分別指定了滾動範圍的最小值和最大值,兩者的差不得超過32767。當兩者都為0 時,滾動條將被隱藏。引數bRedraw 表示是否需要重繪滾動條,如果為TRUE,則重繪。
OnHScroll()與OnVScroll()函式
無論是標準滾動條,還是滾動條控制元件,滾動條的通知訊息都是用WM_HSCROLL 和WM_VSCROLL訊息傳送出去的。對這兩個訊息的預設處理函式是CWnd::OnHScroll和CWnd::OnVScroll,一般需要在派生類中對這兩個函式進行過載,以實現滾動功能。也就是說,假設在一個對話方塊中放入了一個水平滾動條,我們可以在對話方塊類中過載OnHScroll函式,並在OnHScroll函式中實現滾動功能。
這兩個函式的宣告如下:
afx_msg void OnHScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar);
afx_msg void OnVScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar);
引數nSBCode是通知訊息碼,主要通知碼及含義的介紹下面已列出。nPos 是滾動框的位置,只有在nSBCode為SB_THUMBPOSITION或SB_THUMBTRACK時,該引數才有意義。如果通知訊息是滾動條控制元件發來的,那麼pScrollBar 是指向該控制元件的指標,如果是標準滾動條發來的,則pScrollBar 為NULL。
SB_BOTTOM/SB_RIGHT:滾動到底端(右端)
SB_TOP/SB_LEFT:滾動到頂端(左端)
SB_LINEDOWN/SB_LINERIGHT:向下(向右)滾動一行(列)
SB_LINEUP/SB_LINELEFT:向上(向左)滾動一行(列)
SB_PAGEDOWN/SB_PAGERIGHT:向下(向右)滾動一頁
SB_PAGEUP/SB_PAGELEFT:向上(向左)滾動一頁
SB_THUMBPOSITION:滾動到指定位置
SB_THUMBTRACK:滾動框被拖動。可利用該訊息來跟蹤對滾動框的拖動
SB_ENDSCROLL:滾動結束
CScrollBar類應用例項
講完了基礎知識,雞啄米還是給大家一個簡單的例項。例子非常簡單,就是在一個對話方塊中加入一個水平滾動條控制元件和一個編輯框控制元件,無論滾動條控制元件是在滾動還是靜止,編輯框中都顯示滾動塊的當前位置。以下是具體開發步驟:
1. 建立一個基於對話方塊的MFC工程,名稱設定為“Example26”。
2. 在自動生成的對話方塊模板IDD_EXAMPLE26_DIALOG中,刪除“TODO: Place dialog controls here.”靜態文字控制元件、“OK”按鈕和“Cancel”按鈕。新增一個Horizontal Scroll Bar控制元件,ID設定為IDC_HORI_SCROLLBAR。再新增一個靜態文字控制元件和一個編輯框,靜態文字控制元件的Caption屬性設為“滾動塊當前位置:”,編輯框的ID設為IDC_HSCROLL_EDIT,Read Only屬性設為True。此時的對話方塊模板如下圖:
3. 為滾動條IDC_HORI_SCROLLBAR新增CScrollBar型別的控制元件變數m_horiScrollbar。
4. 在對話方塊初始化時,我們需要設定滾動條的滾動範圍和初始位置,並在編輯框中顯示初始位置,那麼需要修改CExample26Dlg::OnInitDialog()函式為:
C++程式碼
1. BOOL CExample26Dlg::OnInitDialog()
2. {
3. CDialogEx::OnInitDialog();
4.
5. // Add "About..." menu item tosystem menu.
6.
7. // IDM_ABOUTBOX must be in the systemcommand range.
8. ASSERT((IDM_ABOUTBOX & 0xFFF0) ==IDM_ABOUTBOX);
9. ASSERT(IDM_ABOUTBOX < 0xF000);
10.
11. CMenu* pSysMenu =GetSystemMenu(FALSE);
12. if (pSysMenu != NULL)
13. {
14. BOOL bNameValid;
15. CString strAboutMenu;
16. bNameValid =strAboutMenu.LoadString(IDS_ABOUTBOX);
17. ASSERT(bNameValid);
18. if (!strAboutMenu.IsEmpty())
19. {
20. pSysMenu->AppendMenu(MF_SEPARATOR);
21. pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX, strAboutMenu);
22. }
23. }
24.
25. // Set the icon for this dialog. The framework does this automatically
26. // when the application's main window is not a dialog
27. SetIcon(m_hIcon, TRUE); // Set big icon
28. SetIcon(m_hIcon, FALSE); // Set small icon
29.
30. // TODO: Add extra initializationhere
31. // 設定水平滾動條的滾動範圍為1到100
32. m_horiScrollbar.SetScrollRange(1,100);
33. // 設定水平滾動條的初始位置為20
34. m_horiScrollbar.SetScrollPos(20);
35. // 在編輯框中顯示20
36. SetDlgItemInt(IDC_HSCROLL_EDIT, 20);
37.
38. return TRUE; // return TRUE unless you set the focus to a control
39. }
5. 現在滾動條還不能正常滾動,並且編輯框中數字也不隨滾動改變。根據上面所講,我們可以過載CExample26Dlg類的OnHScroll函式。具體操作為,在CExample26Dlg類的屬性頁面的工具欄上點“Messages”按鈕,找到WM_HSCROLL訊息,新增響應函式就可以了。OnHScroll函式重寫後如下:
C++程式碼
1. void CExample26Dlg::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
2. {
3. // TODO: Add your message handler codehere and/or call default
4. int pos = m_horiScrollbar.GetScrollPos(); // 獲取水平滾動條當前位置
5.
6. switch (nSBCode)
7. {
8. // 如果向左滾動一列,則pos減1
9. case SB_LINEUP:
10. pos -= 1;
11. break ;
12. // 如果向右滾動一列,則pos加1
13. case SB_LINEDOWN:
14. pos += 1;
15. break ;
16. // 如果向左滾動一頁,則pos減10
17. case SB_PAGEUP:
18. pos -= 10;
19. break ;
20. // 如果向右滾動一頁,則pos加10
21. case SB_PAGEDOWN:
22. pos += 10;
23. break ;
24. // 如果滾動到最左端,則pos為1
25. case SB_TOP:
26. pos = 1;
27. break ;
28. // 如果滾動到最右端,則pos為100
29. case SB_BOTTOM:
30. pos = 100;
31. break ;
32. // 如果拖動滾動塊滾動到指定位置,則pos賦值為nPos的值
33. case SB_THUMBPOSITION:
34. pos = nPos;
35. break ;
36. // 下面的m_horiScrollbar.SetScrollPos(pos);執行時會第二次進入此函式,最終確定滾動塊位置,並且會直接到default分支,所以在此處設定編輯框中顯示數值
37. default :
38. SetDlgItemInt(IDC_HSCROLL_EDIT,pos);
39. return ;
40. }
41.
42. // 設定滾動塊位置
43. m_horiScrollbar.SetScrollPos(pos);
44.
45. CDialogEx::OnHScroll(nSBCode, nPos,pScrollBar);
46. }
6. 編譯執行程式,彈出結果對話方塊,可以自己拖動滾動塊看是否能正常滾動,並且編輯框中也顯示了正確的數值。效果如下:
SpinButton Control
CSpinButtonCtrl
└CWnd |
└CSpinButtonCtrl |
1. 控制元件風格
控制元件風格 |
含義 |
UDS_HORZ |
指定一個水平旋轉按鈕.若不指定該風格則建立一個垂直的旋轉按鈕. |
UDS_WRAP |
當旋轉按鈕增大到超過最大值時,自動重置為最小值,當減小至低於最小值時,自動重置為最大值. |
UDS_ARROWKEYS |
當使用者按下向下或向上箭頭鍵時,旋轉按鈕值遞增或遞減. |
UDS_SETBUDDYINT |
旋轉按鈕將自動更新夥伴控制元件中顯示的數值,如果夥伴控制元件能接受輸入,則可在夥伴控制元件中輸入新的旋轉按鈕值. |
UDS_NOTHOUSANDS |
夥伴控制元件中顯示的數值每隔三位沒有千位分隔符. |
UDS_AUTOBUDDY |
自動使旋轉按鈕擁有一個夥伴控制元件. |
UDS_ALIGNRIGHT |
旋轉按鈕在夥伴控制元件的右側. |
UDS_ALIGNLEFT |
旋轉按鈕在夥伴控制元件的左側. |
除上表的風格外,一般還要為旋轉按鈕指定WS_CHILD和WS_VISIBLE風格.建立一個有夥伴的垂直旋轉按鈕控制元件,一般應指定的風格為WS_CHILD|WS_VISIBLE|UDS_AUTOBUDDY| UDS_SETBUDDYINT.對於用對話方塊模板建立的旋轉按鈕控制元件,可以在控制元件的屬性對話方塊中指定上表中列出的控制元件風格。例如,在屬性對話方塊中選擇Auto buddy,相當於指定了UDS_AUTOBUDDY風格.
2.成員函式
通過CSpinButtonCtrl的成員函式,可以對旋轉按鈕進行查詢和設定:
用GetRange和SetRange來查詢和設定旋轉按鈕值的範圍,預設時值的範圍是1-100.這兩個函式的宣告為
void GetRange( int &lower, int& upper ) const;
void SetRange( int nLower, int nUpper );
第一個引數是最小值,該值不能小於UD_MINVAL,第二個引數是最大值,該值不能大於UD_MAXVAL.值的範圍不能超過UD_MAXVAL.
用GetPos和SetPos來查詢和設定旋轉按鈕的當前值.函式的宣告為
int GetPos( ) const;
int SetPos( int nPos );
用GetBase和SetBase來查詢和設定旋轉按鈕值的計數制.函式的宣告為
UINT GetBase( ) const;
int SetBase( int nBase );
如果引數nBase是10,則夥伴控制元件中顯示的數值是十進位制的,如果nBase是16,則是十六進位制的.
用GetBuddy和SetBuddy來查詢和設定旋轉按鈕的夥伴.上面已講了在對話方塊模板中設定夥伴控制元件的方法,如果是用Create手工建立旋轉按鈕,則可以用SetBuddy來設定夥伴.函式的宣告為
CWnd* GetBuddy( ) const;
CWnd* SetBuddy( CWnd* pWndBuddy );
引數pWndBuddy是指向夥伴控制元件物件的CWnd型指標.
可以用GetAccel和SetAccel來查詢和設定旋轉按鈕的加速值.在平時,在旋轉按鈕上按一下只會增/減一個單位,而當按住按鈕超過一定時間時,遞增或遞減的幅度將會加大到指定的加速值,從而加快了增減的速度.如果對預設的加速值不滿意,可以用SetAccel設定新的加速值.可以有一套以上的加速值.函式的宣告為
UINT GetAccel( int nAccel, UDACCEL* pAccel ) const;
BOOL SetAccel( int nAccel, UDACCEL* pAccel );
引數nAccel指定了UDACCEL結構陣列的大小.引數pAccel指向一個UDACCEL結構陣列.UDACCEL結構含有加速值的資訊,其定義如下
typedef struct {
int nSec; //加速值生效需要的時間(以秒為單位)
int nInc; //加速值
} UDACCEL;
旋轉按鈕常被認為是一個簡化的滾動條.除了表6.22列出的通知訊息外,旋轉按鈕特有的滾動通知訊息是通過WM_HSCROLL和WM_VSCROLL訊息發出的.訊息處理函式OnHScroll或OnVScroll分別用來處理水平或垂直旋轉按鈕的事件通知.由於夥伴控制元件中的內容會自動隨旋轉按鈕變化,所以旋轉按鈕的通知訊息意義不大.如果非要處理通知訊息,一個典型的OnVscroll函式如下所示:
void CMyDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CSpinButtonCtrl* pSpin=(CSpinButtonCtrl*)pScrollBar;
int nPosition;
if(pSpin= =&m_Spin) //判斷是否是該旋轉按鈕發來的訊息
{
nPosition=m_Spin.GetPos( ); //獲取旋轉按鈕的當前值
. . . . . .
}
. . . . . .
}
一個“旋轉按鈕控制元件”(也稱為上下控制元件)是一對箭頭按鈕,使用者點選它們來增加或減小一個值,比如一個滾動位置或顯示在相應控制元件中的一個數字。與一個旋轉按鈕控制元件相聯絡的值被稱為它的當前位置。一個旋轉控制元件通常是與一個相伴的控制元件一起使用的,稱為“夥伴視窗”。
CSpinButtonCtrl類提供了Windows通用旋轉按鈕控制元件的功能。這個控制元件(也就是CSpinButtonCtrl類)只對執行在Windows95和Windows
NT3.51或更高版本下的程式來說是可用的。
對使用者來說,一個旋轉按鈕控制元件和它的夥伴視窗看起來通常就象一個單一的控制元件。你可以指定一個旋轉按鈕控制元件自動將它自己定位在它的夥伴視窗的旁邊,並且它自動將它的夥伴視窗的標題設定為它的當前位置。可以將一個旋轉按鈕控制元件與一個編輯控制元件一起使用,以提示使用者進行數字輸入。
點選向上箭頭使當前位置向最大值方向移動,而點選向下箭頭使當前位置向最小值的方向移動。預設的,最小值是100,最大值是0。任何時候,最小值的設定都大於最大值(例如,當使用預設值時),點選向上箭頭減少位置值,而點選向下箭頭則增加它。
一個沒有夥伴視窗的旋轉按鈕控制元件就象簡化了的滾動條。例如,一個tab控制元件有時顯示一個旋轉按鈕控制元件來使它的使用者能夠滾動其它的tab進入視。
有關使用CSpinButtonCtrl的更多資訊,參見“Visual C++程式設計師指南”中的“控制元件主題”和“使用CSpinButtonCtrl”。
#include <afxcmn.h>
請參閱:CSliderCtrl
CSpinButtonCtrl類成員
Construction
構造一個CSpinButtonCtrl物件 |
|
建立一個旋轉按鈕控制元件並將它連線到一個CSpinButtonCtrl物件 |
Attributes
為一個旋轉按鈕控制元件設定加速 |
|
獲取一個旋轉按鈕控制元件的加速資訊 |
|
為一個旋轉按鈕控制元件設定基數 |
|
獲取一個旋轉按鈕控制元件的當前基數 |
|
為一個旋轉按鈕控制元件設定夥伴視窗 |
|
獲取指向當前夥伴視窗的指標 |
|
設定控制元件的當前位置 |
|
獲取一個旋轉按鈕控制元件的當前位置 |
|
設定一個旋轉按鈕控制元件的上限和下限(範圍) |
|
獲取一個旋轉按鈕控制元件的上限和下限(範圍) |
|
設定旋轉按鈕控制元件的32位範圍 |
|
獲取旋轉按鈕控制元件的32位範圍 |
下面是我自己寫的一個示例:
在我的程式裡我用到了兩個函式,SetRange()和SetBuddy().
SetRange()函式的作用是設定spin控制元件向上與向下按鈕所能調整的最大和最小值.
SetBuddy()函式選擇一個與spin搭夥的控制元件,一般選用的是edit
1/建立一個mfc對話方塊類工程,名稱為SpinTest1
2/在對話方塊視窗裡加入一個Edit(ID號為IDC_EDIT_VALUE)和一個spin(ID號為IDC_SPIN_ABC)控制元件.
為IDC_SPIN_ABC控制元件建一個關聯變數m_abc
3/在CSpinTest1Dlg類的OnInitDialog()裡新增下面程式碼
m_abc.SetRange(1900,2000);
m_abc.SetBuddy((CWnd*)GetDlgItem(IDC_EDIT_VALUE));
4/你可以根據需要為Edit控制元件設定一個初始值,這樣這個spin控制元件就基本可以使用了
說明:
有關這個控制元件,我在網上查了很多的資料,結果都說的很複雜,例如,在沒有設定SetRange()範圍之前,如何執行程式,會發現點選向上鍵頭的按鈕,數值是減少的,反之是增加的,這個問題網上有人還專門用了一個OnDeltaPos*()函式來解決,而我通過實踐證明,只要設定了範圍,就可以校正這個問題(當然這個只適用於數值資料的方面),網上還有有關點選了按鈕之後在edit控制元件裡顯示字元的程式,如果做這樣的程式可能會用到OnDeltaPos*()函式,下面我引用一下有關這個函式的新增方法:
旋轉按鈕控制元件的通知訊息
旋轉按鈕控制元件的通知訊息只有一個:UDN_DELTAPOS,它表示控制元件的位置將要改變。
用ClassWizard可以對映此訊息,在此訊息的處理函式中有個NM_UPDOWN結構需要進行
說明,其結構如下:
typedef struct_NM_UPDOWN{
NMHDR hdr; //通知程式碼的其他資訊
int iPos; //當前位置
int iDelta; //位置的增減量,單擊向上箭頭此值為負數
}NMUPDOWN,FAR* LPNMUPDOWN;
應用例項:用Spin控制元件完成對字元的增減
響應UDN_DELTAPOS訊息
旋轉按鈕控制元件的訊息UDN_DELTAPOS
表示控制元件的位置將要改變
原理 , 過載Spin控制元件的UDN_DELTAPOS訊息 , 將會多出如下函式:
void CTestDlg::OnDeltaposSpin3(NMHDR*pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown= (NM_UPDOWN*)pNMHDR;
if(pNMUpDown->iDelta == 1) // 如果此值為1 , 說明點選了Spin的往下箭頭
{
//對字元做相關處理 , 例如將"a" 變為 "b"
}
else if(pNMUpDown->iDelta== -1) // 如果此值為-1 , 說明點選了Spin的往上箭頭
{
//對字元做相關處理 , 例如將"b" 變為 "a"
}
*pResult = 0;
}
詳細做法:
1: 假設你編輯框為IDC_EDIT , SPIN按鈕為IDC_SPIN .
2: Ctrl + W , 進入Class Wizard , 在Object IDs列選擇IDC_SPIN , 在Messages列選擇UDN_DELTAPOS, 點選"Add Function" 按鈕.將彈出"OnDeltaposSpin"的對話方塊 ,點OK 新增這個函式.然後點"EditCode" , 進入新新增的函式裡 .
3: 將會新新增一個函式.
void CTestDlg::OnDeltaposSpin(NMHDR*pNMHDR, LRESULT* pResult) . . .
4: 新增如下程式碼:
void CTestDlg::OnDeltaposSpin(NMHDR*pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown= (NM_UPDOWN*)pNMHDR;
CWnd* pWnd =(CWnd*)GetDlgItem(IDC_EDIT); //得到指向編輯框的視窗指標
CString strValue ;
pWnd->GetWindowText(strValue); //得到編輯框中的內容
if(pNMUpDown->iDelta ==1) //如果點選的是Spin中的往上按鈕
{
if(!strValue.IsEmpty())
{
strValue.SetAt(0 , strValue[0] + 1); //編輯框首字母加1
pWnd->SetWindowText(strValue); //儲存修改
}
}
elseif(pNMUpDown->iDelta == - 1) //如果點選的是Spin中往下按鈕
{
if(!strValue.IsEmpty())
{
strValue.SetAt(0 , strValue[0] - 1); //編輯框首字母減1
pWnd->SetWindowText(strValue); //儲存修改
}
}
*pResult = 0;
}
使用上述做法,後來遇到一個問題:當一直按住上或者下時,增大16個後就不再增大,後來發現,將條件改成大於0和小於0就可以了,大於0表示向上按鈕。
SplitButton Control
VS2008中可以看到MFC有一個叫Split Button的控制元件,要想看它的效果,瞧下QQ那聊天視窗的"傳送", "訊息記錄"這兩個按鈕就知道了.實際上就是還有點像Combo Box了.不過它的實現應該是button加menu.所以它的訊息處理可以分開成button的處理和menu的處理
往dialog上拖一個split button後,再給它繫結一個變數.
CSplitButton m_sbSend;
DDX_Control(pDX, IDC_SPLIT1, m_sbSend);
因為說了split button實際上是button跟menu的組合.所以你得整個menu先.不是什麼特殊的選單,就是主頁面常用的那種選單.
m_split.SetDropDownMenu(IDR_MENU1,0); //新增split button的下拉選單.第一個引數就是選單的資源ID,第二個引數就是子項索引,就是選單根項從左之右數過去了.我們這裡只能用到它的一個子選單.
訊息處理
split button中按鈕部分的訊息處理跟一般按鈕一樣.
ON_BN_CLICKED(IDC_SPLIT1,OnBnClickedSplit1)
void CMFCControlDlg::OnBnClickedSplit1()
{
AfxMessageBox(_T("click splitbutton"));
}
下拉選單的處理
split button中下拉選單的處理也跟一般選單類似
ON_COMMAND(ID_Split_Menu1, SendMsg)
void CMFCControlDlg::SendMsg()
{
AfxMessageBox(_T("Click dropdownmenu of split button"));
}
PropertyGrid
HotKey
1. 新增WM_HOTKEY視窗訊息
在 VC ++ 6.0 和VS2005中,大多數的視窗訊息可以從 ClassWizard 中找到,但是一些不常用的訊息
在 ClassWizard 中並沒有封裝 ,WM_HOTKEY 就是其中一個,因此使用者必須手動新增。新增程式碼如下:
afx_msg LRESULT OnHotKey(WPARAMwp,LPARAM lp);
ON_MESSAGE(WM_HOTKEY,&CVS_2005_DlgDlg::OnHotKey)
LRESULT CVS_2005_DlgDlg::OnHotKey(WPARAMwp,LPARAM lp)
{
WinExec("notepad",1);//開啟記事本
return 1;
}
2. 註冊熱鍵
BOOL CVS_2005_DlgDlg::OnInitDialog()
{
...
UINT fsModifiers = 0;
fsModifiers |= MOD_CONTROL;
fsModifiers |= MOD_ALT;
RegisterHotKey(GetSafeHwnd(), 1, fsModifiers,VK_F8); // 註冊熱鍵
...
}
這樣,每當按下Ctrl+Alt+F8時,就會調出Windows記事本程式。
hot key control用法:
A "hot key control" is awindow that enables the user to create a hot key.
A "hot key" is a keycombination that the user can press to perform an action quickly.
(For example, a user can create a hotkey that activates a given window and brings it
to the top of the Z order.) The hot keycontrol displays the user's choices and ensures
that the user selects a valid keycombination.
1)加入控制元件變數:
CHotKeyCtrl m_hotKeyCtrl;
DDX_Control(pDX, IDC_HOTKEY1,m_hotKeyCtrl);
2)新增一按鈕和按鈕處理程式,使用者設定完HotKey後按此按鈕即設定了新的HotKey
afx_msg void OnBnClickedButton2();
ON_BN_CLICKED(IDC_BUTTON2,&CVS_2005_DlgDlg::OnBnClickedButton2)
voidCVS_2005_DlgDlg::OnBnClickedButton2()
{
//#define HOTKEYF_SHIFT 0x01
//#define HOTKEYF_CONTROL 0x02
//#define HOTKEYF_ALT 0x04
//#define HOTKEYF_EXT 0x08
WORD VirtualKeyCode=0,fsModifiers = 0;
m_hotKeyCtrl.GetHotKey(VirtualKeyCode,fsModifiers);
//#define MOD_ALT 0x0001
//#define MOD_CONTROL 0x0002
//#define MOD_SHIFT 0x0004
//#define MOD_WIN 0x0008
//GetHotKey() 與RegisterHotKey()用的標誌位不一樣,需要轉換
UINT fsModifiers2 = 0;
if (fsModifiers & HOTKEYF_SHIFT)
{
fsModifiers2 |=MOD_SHIFT;
}
if (fsModifiers & HOTKEYF_CONTROL)
{
fsModifiers2 |=MOD_CONTROL;
}
if (fsModifiers & HOTKEYF_ALT)
{
fsModifiers2 |=MOD_ALT;
}
RegisterHotKey(GetSafeHwnd(), 1, fsModifiers2,VirtualKeyCode); // 註冊熱鍵
}
vbKeyLButton 1 滑鼠左鍵
-------------------------------------------------------------------
vbKeyRButton 2 滑鼠右鍵
-------------------------------------------------------------------
vbKeyCancel 3 CANCEL 鍵
-------------------------------------------------------------------
vbKeyMButton 4 滑鼠中鍵
-------------------------------------------------------------------
vbKeyBack 8 Backspace 鍵
-------------------------------------------------------------------
vbKeyTab 9 TAB 鍵
-------------------------------------------------------------------
vbKeyClear 12 CLEAR 鍵
-------------------------------------------------------------------
vbKeyReturn 13 Enter 鍵
-------------------------------------------------------------------
vbKeyShift 16 Shift 鍵
-------------------------------------------------------------------
vbKeyConterol 17 Ctrl 鍵
-------------------------------------------------------------------
vbKeyMenu 18 選單鍵
-------------------------------------------------------------------
vbKeyPause 19 PAUSE 鍵
-------------------------------------------------------------------
vbKeyCapital 20 CAPS LOCK 鍵
-------------------------------------------------------------------
vbKeyEscape 27 ESC 鍵
-------------------------------------------------------------------
vbKeySpace 32 SPACEBAR 鍵
-------------------------------------------------------------------
vbKeyPageUp 33 PAGEUP 鍵
-------------------------------------------------------------------
vbKeyPageDown 34 PAGEDOWN 鍵
-------------------------------------------------------------------
vbKeyEnd 35 END 鍵
-------------------------------------------------------------------
vbKeyHome 36 HOME 鍵
-------------------------------------------------------------------
vbKeyLeft 37 LEFT ARROW 鍵←
-------------------------------------------------------------------
vbKeyUp 38 UP ARROW 鍵↑
-------------------------------------------------------------------
vbKeyRight 39 RIGHT ARROW 鍵→
-------------------------------------------------------------------
vbKeyDown 40 DOWN ARROW 鍵↓
-------------------------------------------------------------------
vbKeySelect 41 SELECT 鍵
-------------------------------------------------------------------
vbKeyPrint 42 PRINT SCREEN 鍵
-------------------------------------------------------------------
vbKeyExecute 43 EXECUTE 鍵
-------------------------------------------------------------------
vbKeySnapshot 44 SNAP SHOT 鍵
-------------------------------------------------------------------
vbKeyInser 45 INSERT 鍵
-------------------------------------------------------------------
vbKeyDelete 46 DELETE 鍵
-------------------------------------------------------------------
vbKeyHelp 47 HELP 鍵
-------------------------------------------------------------------
vbKey0 48 0 鍵
-------------------------------------------------------------------
vbKey1 49 1 鍵
-------------------------------------------------------------------
vbKey2 50 2 鍵
-------------------------------------------------------------------
vbKey3 51 3 鍵
-------------------------------------------------------------------
vbKey4 52 4 鍵
-------------------------------------------------------------------
vbKey5 53 5 鍵
-------------------------------------------------------------------
vbKey6 54 6 鍵
-------------------------------------------------------------------
vbKey7 55 7 鍵
-------------------------------------------------------------------
vbKey8 56 8 鍵
-------------------------------------------------------------------
vbKey9 57 9 鍵
-------------------------------------------------------------------
vbKeyA 65 A 鍵
-------------------------------------------------------------------
vbKeyB 66 B 鍵
-------------------------------------------------------------------
vbKeyC 67 C 鍵
-------------------------------------------------------------------
vbKeyD 68 D 鍵
-------------------------------------------------------------------
vbKeyE 69 E 鍵
-------------------------------------------------------------------
vbKeyF 70 F 鍵
-------------------------------------------------------------------
vbKeyG 71 G 鍵
-------------------------------------------------------------------
vbKeyH 72 H 鍵
-------------------------------------------------------------------
vbKeyI 73 I 鍵
-------------------------------------------------------------------
vbKeyJ 74 J 鍵
-------------------------------------------------------------------
vbKeyK 75 K 鍵
-------------------------------------------------------------------
vbKeyL 76 L 鍵
-------------------------------------------------------------------
vbKeyM 77 M 鍵
-------------------------------------------------------------------
vbKeyN 78 N 鍵
-------------------------------------------------------------------
vbKeyO 79 O 鍵
-------------------------------------------------------------------
vbKeyP 80 P 鍵
-------------------------------------------------------------------
vbKeyQ 81 Q 鍵
-------------------------------------------------------------------
vbKeyR 82 R 鍵
-------------------------------------------------------------------
vbKeyS 83 S 鍵
-------------------------------------------------------------------
vbKeyT 84 T 鍵
-------------------------------------------------------------------
vbKeyU 85 U 鍵
-------------------------------------------------------------------
vbKeyV 86 V 鍵
-------------------------------------------------------------------
vbKeyW 87 W 鍵
-------------------------------------------------------------------
vbKeyX 88 X 鍵
-------------------------------------------------------------------
vbKeyY 89 Y 鍵
-------------------------------------------------------------------
vbKeyZ 90 Z 鍵
-------------------------------------------------------------------
vbKeyNum0 96 0 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum1 97 1 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum2 98 2 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum3 99 3 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum4 100 4 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum5 101 5 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum6 102 6 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum7 103 7 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum8 104 8 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyNum9 105 9 鍵 (在數字小鍵盤上)
-------------------------------------------------------------------
vbKeyMultiply 106 乘號(*) 鍵
-------------------------------------------------------------------
vbKeyAdd 107 加號(+) 鍵
-------------------------------------------------------------------
vbKeySeparator 108 Enter鍵(在數字小鍵盤上)
-------------------------------------------------------------------
vbKeySubtract 109 減號(-) 鍵
-------------------------------------------------------------------
vbKeyDecimal 110 小數點(.) 鍵
-------------------------------------------------------------------
vbKeyDivide 111 除號(/) 鍵
-------------------------------------------------------------------
vbKeyF1 112 F1 鍵
-------------------------------------------------------------------
vbKeyF2 113 F2 鍵
-------------------------------------------------------------------
vbKeyF3 114 F3 鍵
-------------------------------------------------------------------
vbKeyF4 115 F4 鍵
-------------------------------------------------------------------
vbKeyF5 116 F5 鍵
-------------------------------------------------------------------
vbKeyF6 117 F6 鍵
-------------------------------------------------------------------
vbKeyF7 118 F7 鍵
-------------------------------------------------------------------
vbKeyF8 119 F8 鍵
-------------------------------------------------------------------
vbKeyF9 120 F9 鍵
-------------------------------------------------------------------
vbKeyF10 121 F10 鍵
-------------------------------------------------------------------
vbKeyF11 122 F11 鍵
-------------------------------------------------------------------
vbKeyF12 123 F12 鍵
-------------------------------------------------------------------
vbKeyF13 124 F13 鍵
-------------------------------------------------------------------
vbKeyF14 125 F14 鍵
-------------------------------------------------------------------
vbKeyF15 126 F15 鍵
-------------------------------------------------------------------
vbKeyF16 127 F16 鍵
-------------------------------------------------------------------
vbKeyNumlock 144 NUM LOCK 鍵
AnimationControl
有時要在頁面上顯示些動態畫面,可以使用該控制元件.
CAnimateCtrl m_animate;
DDX_Control(pDX, IDC_ANIMATE1,m_animate);
m_animate.Open(_T("D:\\Temp\\boxed-correct.avi"));//載入一個avi檔案
m_animate.CenterWindow(); //播放視窗顯示位置
m_animate.Play(0,-1,-1); //開始播放,三個引數的意思分別是:第一個參數列示開始播放的位置,0表示從開頭播放. 第二個參數列示結束位置,-1表示播放完整個視訊.第三個參數列示重複播放的次數,-1表示重複無數次. 播放的位置你可以聯想下看視訊時下面的進度條,可以拉動選擇播放指定的內容.
如果要停止播放則
m_animate.Stop();
昨晚到現在一直尋思著在MFC的Dialog上顯示個GIF圖片,無奈如此的有難度,經過尋找找到個好用的控制元件,拿來用了,但是官網給的不是很好使。也缺乏一個檔案,我這裡一起整理出來了。說個過程
1:一共需要5個檔案,其中3個h,2個cpp檔案,如圖:
2:分別匯入到自己的工程,接下來才是操作
3:在自己的Dlg的資源設計上,新增一個static的靜態文字框,然後給這個文字框賦予id衛IDC_GIF_ANIMATION,然後右鍵點選這個文字框找到-》建立類嚮導-》成員變數-》在下面找到“IDC_GIF_ANIMATION”,雙擊-》變數名字輸入“m_Animation”,目錄選擇“Control”,型別選擇CStatic。
4:在Dlg的h中找到CStaticm_Animation,修改成 CGifAnimationm_Animation;,並且在這個h中新增#include "GifAnimation.h"
5:在Dlg的cpp中初始化函式中新增:
m_Animation.LoadAnimatedGif("./res/1.gif");
m_Animation.Play();
6:編譯即可。
動畫控制元件的侷限:
動畫控制元件並不能播放所有的AVI檔案,只有滿足下列條件的AVI檔案才能被播放:
- AVI檔案必須是無聲的,不能有聲道。
- AVI檔案必須是未壓縮的,或是用RLE演算法壓縮的。
- AVI的調色盤必須保持不變。
動畫控制元件最大的侷限性在於它只能顯示系統調色盤中預設的顏色,因此如果用動畫控制元件來播放一個256色的AVI檔案,那麼播放效果看起來就象一個16色的動畫一樣,很不理想。
總之,動畫控制元件只能播放一些簡單的,顏色數較少的AVI動畫。
CommandButton Control
這個名字取得挺忽悠人.其實該控制元件沒太多新東西,就在原有的Button上加了一點新特性.仍然屬於button.
它用起來不同於一般button的地方主要是3個方面.
1.除了button上面的caption顯示的文字外還多了個note文字,相當起於進一步解釋作用的文字,並是用小號的字顯示出來.
2.可以在button前面顯示一個icon圖示,預設是指向右邊的箭頭
3.滑鼠沒放過去之前不像個button,像個static text控制元件一樣的文字資訊.滑鼠移上去後才變得像button.
除了上面說的之外其他操作跟一般button一樣.
所以主要來看下怎麼設定note,和icon
CButton*pBtn = (CButton*)GetDlgItem(IDC_COMMAND1);
pBtn->SetNote(_T("something todescription")); //設定note的內容
pBtn->SetIcon(m_hIcon); //設定icon,當然也可以使用預設的icon.
NetwordAddress Control
開啟看到那控制元件的樣子就完全是個Edit control.不過該控制元件對應的類也確實是繼承自類CEdit.
先拖個控制元件.然後繫結個變數
CNetAddressCtrl m_netName;
DDX_Control(pDX,IDC_NETADDRESS, m_netName);
m_netName.SetAllowType(NET_STRING_IPV4_ADDRESS);//只要輸入IPV4格式的IP .如果讓輸入IPv6就是NET_STRING_IPV6_ADDRESS,輸入網址就是NET_STRING_NAMED_ADDRESS
不過輸入的時候反正不管,只有完了後再驗證.並且要自己寫點程式碼驗證.假如點OK後驗證下輸的對不
voidCMFCControlDlg::OnOK()
{
NC_ADDRESS m_na;
NET_ADDRESS_INFOm_nai;
m_na.pAddrInfo= &m_nai;
HRESULTrslt = m_netName.GetAddress(&m_na);
if (rslt!= S_OK)
m_netName.DisplayErrorTip();
else
AfxMessageBox(_T("The format is correct"));
}
IPAddress Control
1.獨立的獲取本機IP地址和計算機名
void CMyDlg::OnIPAddress()
{
//此段程式碼:獨立的獲取本機IP地址和計算機名
WORDwVersionRequested;
WSADATAwsaData;
charname[255];
CStringip;
PHOSTENThostinfo;
wVersionRequested= MAKEWORD(2, 0);
if(WSAStartup(wVersionRequested, &wsaData) == 0)
{
if(gethostname(name, sizeof(name)) == 0)
{
if((hostinfo= gethostbyname(name)) != NULL)
{
ip = inet_ntoa(*(struct in_addr*)*hostinfo->h_addr_list);
}
}
WSACleanup( );
}
//AfxMessageBox(name);//name裡是本機名
//AfxMessageBox(ip); //ip中是本機IP
m_IPAddress= ip; // m_IPAddress是IP控制元件對應的變數,ip是Edit控制元件對應的變數
//m_IP.SetAddress(255, 86, 255, 68); // 直接設定控制元件裡顯示的值
2.把IP Address控制元件裡的值轉化為CString格式
/*
//下面程式碼實現:把IP Address控制元件裡的值轉化為 CString格式
unsignedchar *pIP;
CStringstrIP;
DWORDdwIP;
m_IP.GetAddress(dwIP);// m_IP為IP Address控制元件對應的變數
pIP= (unsigned char*)&dwIP;
strIP.Format("%u.%u.%u.%u",*(pIP+3), *(pIP+2), *(pIP+1), *pIP);
MessageBox(strIP);*/
/*
//下面程式碼實現:把IP Address控制元件裡的值轉化為 CString格式
BYTEf0, f1, f2, f3;
m_IP.GetAddress(f0,f1, f2, f3);
CStringm_addr;
m_addr.Format("%d%s%d%s%d%s%d",f0, ".", f1, ".", f2, ".", f3);
MessageBox(m_addr);*/
/*
//下面程式碼實現:把IP Address控制元件裡的值轉化為 CString格式
BYTEIPByte[4];
m_IP.GetAddress(IPByte[0],IPByte[1], IPByte[2], IPByte[3]);
CStringstrIP = "";
chartemp1[10], temp2[10], temp3[10], temp4[10];
itoa(IPByte[0],temp1, 10);
itoa(IPByte[1],temp2, 10);
itoa(IPByte[2],temp3, 10);
itoa(IPByte[3],temp4, 10);
strIP+= temp1;
strIP+= ".";
strIP+= temp2;
strIP+= ".";
strIP+= temp3;
strIP+= ".";
strIP+= temp4;
MessageBox(strIP);*/
/*
//下面程式碼實現:把IP Address控制元件裡的值轉化為 CString格式
CStringstrx;
m_IP.GetWindowText(strx);
MessageBox(strx);*/
//此段程式碼:用獲取的IP地址值,顯示到對話方塊裡IP Address控制元件中
/*CString strIP;
GetDlgItemText(IDC_EDIT_IPAddress,strIP);
m_IP.SetWindowText(strIP);*/
m_IP.SetWindowText(ip);// 把IP地址(CString型別)直接顯示到IP Address控制元件中
UpdateData(FALSE);
}
3.從IP Address控制元件獲得IP地址,並交給程式(如socket中的connect函式)處理。
方法一:
//m_Ip為IP Address控制元件的變數名
m_Ip.GetAddress(IPByte[0],IPByte[1],IPByte[2],IPByte[3]); 獲得IP Address控制元件中的4部分數字
//------------------把IP地址轉化為字元
CString strI;="";
char temp1[10],temp2[10],temp3[10],temp4[10];
itoa(IPByte[0],temp1,10);
itoa(IPByte[1],temp2,10);
itoa(IPByte[2],temp3,10);
itoa(IPByte[3],temp4,10);
strIp+=temp1;
strIp+=".";
strIp+=temp2;
strIp+=".";
strIp+=temp3;
strIp+=".";
strIp+=temp4;
itoa函式介紹
定義在stdlib中的, _CRTIMP char * __cdecl _itoa(int, char *, int);
我看的原始碼中是這麼呼叫的:
_itoa(i,str3,10);
功能:把整形轉換為字元型別,
含義: i:需要轉換的整形
str3:字串緩衝區
10:十進位制方式
方法二(簡單):
m_IP.GetAddress(f0,f1,f2,f3);//m_IP是ip控制元件的控制變數
m_addr.Format("%d%s%d%s%d%s%d",f0,".",f1,".",f2,".",f3);
使用VC提供的Format函式,省去了整數轉化為字串的操作。
CustomControl
VC裡的Custom Control的使用很簡單,用滑鼠拖動到窗體上,然後設定其“Class”屬性為已註冊的視窗類,比哪Edit、Button等等。因為像Edit、Button等控制元件可以很容易的畫到窗體上,而對繼承於CWnd的自定義視窗類則沒有辦法直接用滑鼠畫到窗體上,這時Custom Control就用上了,只要類是使用RegisterClass註冊後就能被使用,如:
[cpp] viewplaincopy
WNDCLASSwc;
wc.lpszClassName= _T("MyWindow"); // matches class name in client
wc.hInstance =hInstance;
wc.lpfnWndProc =::DefWindowProc;
wc.hCursor =::LoadCursor(NULL, IDC_ARROW);
wc.hIcon =0;
wc.lpszMenuName= NULL;
wc.hbrBackground= (HBRUSH) ::GetStockObject(LTGRAY_BRUSH);
wc.style =CS_GLOBALCLASS; // To be modified
wc.cbClsExtra =0;
wc.cbWndExtra =0;
::RegisterClass(&wc)!= 0
這時儲存在CustomControl的Class屬性上輸入MyWindow後,程式執行正常。
其實我們可以不用這麼“麻煩”的來使用自定義類。只一個SubclassWindow就搞定了。使用方法:
1:定義我們需要類,比如從CWnd繼承一個新的類MyWindow、並編寫自己的程式碼實現。
2:在窗體上放任何一個控制元件(目的是使用這個控制元件的大小及位置),比如可以放一個Static在窗體上。為控制元件新增一個變數,變數型別為MyWindow,然後在程式碼的合適的地方(比如OnInitDialog)新增如下的程式碼就可以了:
[cpp] viewplaincopy
this->m_MyWindow.SubclassWindow(this->GetDlgItem(IDC_Static)->GetSafeHwnd());
直接執行程式,絕不會出現CustomControl那種執行不起來的現象。
MFCButton Control
SysLinkControl
MFC中有一個 SysLink Control 的控制元件,用於在 MFC 應用程式上新增超連結。下面說一下簡單的使用方法:
1、首先建立一個基於對話方塊的MFC工程,新增一個 Syslink Control 控制元件;
2、在該控制元件的 Caption 屬性裡新增帶 href 的錨定標記MFC<wbr>SysLink的使用方法
3、接著,為控制元件新增NM_CLICK 事件,在事件函式裡面新增如下:
voidCAesAboutDlg::OnNMClickSyslink3(NMHDR *pNMHDR, LRESULT *pResult)
{
PNMLINK pNMLink = (PNMLINK) pNMHDR;
if (wcscmp(pNMLink->item.szUrl,_T("http:\/\/weibo.com\/lisonglisong")) == 0)
{
// 主要執行語句
ShellExecuteW(NULL, L"open",pNMLink->item.szUrl, NULL, NULL, SW_SHOWNORMAL);
}
*pResult = 0;
}
注意,_T()中轉義字元的使用。
MFCColorButton Control
新增了一個到了一個對話方塊,試執行一下,發現效果不錯
可以選擇RGB所有的顏色,可以說功能很強大了,而且自動是彈出式的,這些功能的實現都不用編寫一行程式碼
可謂是十分方便
但悲催的是,搜尋這個控制元件的用法,是在少之又少,
唯一一個比較有效的還是一個著重討論改變這個控制元件外觀的.......
檢視MSDN幫助文件,滿眼英文,而且講得很少,幾乎沒起到什麼作用
經歷了一個半小時琢磨,終於自己弄出了一個很基礎功能的用法
----------------------------------------------------------------------------------------------------------------------------------------------
首先,該按鈕不是一個類,這是基本概念了,
設定一個變數,CMFCColorButton的例項,
1.在資源檢視右擊該控制元件
右擊新增變數
2.
3.切換到類檢視,在CPenDialog類中
[cpp] view plaincopy
- class CPenDialog : public CDialog
- {
- //.........................................
- public:
- // 顏色選擇的按鈕
- CMFCColorButton m_ColorPicker;
- };
多出這一行程式碼說明新增變數成功,這個
[cpp] view plaincopy
m_ColorPicker
已經關聯到那個顏色選擇控制元件了
4.在初始化對話方塊時初始化該控制元件
[cpp] view plaincopy
- BOOL CPenDialog::OnInitDialog()
- {
- CDialog::OnInitDialog();
- // TODO: 在此新增額外的初始化
- m_ColorPicker.EnableAutomaticButton(_T("目前"), m_SelectedColor);
- //m_ColorPicker.SetColor(m_SelectedColor);
- m_ColorPicker.EnableOtherButton(_T("其餘顏色"));
- m_ColorPicker.SetColor((COLORREF)-1);
- m_ColorPicker.SetColumnsNumber(5);
- return TRUE; // return TRUE unless you set the focus to a control
- // 異常: OCX 屬性頁應返回 FALSE
- }
5.獲取選擇的顏色
在類檢視中新增程式碼
voidCPenDialog::OnBnClickedMfccolorbutton1()
{
// TODO: 在此新增控制元件通知處理程式程式碼
m_SelectedColor = m_ColorPicker.GetColor();
}
m_SelectedColor是自己宣告的一個儲存選取顏色的變數
MFCEditBrowse Control
對映一個變數;然後設定他的文字即可;
控制元件變數m_Control.SetWindowTextA("C:\\Program Files");
如果是字串變數設定完需要用 UpdataData(False) 更新
m_stControl ="C:\\Program Files";
UpdataData(False);
MFC 使用MFC EditBrowse Control控制元件選擇檔案或者資料夾
從工具箱中拖拽一個MFC EditBrowse Control到窗體中,
通過設定“Browse Mode”屬性指定“檔案瀏覽”還是“資料夾瀏覽”
可以通過新增物件的方式將其與一個CString selectedPath物件關聯選擇的路徑。
也可以通過
CStringselectedPath;
GetDlgItemText(IDC_MFCEDITBROWSE1,selectedPath);
獲得選擇的檔案或者資料夾路徑
MFCVSListBox Control
一在資源視窗中,選中資源右鍵-》資源包括-》輸入如下程式碼
#ifndef_AFXDLL
#include"afxribbon.rc"
#endif
二新建一個基於對話方塊的專案
將工具箱中的MFCVSListBox Control直接拖到視窗中
利用嚮導為該控制元件繫結一個變數
CVSListBox m_List_ctlMain
嚮導自動新增標頭檔案
#include"afxvslistbox.h"
三增加輸入規則
1 刪除時,先彈出提示對話方塊,詢問使用者是否刪除
2 在新建和編輯List中的內容時,檢查是否存在重複內容
在微軟提供的例子中重寫關於按鈕的訊息
classCCustomEditListBox :public CVSListBox
{
virtual void OnBrowse()
{
int nSel = GetSelItem();
MessageBox(_T("Browse item..."));
if (nSel == GetCount()) // New item
{
nSel = AddItem(_T("New text"));
SelectItem(nSel);
}
else
{
SetItemText(nSel, _T("Updated text"));
}
}
};
標頭檔案和實現檔案放在一個檔案中
根據微軟提供的例子按照這種寫法進行仿寫
類的繼承關係
class CVSListBox:public CVSListBoxBase
class CVSListBoxBase:public CStatic
在CVSListBoxBase類中有
virtual BOOLOnBeforeRemoveItem(int/*iItem*/) { returnTRUE; }
新建一個繼承自CVSListBox的類CCustomEditListBox
以下程式碼實現刪除時,先彈出提示對話方塊,詢問使用者是否刪除
class CCustomEditListBox:public CVSListBox
{
protected:
BOOL OnBeforeRemoveItem(intnItem)
{
CString strText = GetItemText(nItem);
CString strPrompt=_T("");
strPrompt.Format(_T("確定要刪除【%s】嗎?"),strText);
if ( MessageBox(strPrompt,_T("提示"),MB_ICONQUESTION|MB_OKCANCEL)==IDOK)
{
return TRUE;
}
return FALSE;
}
};
以下程式碼實現在新建和編輯List中的內容時,檢查是否存在重複內容
classCCustomEditListBox :public CVSListBox
{
boolIsExist(CStringstrText)
{
for (int i=0;i<GetCount();i++)
{
CString strContent=GetItemText(i);
if (strContent == strText )
{
return true;//已經存在
}
}
return false;
}
voidSetItemText(int iIndex, const CString& strText)
{
if (IsExist(strText))
{
CString strPrompt=_T("");
strPrompt.Format(_T("【%s】已經存在"),strText);
AfxMessageBox(strPrompt);
EditItem(iIndex);
m_wndEdit.SetWindowText(strText);
m_wndEdit.SetSel(0,-1);//全選
// m_wndEdit.SetSel(-1);//游標處於文字的末端
return;
}
if (GetSafeHwnd() == NULL || m_pWndList ==NULL)
{
ASSERT(FALSE);
return;
}
ASSERT_VALID(m_pWndList);
m_pWndList->SetItemText(iIndex,0,strText);
}
};
程式碼中使用CVSListBox類中的成員變數
CListCtrl*m_pWndList;
CVSListBoxEditCtrl m_wndEdit;
還可以重寫其他事件
virtualvoid OnAfterAddItem(int/*iItem*/){}
virtualvoid OnAfterRenameItem(int/*iItem*/){}
virtualvoid OnAfterMoveItemUp(int/*iItem*/){}
virtualvoid OnAfterMoveItemDown(int/*iItem*/){}
如需其他功能例如多列,輸入掩碼,只允許輸入數字等等功能就需要對CListCtrl和CVSListBoxEditCtrl 進行擴充套件。
MFCMaskedEdit Control
成員
公共建構函式
名稱 |
說明 |
CMFCMaskedEdit::CMFCMaskedEdit |
預設建構函式。 |
CMFCMaskedEdit::~CMFCMaskedEdit |
解構函式。 |
公共方法
名稱 |
說明 |
驗證使用者輸入的禁用。 |
|
指定 GetWindowText 方法是否只檢索掩碼字元。 |
|
初始化掩碼編輯控制元件。 |
|
指定掩碼是編輯控制元件選擇使用者輸入的特定組,或者所有使用者輸入。 |
|
指定文字是否僅驗證掩碼字元,或者所有掩碼。 |
|
CMFCMaskedEdit::GetThisClass |
用於由框架獲取指向與此選件類型別的 CRuntimeClass 物件。 |
retrieves驗證起始於掩碼文字編輯控制元件。 |
|
指定使用者可以輸入有效字元的字串。 |
|
顯示在掩碼一個提示編輯控制元件。 |
受保護的方法
名稱 |
說明 |
呼叫由結構驗證指定的字元對應的掩碼字元。 |
備註
執行以下步驟使用 CMFCMaskedEdit 控制元件在您的應用程式:
1. 嵌入一 CMFCMaskedEdit 物件新增到windows選件類。
2. 呼叫 CMFCMaskedEdit::EnableMask 方法指定掩碼。
3. 呼叫 CMFCMaskedEdit::SetValidChars 方法指定有效字元列表。
4. 呼叫 CMFCMaskedEdit::SetWindowText 方法對掩碼指定預設文字編輯控制元件。
5. 呼叫 CMFCMaskedEdit::GetWindowText 方法檢索已驗證的文字。
如果不呼叫一個或多個方法初始化掩碼、有效字元和預設文字,掩碼編輯控制元件的行為就象標準編輯控制元件的行為。
示例
下面的示例演示如何設定mask (例如電話號碼)使用 EnableMask 方法建立掩碼遮蔽編輯控制元件,SetValidChars 方法指定使用者可以輸入有效字元的字串,並且,顯示在掩碼一個提示的 SetWindowText 方法編輯控制元件。 此示例是 新的控制元件示例的一部分。
C++
CMFCMaskedEdit m_wndMaskEdit1;
CMFCMaskedEdit m_wndMaskEdit2;
CMFCMaskedEdit m_wndMaskEdit3;
CMFCMaskedEdit m_wndMaskEdit4;
CMFCMaskedEdit m_wndMaskEdit5;
CString m_strValue1;
CString m_strValue2;
CString m_strValue3;
CString m_strValue4;
CString m_strValue5;
...
BOOL CPage4::OnInitDialog()
{
CMFCPropertyPage::OnInitDialog();
// Mask 1: phone number
m_wndMaskEdit1.EnableMask(_T(" ddd ddd dddd"), // The mask string
_T("(___) ___-____"), // Literal, "_" char = character entry
_T(' ')); // Default char
m_wndMaskEdit1.SetValidChars(NULL); // Valid string characters
m_wndMaskEdit1.SetWindowText(_T("(123) 123-1212"));
// Mask 2: State, Zip Code
m_wndMaskEdit2.EnableMask(_T(" cc ddddd-dddd"), // The mask string
_T("State: __, Zip: _____-____"), // Literal, "_" char = character entry
_T(' ')); // Backspace replace char
m_wndMaskEdit2.SetValidChars(NULL); // Valid string characters
m_wndMaskEdit2.SetWindowText(_T("State: NY, Zip: 12345-6789"));
// Mask 3: serial code
m_wndMaskEdit3.EnableMask(_T(" AAAA AAAA AAAA AAAA"), // The mask string
_T("S/N: ____-____-____-____"), // Literal, "_" char = character entry
_T('_')); // Backspace replace char
m_wndMaskEdit3.SetValidChars(NULL); // Valid string characters
m_wndMaskEdit3.SetWindowText(_T("S/N: FPR5-5678-1234-8765"));
// Mask 4: 0xFFFF
m_wndMaskEdit4.EnableMask(_T(" AAAA"), // The mask string
_T("0x____"), // Literal, "_" char = character entry
_T('_')); // Backspace replace char
m_wndMaskEdit4.SetValidChars(_T("1234567890ABCDEFabcdef")); // Valid string characters
m_wndMaskEdit4.SetWindowText(_T("0x01AF"));
// Mask 5: digits only
m_wndMaskEdit5.DisableMask(); // Don't use the mask
m_wndMaskEdit5.SetValidChars(_T("1234567890")); // Valid string characters
m_wndMaskEdit5.SetWindowText(_T("1234567890"));
return TRUE; // return TRUE unless you set the focus to a control
}
void CPage4::OnButtonGet()
{
m_wndMaskEdit1.GetWindowText(m_strValue1);
m_wndMaskEdit2.GetWindowText(m_strValue2);
m_wndMaskEdit3.GetWindowText(m_strValue3);
m_wndMaskEdit4.GetWindowText(m_strValue4);
m_wndMaskEdit5.GetWindowText(m_strValue5);
UpdateData(FALSE);
}
繼承層次結構
CObject
CCmdTarget
CWnd
CEdit
CMFCMaskedEdit
要求
標頭: afxmaskededit.h
MFCFontComboBox Control
CMFCFontComboBox
實現:
拖放該控制元件至對話方塊模板
初始化字型:
在OnInitialUpdate裡新增:
((CMFCFontComboBox*)GetDlgItem(IDC_MFCFONTCOMBO1))->SelectFont(_T("新宋體"));
處理單擊事件:
新增訊息原型:
afx_msg void OnCbnSelchangeMfcfontcombo1();
訊息對映:
ON_CBN_SELCHANGE(IDC_MFCFONTCOMBO1,&CToolView::OnCbnSelchangeMfcfontcombo1)
訊息實現:
void CToolView::OnCbnSelchangeMfcfontcombo1()
{
// TODO: 在此新增控制元件通知處理程式程式碼
CMFCFontInfo*pInfoFont;
pInfoFont=((CMFCFontComboBox*)GetDlgItem(IDC_MFCFONTCOMBO1))->GetSelFont();
CString str;
str=pInfoFont->m_strName;
AfxMessageBox(str);
}
MFCMenuButton Control
可以在按鈕上加上選單的功能,這樣用對話方塊就能實現選單欄的功能
1、準備工作:準備3個對話方塊,一個用於主視窗,ID為ID_MAIN_DIALOG,另外兩個用於選單的彈出,ID分別命名為ID_ONE_DIALOG,ID_TWO_DIALOG,為後兩個對話方塊新增類,類名為COneDlg和CTwoDlg
2、在主視窗上新增MFC MenuButton控制元件,為它新增一個變數:m_MenuButton
3、在資源部分加入一個選單資源,ID為IDR_MENU,設計好彈出選單樣式,為每個彈出選項設ID,這裡設為ID_ONE和ID_TWO
4、將MenuButton控制元件和上面的選單資源繫結,參考下面程式碼:
CMenu* pMenu =new CMenu;
pMenu->LoadMenu(IDR_MENU); // 載入選單資源
m_MenuButton.m_hMenu= pMenu->GetSubMenu(0)->GetSafeHmenu(); // 將CMFCMenuButton和Menu IDR_MENU1關聯
5、設定事件,這裡注意設定MenuButton的ON_CLICKED的訊息,而不是在選單選項那裡新增事件,在訊息函式中新增類似下面的程式碼即可(這裡的工作是彈出兩個對話方塊)
switch(m_settingMenu.m_nMenuResult)
{
case ID_ONE:
{
COneDlg oneDlg;
oneDlg.DoModal();
break;
}
case ID_TWO:
{
CTwoDlg twoDlg;
twoDlg.DoModal();
break;
}
default:
break;
}
MFCPropertyGrid Control
簡要分析
PropertyGrid, 做工具一定要用這東西.....
把要編輯的物件看成類的話, 所有要編輯的屬性就是成員
嗯嗯, 最近看了幾眼Ogitor, 它對於PropertyGrid的使用就很不錯
所有要編輯的物件(燈光, 模型, 粒子等等)都有一個共同的基類, 每當選中一個可編輯物件時, 右邊的屬性框裡就顯示出當前物件的屬性...(公司那個編輯器要多土就有多土-_-)
儘管Ribbon介面看起來很酷, 我還是對MFC提不起興趣來...
.net裡的PropertyGrid更方便, 一點一點來:
屬性自動繫結:
[cpp] view plaincopy
- ref class Human
- {
- public:
- Human()
- {
- this->Name = "(None)";
- this->Age = 0;
- this->IsMale = false;
- }
- property String^ Name;
- property int Age;
- property bool IsMale;
- };
只需要一句
[cpp] view plaincopy
- this->propertyGrid1->SelectedObject = gcnew Human();
它就能自動識別出Human類中的property, 並且自動關聯到PropertyGrid中:
對屬性進行分類並加註釋:
[cpp] view plaincopy
- ref class Human
- {
- public:
- Human()
- {
- this->Name = "(None)";
- this->Age = 0;
- this->IsMale = false;
- this->SkinColor = Color::Yellow;
- }
- [CategoryAttribute("常規"), DescriptionAttribute("名字")]
- property String^ Name;
- [CategoryAttribute("常規"), DescriptionAttribute("年齡")]
- property int Age;
- [CategoryAttribute("外觀"), DescriptionAttribute("性別")]
- property bool IsMale;
- [CategoryAttribute("外觀"), DescriptionAttribute("膚色")]
- property Color SkinColor;
- };
太爽啦~顏色自己就能識別........
弄個Image型別居然還能自己選擇檔案...NB啊
除了基本型別之外, Font, Size,Color等複雜型別也可以支援, 那麼自定義型別呢?
如果只是像上面那樣放上的話, 只會得到個灰色不可編輯的東西~
要想讓PropertyGrid能夠展開Vector3屬性, 指定一下TypeConverter就可以了:
[cpp] view plaincopy
- [TypeConverterAttribute(ExpandableObjectConverter::typeid)]
- ref struct Vector3
- {
- property float X;
- property float Y;
- property float Z;
- virtual String^ ToString() override
- {
- return String::Format("({0}, {1}, {2})", this->X, this->Y, this->Z);
- }
- };
對於列舉型別, PropertyGrid會自動顯示成下拉框. 把性別改成列舉看看:
[cpp] view plaincopy
- enum struct SexType
- {
- Male,
- Female
- };
另外, 還可以彈出自定義的編輯介面, 比如隨時間變化的曲線啦(經常用來做效果...)
這個, 暫時沒需求, 不實現了, 有興趣的參考:Getting the Most Out of the .NET FrameworkPropertyGrid Control
簡單教程
用vs2010建立一個基於對話方塊的MFC工程,拖一個CMFCPropertyGridCtrl進去,大小調整好。(注:首先採用的是靜態建立的辦法,大部分需要的屬性在對話方塊編輯介面就可以編輯。)然後為該控制元件更改ID為IDC_MFCPROPERTYGRID_TEST,並且使用ClassWizard為控制元件新增一個變數m_propertyGrid。
接下來更改控制元件的一些屬性。
其實這不就是個CMFCPropertyGridCtrl控制元件麼。Border神馬的基礎東西就不說了。
"DescriptionRows Count"指的是下面的描述部分有幾行。
"EnableDescription Area"表示是否啟動下面的描述功能
"EnableHeader"表示是否啟動表頭
"MarkModified Properties"表示是否著重顯示更改項
可以按照需求來進行設定。這裡先使用預設的設定。先編譯執行一下,比較簡陋。
好,接下來該新增東西進去了。
在OnInitDialog中新增如下程式碼,我會一行一行解釋。
1. CMFCPropertyGridProperty * pProp1 = new CMFCPropertyGridProperty(
2. _T("天朝適合生存嗎?"),
3. _T("51CTO不談政治"),
4. _T("這是描述部分"));
5.
6. m_propertyGrid.AddProperty(pProp1);
第一行是建立一個新的專案,也是最普通的專案,CMFCPropertyGridProperty。與這種專案同級的還有CMFCPropertyGridColorProperty、CMFCPropertyGridFontProperty以及CMFCPropertyGridFileProperty,等會都可以試一下。呼叫建構函式時傳入的三個引數分別是條目名稱、預設選項及描述文字。執行一下就知分曉。
餓滴神啊,腫麼這個樣子。不過該有的全有,只需要設定一下就行。這裡得提一筆,微軟似乎非常喜歡把第一列的寬度設定為“只能容得下一個普通的5號小宋體的寬度”,不光是CMFCPropertyGrid,連CListCtrl也是如此,需要動點特殊的手段才能調整過來。在這段程式碼的前面加這麼幾句:
1. HDITEM item;
2. item.cxy=120;
3. item.mask=HDI_WIDTH;
4. m_propertyGrid.GetHeaderCtrl().SetItem(0, new HDITEM(item));
如此再執行,就會比較好看了。
好,接下來我們看一下右邊的value部分還能換成神馬東西。
如同vs2010裡提供的“屬性”欄一樣,這CMFCPropertyGridCtrl應該也支援下拉選單,好,就來新增下拉選單看看。修改剛才的程式碼:
1. CMFCPropertyGridProperty* pProp2 = new CMFCPropertyGridProperty(
2. _T("我是不是帥哥?"),
3. _T("看選項"),
4. _T(""));
5. pProp2->AddOption(_T("是"));
6. pProp2->AddOption(_T("肯定是"));
7. pProp2->AddOption(_T("絕對是"));
8. pProp2->AllowEdit(FALSE); //不允許對選項進行編輯
9.
10. m_propertyGrid.AddProperty(pProp2);
然後執行,就會如願以償地出現下拉框了。
接下來是另外三個同級的專案:
1. CMFCPropertyGridColorProperty * pProp3 = new CMFCPropertyGridColorProperty(
2. _T("顏色"), RGB(0, 111, 200));
3. m_propertyGrid.AddProperty(pProp3);
4.
5. CMFCPropertyGridFileProperty * pProp4 = new CMFCPropertyGridFileProperty(
6. _T("開啟檔案"), TRUE, _T("D:\\test.txt"));
7. m_propertyGrid.AddProperty(pProp4);
8.
9. LOGFONT font = {NULL};
10. CMFCPropertyGridFontProperty * pProp5 = new CMFCPropertyGridFontProperty(
11. _T("選擇字型"), font);
12. m_propertyGrid.AddProperty(pProp5);
注:每一種型別的專案都有2個或3個過載函式,可以自己根據需求慢慢挖掘,在這裡就不贅述了。
執行效果如下:
這麼些不同種類的東西亂七八糟堆在一起,是不是有點不科學?那麼就引入下一個概念:分組。回到第一張圖,vs2010的“屬性”欄分了三個組,分別是Apperance、Behavior和Misc,看起來就清晰多了,我們也可以。
好,來重新構建一下我們的程式碼:
1. CMFCPropertyGridProperty * group1 = new CMFCPropertyGridProperty(_T("分組1"));
2. CMFCPropertyGridProperty * group2 = new CMFCPropertyGridProperty(_T("分組2"));
3.
4. group1->AddSubItem(pProp1);
5. group1->AddSubItem(pProp2);
6. group2->AddSubItem(pProp3);
7. group2->AddSubItem(pProp4);
8. group2->AddSubItem(pProp5);
9.
10. m_propertyGrid.AddProperty(group1);
11. m_propertyGrid.AddProperty(group2);
編譯執行效果如下:
至此,靜態建立CMFCPropertyGridCtrl的方法就結束了。
還有一種方法是動態建立,與CStatic、CEdit等控制元件無二,在建立之後也可以利用自帶的函式修改控制元件的屬性,如:
1. CMFCPropertyGridCtrl * propertyGrid = new CMFCPropertyGridCtrl;
2. propertyGrid->Create(WS_CHILD | WS_BORDER | WS_VISIBLE, CRect(400, 100, 600, 200), this, WM_USER + 100);
3. propertyGrid->EnableHeaderCtrl(TRUE); //使用表頭
4. propertyGrid->SetVSDotNetLook(); //使用樣式
5. propertyGrid->MarkModifiedProperties(); //著重顯示更改過的部分
例子分析
MFCPropertyGridCtrl
是VC 2008 pack中的類,實現瞭如下功能:
(1)介面分面兩欄:一欄為屬性,一欄為值
如這個圖
[cpp] view plaincopy
- virtual BOOL Create(DWORD dwStyle,const RECT& rect,CWnd* pParentWnd,UINT nID );
Parameters
[in] rect
A bounding rectangle that specifies the size and position of the window, in client coordinates of pParentWnd.
[in] pParentWnd
Pointer to the parent window. Must not be NULL.
Remarks
To create a property grid control, first call CMFCPropertyGridCtrl::CMFCPropertyGridCtrl to construct a property grid object. Then call CMFCPropertyGridCtrl::Create.
void EnableHeaderCtrl(BOOL bEnable=TRUE,LPCTSTR
lpszLeftColumn=_T("Property"),LPCTSTR lpszRightColumn=_T("Value") );
功能:是否顯示錶頭。
bEnable=TRUE顯示錶頭,如下圖
bEnable=FALSE,不顯示錶頭,如下圖
顯而易見,後兩個引數指定了表頭名。
void EnableDescriptionArea(BOOL bEnable=TRUE );
功能:是事啟用描述區
如下圖所示
參見例子
MFCFeaturePackSample/NewControls/Page5.cpp /BOOL CPage5::OnInitDialog()
可研究CMFCPropertyGridCtrl控制元件。理解vs2008後的MFC新介面系統。
主要CMFCPropertyGridCtrl 資料成員
m_ToolTip |
CToolTipCtrl |
Tooltip control |
|
m_wndHeader |
CMFCHeaderCtrl |
Property list header control |
如圖fig-11 |
m_IPToolTip |
CMFCPropertyGridToolTipCtrl |
Inplace tooltip control |
|
m_wndScrollVert |
CScrollBar |
Vertical scroll bar |
|
m_cListDelimeter |
TCHAR |
Customized list delimeter character |
|
m_rectList |
CRect |
Properies area |
|
m_lstProps |
|
List of top-level properties |
|
m_pSel |
CMFCPropertyGridProperty |
Current selection |
|
Custom colors |
|||
m_clrBackground |
|
|
|
m_clrText |
|
|
|
m_clrGroupBackground |
|
|
|
m_clrGroupText |
|
|
|
........................... |
|
|
|
功能:disable,雙擊,組disable
更改。
CMFCPropertyGridProperty由{name, value}組成。
介面繪製主要程式碼
[cpp] view plaincopy
- OnPaint()
- {
- OnFillBackground
- OnDrawList
- }
- void CMFCPropertyGridCtrl::OnFillBackground(CDC* pDC, CRect rectClient)
- {
- ......
- //CBrush m_brBackground;用指定好的畫刷繪製背景
- pDC->FillRect(rectClient, &m_brBackground);
- ......
- }
- }
- void CMFCPropertyGridCtrl::OnDrawList(CDC* pDC)
- {
- //畫中間的分隔線
- pDC->MoveTo(nXCenter, m_rectList.top - 1);
- pDC->LineTo(nXCenter, m_rectList.bottom);
- //得到屬性項的連結串列
- const CList<CMFCPropertyGridProperty*, CMFCPropertyGridProperty*>& lst = m_bAlphabeticMode ? m_lstTerminalProps : m_lstProps;
- for (POSITION pos = lst.GetHeadPosition(); pos != NULL;)
- {
- CMFCPropertyGridProperty* pProp = lst.GetNext(pos);
- //畫每個屬性項
- if (!OnDrawProperty(pDC, pProp))
- {
- break;
- }
- }
- }
- BOOL CMFCPropertyGridCtrl::OnDrawProperty(CDC* pDC, CMFCPropertyGridProperty* pProp) const
- {
- if (!pProp->IsEnabled())
- {
- clrTextOld = pDC->SetTextColor(afxGlobalData.clrGrayedText);
- }
- CRect rectName = pProp->m_Rect;
- CRgn rgnClipName;
- CRect rectNameClip = rectName;
- rectNameClip.bottom = min(rectNameClip.bottom, m_rectList.bottom);
- rgnClipName.CreateRectRgnIndirect(&rectNameClip);
- pDC->SelectClipRgn(&rgnClipName);
- pProp->OnDrawName(pDC, rectName);
- CRect rectValue = pProp->m_Rect;
- rectValue.left = nXCenter + 1;
- CRgn rgnClipVal;
- CRect rectValClip = rectValue;
- rectValClip.bottom = min(rectValClip.bottom, m_rectList.bottom);
- rgnClipVal.CreateRectRgnIndirect(&rectValClip);
- pDC->SelectClipRgn(&rgnClipVal);
- pProp->OnDrawValue(pDC, rectValue);
- }
- void CMFCPropertyGridProperty::OnDrawName(CDC* pDC, CRect rect)
- {
- int nTextHeight = pDC->DrawText(m_strName, rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS);
- //計算出文字是被截斷
- m_bNameIsTruncated = pDC->GetTextExtent(m_strName).cx > rect.Width();
- }
- void CMFCPropertyGridProperty::OnDrawValue(CDC* pDC, CRect rect)
- {
- CString strVal = FormatProperty();
- pDC->DrawText(strVal, rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS);
- }
- COLORREF m_clrLine; // Color of the grid lines
- BOOL m_bAlphabeticMode; // Use property list in alphabetic (non-"tree") mode
- 沒有皮膚這種概念。所有風格都靠程式碼畫出來。
- CMFCPropertyGridCtrl 程式碼特點。拆分成多個函式。每個函式的程式碼行數都少,可讀性強。
- The GetTextExtentPoint32 function computes the width and height of the specified string of text.
- ///////////////////////////////////////////////主要事件響應程式碼///////////////////////////////////////////////
- 左鍵單擊
- void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- {
- SetFocus();
- CRect rectClient;
- GetClientRect(rectClient);
- CMFCPropertyGridProperty::ClickArea clickArea;
- CMFCPropertyGridProperty* pHit = HitTest(point, &clickArea);
- //與當前的屬性項比較,不同則屬性項變更
- BOOL bSelChanged = pHit != GetCurSel();
- SetCurSel(pHit);
- if (pHit == NULL)
- {
- return;
- }
- switch (clickArea)
- {
- case CMFCPropertyGridProperty::ClickExpandBox:
- pHit->Expand(!pHit->IsExpanded()); //展開/收起子項
- break;
- case CMFCPropertyGridProperty::ClickName:
- pHit->OnClickName(point);
- break;
- case CMFCPropertyGridProperty::ClickValue:
- if (pHit->m_bEnabled)
- {
- if (EditItem(pHit, &point) && pHit->m_pWndInPlace != NULL)
- {
- if (pHit->m_rectButton.PtInRect(point))
- {
- CString strPrevVal = pHit->FormatProperty();
- if (::GetCapture() == GetSafeHwnd())
- {
- ReleaseCapture();
- }
- pHit->OnClickButton(point);
- if (strPrevVal != pHit->FormatProperty())
- {
- OnPropertyChanged(pHit);
- }
- }
- else if (!bSelChanged || pHit->IsProcessFirstClick())
- {
- pHit->OnClickValue(WM_LBUTTONDOWN, point);
- }
- }
- }
- break;
- default:
- break;
- }
- }
- //輸入滑鼠點,判斷滑鼠點在哪個屬性項的矩形邊界內,進而測試出滑鼠點下的屬性項。
- CMFCPropertyGridProperty* CMFCPropertyGridCtrl::HitTest(CPoint pt, CMFCPropertyGridProperty::ClickArea* pnArea, BOOL bPropsOnly) const
- {
- for (POSITION pos = lst.GetHeadPosition(); pos != NULL;)
- {
- CMFCPropertyGridProperty* pProp = lst.GetNext(pos);
- ASSERT_VALID(pProp);
- CMFCPropertyGridProperty* pHit = pProp->HitTest(pt, pnArea);
- if (pHit != NULL)
- {
- return pHit;
- }
- }
- }
- void CMFCPropertyGridCtrl::SetCurSel(CMFCPropertyGridProperty* pProp, BOOL bRedraw)
- {
- m_pSel = pProp;
- OnChangeSelection//是一個空的虛擬函式
- OnChangeSelection(m_pSel, pOldSelectedItem);
- if (pOldSelectedItem != NULL)
- {
- //CMFCPropertyGridProperty中的空的虛擬函式
- pOldSelectedItem->OnKillSelection(pProp);
- }
滑鼠單擊某項,編輯響應過程
[cpp] view plaincopy
- void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- {
- case CMFCPropertyGridProperty::ClickValue:
- if (pHit->m_bEnabled)
- {
- if (EditItem(pHit, &point) && pHit->m_pWndInPlace != NULL)
- }
- BOOL CMFCPropertyGridCtrl::EditItem(CMFCPropertyGridProperty* pProp, LPPOINT lptClick)
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pProp);
- if (!EndEditItem())
- {
- return FALSE;
- }
- if (pProp->IsGroup() && !pProp->m_bIsValueList)
- {
- return FALSE;
- }
- if (pProp->OnEdit(lptClick))
- {
- pProp->Redraw();
- SetCurSel(pProp);
- SetCapture();
- }
- return TRUE;
- }
- ////////////////////////////////////////////////////////
- CMFCPropertyGridProperty
- {
- BOOL m_bEnabled;//是否允許編輯
- CWnd* m_pWndInPlace; // Pointer to InPlace editing window
- CComboBox* m_pWndCombo; // Pointer to combbox
- CSpinButtonCtrl* m_pWndSpin; // Pointer to spin button
- CMFCPropertyGridCtrl* m_pWndList; // Pointer to the PropertyList window
- CMFCPropertyGridProperty* m_pParent; // Parent property (NULL for top-level properties)
- enum ClickArea
- {
- ClickExpandBox,
- ClickName,
- ClickValue,
- ClickDescription
- };
- };
禁止擴充套件
[cpp] view plaincopy
- void Expand(BOOL bExpand = TRUE);
- m_bEnabled
- void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- { switch (clickArea)
- {
- case CMFCPropertyGridProperty::ClickExpandBox:
- pHit->Expand(!pHit->IsExpanded());
- break;
- ..................................
- }
編輯完
[cpp] view plaincopy
- virtual BOOL CMFCPropertyGridProperty::OnEndEdit();
- ///////////////////////////////////雙擊////////////////////////////////////
- if (m_pSel->GetRect().PtInRect(point))
- {
- m_pSel->OnDblClk(point);
- }
出現編輯框
[cpp] view plaincopy
- void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- {
- if (EditItem(pHit, &point) && pHit->m_pWndInPlace != NULL)
- }
- BOOL CMFCPropertyGridCtrl::EditItem(CMFCPropertyGridProperty* pProp, LPPOINT lptClick)
- {
- if (pProp->OnEdit(lptClick))
- }
- BOOL CMFCPropertyGridProperty::OnEdit(LPPOINT /*lptClick*/)
- {
- m_pWndInPlace = CreateInPlaceEdit(rectEdit, bDefaultFormat);
- }
CMFCPropertyGridProperty子類
CCheckBoxProp
CPasswordProp
CSliderProp
CBoundedNumberPairProp
CBoundedNumberSubProp
CIconListProp
CComboBoxExProp
COwnerDrawDescrProp
CTwoButtonsProp
CCustomDlgProp
響應點選屬性項Combox框中的下拉項事件
[cpp] view plaincopy
- ON_CBN_SELENDOK(AFX_PROPLIST_ID_INPLACE, &CMFCPropertyGridCtrl::OnSelectCombo)
- void CMFCPropertyGridCtrl::OnSelectCombo()
- {
- ..............
- ASSERT_VALID(m_pSel);
- m_pSel->OnSelectCombo();
- }
- void CMFCPropertyGridProperty::OnSelectCombo()
- {
- ASSERT_VALID(this);
- ASSERT_VALID(m_pWndCombo);
- ASSERT_VALID(m_pWndInPlace);
- int iSelIndex = m_pWndCombo->GetCurSel();
- if (iSelIndex >= 0)
- {
- CString str;
- m_pWndCombo->GetLBText(iSelIndex, str);
- m_pWndInPlace->SetWindowText(str);
- OnUpdateValue();
- }
- }
CComboBox ClassA
Each message-map entry takes the following form:
ON_Notification( id, memberFxn )
where id specifies the child-window ID of the combo-box control sending the notification and memberFxn is the name of the parent member function you have written to handle the notification.
The parent's function prototype is as follows:
afx_msg void memberFxn( );
ON_CBN_SELENDOK The user selects an item and then either presses the ENTER key or clicks the DOWN ARROW key to hide the list box of a combo box. This notification message is sent before the CBN_CLOSEUP message to indicate that the user's selection should be considered valid. The CBN_SELENDCANCEL or CBN_SELENDOK notification message is sent even if the CBN_CLOSEUP notification message is not sent (as in the case of a combo box with the CBS_SIMPLE style).
例子程式
截圖
MFCShellList Control
DisplayFolder("C:\\");
MFCShellTree Control
VS2010新增加(相較於VC6)了一個CMFCShellTreeCtrl類,說實話,這個類確實很好,但是有一點你會發現,在展開某些節點的時候可能會很慢很慢。這嚴重影響了效率。為什麼呢?很長一段時間,一直百思不得其解!甚至抓狂!原來問題出現在一個很小的函式上。
HRESULT CMFCShellTreeCtrl::EnumObjects(HTREEITEM hParentItem, LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent)
{
ASSERT_VALID(this);
ASSERT_VALID(afxShellManager);
LPENUMIDLIST pEnum = NULL;
HRESULT hr = pParentFolder->EnumObjects(NULL, m_dwFlags, &pEnum);
if (FAILED(hr) || pEnum == NULL)
{
return hr;
}
LPITEMIDLIST pidlTemp;
DWORD dwFetched = 1;
// Enumerate the item's PIDLs:
while (SUCCEEDED(pEnum->Next(1, &pidlTemp, &dwFetched)) && dwFetched)
{
TVITEM tvItem;
ZeroMemory(&tvItem, sizeof(tvItem));
// Fill in the TV_ITEM structure for this item:
tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;
// AddRef the parent folder so it's pointer stays valid:
pParentFolder->AddRef();
// Put the private information in the lParam:
LPAFX_SHELLITEMINFO pItem = (LPAFX_SHELLITEMINFO)GlobalAlloc(GPTR, sizeof(AFX_SHELLITEMINFO));
ENSURE(pItem != NULL);
pItem->pidlRel = pidlTemp;
pItem->pidlFQ = afxShellManager->ConcatenateItem(pidlParent, pidlTemp);
pItem->pParentFolder = pParentFolder;
tvItem.lParam = (LPARAM)pItem;
CString strItem = OnGetItemText(pItem);
tvItem.pszText = strItem.GetBuffer(strItem.GetLength());
tvItem.iImage = OnGetItemIcon(pItem, FALSE);
tvItem.iSelectedImage = OnGetItemIcon(pItem, TRUE);
問題出現在這裡,接下來要檢查檔案的屬性,判斷是否有子資料夾。正常情況下我們其實是不需要這麼多屬性的,前兩個足夠了SFGAO_HASSUBFOLDER 和 SFGAO_FOLDER 。將後面的其他屬性全部遮蔽,再執行程式時,就會發現很快了。
// Determine if the item has children:
/*DWORD dwAttribs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DISPLAYATTRMASK | SFGAO_CANRENAME | SFGAO_FILESYSANCESTOR;*/
DWORD dwAttribs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER ;
pParentFolder->GetAttributesOf(1, (LPCITEMIDLIST*) &pidlTemp, &dwAttribs);
tvItem.cChildren = (dwAttribs & (SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR));
// Determine if the item is shared:
if (dwAttribs & SFGAO_SHARE)
{
tvItem.mask |= TVIF_STATE;
tvItem.stateMask |= TVIS_OVERLAYMASK;
tvItem.state |= INDEXTOOVERLAYMASK(1); //1 is the index for the shared overlay image
}
// Fill in the TV_INSERTSTRUCT structure for this item:
TVINSERTSTRUCT tvInsert;
tvInsert.item = tvItem;
tvInsert.hInsertAfter = TVI_LAST;
tvInsert.hParent = hParentItem;
InsertItem(&tvInsert);
dwFetched = 0;
}
pEnum->Release();
return S_OK;
}
2014/10/16 :今天有網友提問如何在MFC程式中使用CMFCShellTreeCtrl,其實很簡單。首先新建一個基於CMFCShellTreeCtrl的MFC類,然後將新建的類和控制元件繫結。CMFCShellTreeCtrl有幾個比較重要的虛擬函式:
/* 獲取Item的文字*/
virtual CString OnGetItemText(LPAFX_SHELLITEMINFOpItem);
/* 獲取Item的圖示 */
virtual intOnGetItemIcon(LPAFX_SHELLITEMINFO pItem, BOOL bSelected);
/* 列舉目錄下所有的檔案 */
virtual HRESULT EnumObjects(HTREEITEMhParentItem, LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent);
其中第3個函式就是上文提到的可以修改的函式。但是有一點需要注意的是,MFC框架內使用了一個全域性變數:
externCShellManager* afxShellManager;
這個變數並沒有被MFC框架匯出,所以在我們自己的原始碼中是不能引用這個變數的。解決這個問題也很簡單。
afxShellManager被定義在afxshellmanager.cpp檔案中,而且要求全域性範圍內只有一個變數。
CShellManager* afxShellManager = NULL;
CShellManager::CShellManager() {
// 實際上要求CShellManager在全域性範圍內只有一個變數
ENSURE(afxShellManager== NULL);
afxShellManager= this;
...
}
所以我們在MFC框架生成的App類的InitInstance函式中能夠看到:
CShellManager pShellManager = new CShellManager;
delete pShellManager;
我們只需要將此處區域性性質的pShellManager提高到全域性範圍內,然後在程式中使用它。
我們說使用它,不是說將所有使用afxShellManager變數的地方全部改為pShellManager,而是僅限於我們自己的專案程式碼,MFC框架的原始碼是不能被更改的,而且是不應被更改的。
MFCLink Control
MFCPropertyGrid Control
相關文章
- MFC NumericUpDown Spin控制元件 CSpinButtonCtrl控制元件
- QT控制元件大全QT控制元件
- MFC功能擴充套件控制元件BCGSuite for MFC釋出v27.1|附下載套件控制元件UI
- MFC---ActiveX控制元件程式設計基礎控制元件程式設計
- 基於vs2012開發activex(MFC)控制元件控制元件
- MFC——SkinMagic使用詳解
- Flutter 標籤類控制元件大全ChipFlutter控制元件
- C# Winform常用控制元件縮寫大全C#ORM控制元件
- OCX 控制元件主動傳送訊息給 MFC 視窗訊息控制元件
- MFC 之使用者登入介面
- pip使用大全
- mfc+最大最小化視窗+控制元件變化+圖片(視訊幀)顯示在控制元件上控制元件
- MFC打包
- 154 、MFC中使用者介面執行緒執行緒
- MFC: 檔案
- C#控制元件之Repeater控制元件使用C#控制元件
- MFC學習(五)
- 攻防世界-mfc逆向
- docker使用大全 tomcat安裝DockerTomcat
- Duilib的使用(優化MFC介面)之 配置專案屬性UI優化
- MFC訊息對映
- MFC程式設計(六)C程式程式設計
- MFC程式設計(一)C程式程式設計
- MFC程式設計(二)C程式程式設計
- MFC程式設計(三)C程式程式設計
- MFC程式設計(四)C程式程式設計
- MFC程式設計(五)C程式程式設計
- MFC 程式基本介面配置
- VS2017-快捷鍵使用大全
- Fastjson的基本使用方法大全ASTJSON
- lodop列印控制元件的使用控制元件
- ACCESS TreeView控制元件的使用View控制元件
- 工作自動化,替代手工操作,使用python操作MFC、windows程式PythonWindows
- MFC介面套包BCG Pro Edition for MFC正式釋出v27.3|附下載
- MFC介面套包BCGControlBar Pro Edition for MFC正式釋出v28.0|附下載GC
- 沒有找到MFC80UD.DLL"沒有找到MFC80UD.DLL,
- MFC介面開發類庫BCG Pro for MFC幫助文件:CBCGPEditCtrl的XML格式XML
- MFC框架軟體逆向研究框架
- linux命令大全-linux命令使用和管理Linux