MFC常用控件功能及用法

4.1 Button

按鈕窗口(控件)在MFC中使用CButton表示,CButton包含了三種樣式的按鈕,Push Button,Check Box,Radio Box。所以在利用CButton對象生成按鈕窗口時需要指明按鈕的風格。

創建按鈕:BOOL CButton::Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );其中lpszCaption是按鈕上顯示的文字,dwStyle爲按鈕風格,除了Windows風格可以使用外(如 WS_CHILD|WS_VISUBLE|WS_BORDER)還有按鈕專用的一些風格。

  • BS_AUTOCHECKBOX 檢查框,按鈕的狀態會自動改變   Same as a check box, except that a check mark appears in the check box when the user selects the box; the check mark disappears the next time the user selects the box.

  • BS_AUTORADIOBUTTON 圓形選擇按鈕,按鈕的狀態會自動改變   Same as a radio button, except that when the user selects it, the button automatically highlights itself and removes the selection from any other radio buttons with the same style in the same group.

  • BS_AUTO3STATE 允許按鈕有三種狀態即:選中,未選中,未定   Same as a three-state check box, except that the box changes its state when the user selects it.

  • BS_CHECKBOX 檢查框   Creates a small square that has text displayed to its right (unless this style is combined with the BS_LEFTTEXT style).

  • BS_DEFPUSHBUTTON 默認普通按鈕   Creates a button that has a heavy black border. The user can select this button by pressing the ENTER key. This style enables the user to quickly select the most likely option (the default option).

  • BS_LEFTTEXT 左對齊文字   When combined with a radio-button or check-box style, the text appears on the left side of the radio button or check box.

  • BS_OWNERDRAW 自繪按鈕   Creates an owner-drawn button. The framework calls the DrawItem member function when a visual aspect of the button has changed. This style must be set when using the CBitmapButton class.

  • BS_PUSHBUTTON 普通按鈕   Creates a pushbutton that posts a WM_COMMAND message to the owner window when the user selects the button.

  • BS_RADIOBUTTON 圓形選擇按鈕   Creates a small circle that has text displayed to its right (unless this style is combined with the BS_LEFTTEXT style). Radio buttons are usually used in groups of related but mutually exclusive choices.

  • BS_3STATE 允許按鈕有三種狀態即:選中,未選中,未定   Same as a check box, except that the box can be dimmed as well as checked. The dimmed state typically is used to show that a check box has been disabled.

rect爲窗口所佔據的矩形區域,pParentWnd爲父窗口指針,nID爲該窗口的ID值。

獲取/改變按鈕狀態:對於檢查按鈕和圓形按鈕可能有兩種狀態,選中和未選中,如果設置了BS_3STATE或BS_AUTO3STATE風格就可能出現第三種狀態:未定,這時按鈕顯示灰色。通過調用int CButton::GetCheck( ) 得到當前是否被選中,返回0:未選中,1:選中,2:未定。調用void CButton::SetCheck( int nCheck );設置當前選中狀態。

處理按鈕消息:要處理按鈕消息需要在父窗口中進行消息映射,映射宏爲ON_BN_CLICKED( id, memberFxn )id爲按鈕的ID值,就是創建時指定的nID值。處理函數原型爲afx_msg void memberFxn( );

4.2 Static Box

靜態文本控件的功能比較簡單,可作爲顯示字符串,圖標,位圖用。創建一個窗口可以使用成員函數:
BOOL CStatic::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle將指明該窗口的風格,除了子窗口常用的風格WS_CHILD,WS_VISIBLE外,你可以針對靜態控件指明專門的風格。

  • SS_CENTER,SS_LEFT,SS_RIGHT 指明字符顯示的對齊方式。
  • SS_GRAYRECT 顯示一個灰色的矩形
  • SS_NOPREFIX 如果指明該風格,對於字符&將直接顯示,否則&將作爲轉義符,&將不顯示而在其後的字符將有下劃線,如果需要直接顯示&必須使用&&表示。
  • SS_BITMAP 顯示位圖
  • SS_ICON 顯示圖標
  • SS_CENTERIMAGE 圖象居中顯示

控制顯示的文本利用成員函數SetWindowText/GetWindowText用於設置/得到當前顯示的文本。

控制顯示的圖標利用成員函數SetIcon/GetIcon用於設置/得到當前顯示的圖標。

控制顯示的位圖利用成員函數SetBitmap/GetBitmap用於設置/得到當前顯示的位圖。下面一段代碼演示如何創建一個顯示位圖的靜態窗口並設置位圖

CStatic* pstaDis=new CStatic; pstaDis->Create("",WS_CHILD|WS_VISIBLE|SS_BITMAP|SSCENTERIMAGE, CRect(0,0,40,40),pWnd,1); CBitmap bmpLoad; bmpLoad.LoadBitmap(IDB_TEST); pstaDis->SetBitmap(bmpLoad.Detach()); 

4.3 Edit Box

Edit窗口是用來接收用戶輸入最常用的一個控件。創建一個輸入窗口可以使用成員函數:
BOOL CEdit::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle將指明該窗口的風格,除了子窗口常用的風格WS_CHILD,WS_VISIBLE外,你可以針對輸入控件指明專門的風格。

  • ES_AUTOHSCROLL,ES_AUTOVSCROLL 指明輸入文字超出顯示範圍時自動滾動。
  • ES_CENTER,ES_LEFT,ES_RIGHT 指定對齊方式
  • ES_MULTILINE 是否允許多行輸入
  • ES_PASSWORD 是否爲密碼輸入框,如果指明該風格則輸入的文字顯示爲*
  • ES_READONLY 是否爲只讀
  • ES_UPPERCASE,ES_LOWERCASE 顯示大寫/小寫字符

控制顯示的文本利用成員函數SetWindowText/GetWindowText用於設置/得到當前顯示的文本。

通過GetLimitText/SetLimitText可以得到/設置在輸入框中輸入的字符數量。

由於在輸入時用戶可能選擇某一段文本,所以通過void CEdit::GetSel( int& nStartChar, int& nEndChar )得到用戶選擇的字符範圍,通過調用void CEdit::SetSel( int nStartChar, int nEndChar, BOOL bNoScroll = FALSE )可以設置當前選擇的文本範圍,如果指定nStartChar=0 nEndChar=-1則表示選中所有的文本。void ReplaceSel( LPCTSTR lpszNewText, BOOL bCanUndo = FALSE )可以將選中的文本替換爲指定的文字。

此外輸入框還有一些和剪貼板有關的功能,void Clear( );刪除選中的文本,void Copy( );可將選中的文本送入剪貼板,void Paste( );將剪貼板中內容插入到當前輸入框中光標位置,void Cut( );相當於Copy和Clear結合使用。

最後介紹一下輸入框幾種常用的消息映射宏:

  • ON_EN_CHANGE 輸入框中文字更新後產生
  • ON_EN_ERRSPACE 輸入框無法分配內存時產生
  • ON_EN_KILLFOCUS / ON_EN_SETFOCUS 在輸入框失去/得到輸入焦點時產生

使用以上幾種消息映射的方法爲定義原型如:afx_msg void memberFxn( );的函數,並且定義形式如ON_Notification( id, memberFxn )的消息映射。如果在對話框中使用輸入框,Class Wizard會自動列出相關的消息,並能自動產生消息映射代碼。

4.4 Scroll Bar

Scroll Bar一般不會單獨使用,因爲SpinCtrl可以取代滾動條的一部分作用,但是如果你需要自己生成派生窗口,滾動條還是會派上一些用場。創建一個滾動條可以使用成員函數: :
BOOL CEdit::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle將指明該窗口的風格,除了子窗口常用的風格WS_CHILD,WS_VISIBLE外,你可以針對滾動條指明專門的風格。

  • SBS_VERT 風格將創建一個垂直的滾動條。
  • SBS_HORZ 風格將創建一個水平的滾動條。

在創建滾動條後需要調用void SetScrollRange( int nMinPos, int nMaxPos, BOOL bRedraw = TRUE )設置滾動範圍,
int GetScrollPos( )/int SetScrollPos( )用來得到和設置當前滾動條的位置。

void ShowScrollBar( BOOL bShow = TRUE );用來顯示/隱藏滾動條。

BOOL EnableScrollBar( UINT nArrowFlags = ESB_ENABLE_BOTH )用來設置滾動條上箭頭是否爲允許狀態。nArrowFlags可取以下值:

  • ESB_ENABLE_BOTH 兩個箭頭都爲允許狀態
  • ESB_DISABLE_LTUP 上/左箭頭爲禁止狀態
  • ESB_DISABLE_RTDN 下/右箭頭爲禁止狀態
  • ESB_DISABLE_BOTH 兩個箭頭都爲禁止狀態

如果需要在滾動條位置被改變時得到通知,需要在父窗口中定義對消息WM_VSCROLL/WM_HSCROLL的映射。方法爲在父窗口類中重載
afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )/afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
所使用的消息映射宏爲:ON_WM_VSCROLL( ),ON_WM_HSCROLL( ),在映射宏中不需要指明滾動條的ID,因爲所有滾動條的滾動消息都由同樣的函數處理。在OnHScroll/OnVScroll的第三個參數會指明當前滾動條的指針。第一個參數表示滾動條上發生的動作,可取以下值:

  • SB_TOP/SB_BOTTOM 已滾動到頂/底部
  • SB_LINEUP/SB_LINEDOWN 向上/下滾動一行
  • SB_PAGEDOWN/SB_PAGEUP 向上/下滾動一頁
  • SB_THUMBPOSITION/SB_THUMBTRACK 滾動條拖動到某一位置,參數nPos指明當前位置(參數nPos在其它的情況下是無效的)
  • SB_ENDSCROLL 滾動條拖動完成(用戶鬆開鼠標)

4.5 List Box/Check List Box

ListBox窗口用來列出一系列的文本,每條文本佔一行。創建一個列表窗口可以使用成員函數:
BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle將指明該窗口的風格,除了子窗口常用的風格WS_CHILD,WS_VISIBLE外,你可以針對列表控件指明專門的風格。

  • LBS_MULTIPLESEL 指明列表框可以同時選擇多行
  • LBS_EXTENDEDSEL 可以通過按下Shift/Ctrl鍵選擇多行
  • LBS_SORT 所有的行按照字母順序進行排序

在列表框生成後需要向其中加入或是刪除行,可以利用:
int AddString( LPCTSTR lpszItem )添加行,
int DeleteString( UINT nIndex )刪除指定行,
int InsertString( int nIndex, LPCTSTR lpszItem )將行插入到指定位置。
void ResetContent( )可以刪除列表框中所有行。
通過調用int GetCount( )得到當前列表框中行的數量。

如果需要得到/設置當前被選中的行,可以調用int GetCurSel( )/int SetCurSel(int iIndex)。如果你指明瞭選擇多行的風格,你就需要先調用int GetSelCount( )得到被選中的行的數量,然後int GetSelItems( int nMaxItems, LPINT rgIndex )得到所有選中的行,參數rgIndex爲存放被選中行的數組。通過調用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框內指定行的字符串。

此外通過調用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在當前所有行中查找指定的字符傳的位置,nStartAfter指明從那一行開始進行查找。
int SelectString( int nStartAfter, LPCTSTR lpszItem )可以選中包含指定字符串的行。

在MFC 4.2版本中添加了CCheckListBox類,該類是由CListBox派生並擁有CListBox的所有功能,不同的是可以在每行前加上一個檢查框。必須注意的是在創建時必須指明LBS_OWNERDRAWFIXED或LBS_OWNERDRAWVARIABLE風格。

通過void SetCheckStyle( UINT nStyle )/UINT GetCheckStyle( )可以設置/得到檢查框的風格,關於檢查框風格可以參考4.1 Button中介紹。通過void SetCheck( int nIndex, int nCheck )/int GetCheck( int nIndex )可以設置和得到某行的檢查狀態,關於檢查框狀態可以參考4.1 Button中介紹。

最後介紹一下列表框幾種常用的消息映射宏:

  • ON_LBN_DBLCLK 鼠標雙擊
  • ON_EN_ERRSPACE 輸入框無法分配內存時產生
  • ON_EN_KILLFOCUS / ON_EN_SETFOCUS 在輸入框失去/得到輸入焦點時產生
  • ON_LBN_SELCHANGE 選擇的行發生改變

使用以上幾種消息映射的方法爲定義原型如:afx_msg void memberFxn( );的函數,並且定義形式如ON_Notification( id, memberFxn )的消息映射。如果在對話框中使用列表框,Class Wizard會自動列出相關的消息,並能自動產生消息映射代碼。

4.6 Combo Box/Combo Box Ex

組合窗口是由一個輸入框和一個列表框組成。創建一個組合窗口可以使用成員函數:
BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle將指明該窗口的風格,除了子窗口常用的風格WS_CHILD,WS_VISIBLE外,你可以針對列表控件指明專門的風格。

  • CBS_DROPDOWN 下拉式組合框
  • CBS_DROPDOWNLIST 下拉式組合框,但是輸入框內不能進行輸入
  • CBS_SIMPLE 輸入框和列表框同時被顯示
  • LBS_SORT 所有的行按照字母順序進行排序

由於組合框內包含了列表框,所以列表框的功能都能夠使用,如可以利用:
int AddString( LPCTSTR lpszItem )添加行,
int DeleteString( UINT nIndex )刪除指定行,
int InsertString( int nIndex, LPCTSTR lpszItem )將行插入到指定位置。
void ResetContent( )可以刪除列表框中所有行。
通過調用int GetCount( )得到當前列表框中行的數量。

如果需要得到/設置當前被選中的行的位置,可以調用int GetCurSel( )/int SetCurSel(int iIndex)。通過調用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框內指定行的字符串。

此外通過調用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在當前所有行中查找指定的字符傳的位置,nStartAfter指明從那一行開始進行查找。
int SelectString( int nStartAfter, LPCTSTR lpszItem )可以選中包含指定字符串的行。

此外輸入框的功能都能夠使用,如可以利用:
DWORD GetEditSel( ) /BOOL SetEditSel( int nStartChar, int nEndChar )得到或設置輸入框中被選中的字符位置。
BOOL LimitText( int nMaxChars )設置輸入框中可輸入的最大字符數。
輸入框的剪貼板功能Copy,Clear,Cut,Paste動可以使用。

最後介紹一下列表框幾種常用的消息映射宏:

  • ON_CBN_DBLCLK 鼠標雙擊
  • ON_CBN_DROPDOWN 列表框被彈出
  • ON_CBN_KILLFOCUS / ON_CBN_SETFOCUS 在輸入框失去/得到輸入焦點時產生
  • ON_CBN_SELCHANGE 列表框中選擇的行發生改變
  • ON_CBN_EDITUPDATE 輸入框中內容被更新

使用以上幾種消息映射的方法爲定義原型如:afx_msg void memberFxn( );的函數,並且定義形式如ON_Notification( id, memberFxn )的消息映射。如果在對話框中使用組合框,Class Wizard會自動列出相關的消息,並能自動產生消息映射代碼。

4.7 Tree Ctrl

樹形控件TreeCtrl和下節要講的列表控件 ListCtrl在系統中大量被使用,例如Windows資源管理器就是一個典型的例子。

樹形控件可以用於樹形的結構,其中有一個根接點(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結點只有一個,既不可以添加也不可以刪除)利用
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一個結點,pszItem爲顯示的字符,hParent代表父結點的句柄,當前添加的結點會排在hInsertAfter表示的結點的後面,返回值爲當前創建的結點的句柄。下面的代碼會建立一個如下形式的樹形結構:

+--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3 /*假設m_tree爲一個CTreeCtrl對象,而且該窗口已經創建*/ HTREEITEM hItem,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中圖片爲準。然後調用
HTREEITEM InsertItem( 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還提供了一些函數用於得到/修改控件的狀態。
HTREEITEM GetSelectedItem( );將返回當前選中的結點的句柄。BOOL SelectItem( HTREEITEM hItem );將選中指明結點。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用於得到/修改某結點所使用圖標索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用於得到/修改某一結點的顯示字符。
BOOL DeleteItem( HTREEITEM hItem );用於刪除某一結點,BOOL DeleteAllItems( );將刪除所有結點。

此外如果想遍歷樹可以使用下面的函數:
HTREEITEM GetRootItem( );得到根結點。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子結點。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結點的上/下一個兄弟結點。
HTREEITEM GetParentItem( 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 ); //處理消息 void CParentWnd::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 void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.lParam==0);//判斷是否取消該操作 *pResult = 1; else *pResult = 0; } //處理消息 TVN_BEGINLABELEDIT void CParentWnd::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的所有消息都需要在父窗口中處理)。

4.8 List Ctrl

列表控件可以看作是功能增強的ListBox,它提供了四種風格,而且可以同時顯示一列的多中屬性值。MFC中使用CListCtrl類來封裝列表控件的各種操作。通過調用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );創建一個窗口,dwStyle中可以使用以下一些列表控件的專用風格:

  • LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT 這四種風格決定控件的外觀,同時只可以選擇其中一種,分別對應:大圖標顯示,小圖標顯示,列表顯示,詳細報表顯示

  • LVS_EDITLABELS 結點的顯示字符可以被編輯,對於報表風格來講可編輯的只爲第一列。

  • LVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點

  • LVS_SINGLESEL 同時只能選中列表中一項

首先你需要設置列表控件所使用的ImageList,如果你使用大圖標顯示風格,你就需要以如下形式調用:
CImageList* SetImageList( CImageList* pImageList, LVSIL_NORMAL);
如果使用其它三種風格顯示而不想顯示圖標你可以不進行任何設置,否則需要以如下形式調用:
CImageList* SetImageList( CImageList* pImageList, LVSIL_SMALL);

通過調用 int InsertItem( int nItem, LPCTSTR lpszItem );可以在列表控件中nItem指明位置插入一項,lpszItem爲顯示字符。除LVS_REPORT風格外其他三種風格都只需要直接調用 InsertItem就可以了,但如果使用報表風格就必須先設置列表控件中的列信息。

通過調用 int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat , int nWidth, int nSubItem);可以插入列。iCol爲列的位置,從零開始,lpszColumnHeading爲顯示的列名,nFormat爲顯示對齊方式, nWidth爲顯示寬度,nSubItem爲分配給該列的列索引。

在有多列的列表控件中就需要爲每一項指明其在每一列中的顯示字符,通過調用
BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText );可以設置每列的顯示字符。nItem爲設置的項的位置,nSubItem爲列位置,lpszText爲顯示字符。下面的代碼演示瞭如何設置多列並插入數據:

m_list.SetImageList(&m_listSmall,LVSIL_SMALL);//設置ImageList m_list.InsertColumn(0,"Col 1",LVCFMT_LEFT,300,0);//設置列 m_list.InsertColumn(1,"Col 2",LVCFMT_LEFT,300,1); m_list.InsertColumn(2,"Col 3",LVCFMT_LEFT,300,2); m_list.InsertItem(0,"Item 1_1");//插入行 m_list.SetItemText(0,1,"Item 1_2");//設置該行的不同列的顯示字符 m_list.SetItemText(0,2,"Item 1_3"); 

此外CListCtrl還提供了一些函數用於得到/修改控件的狀態。
COLORREF GetTextColor( )/BOOL SetTextColor( COLORREF cr );用於得到/設置顯示的字符顏色。
COLORREF GetTextBkColor( )/BOOL SetTextBkColor( COLORREF cr );用於得到/設置顯示的背景顏色。
void SetItemCount( int iCount );用於得到添加進列表中項的數量。
BOOL DeleteItem(int nItem);用於刪除某一項,BOOL DeleteAllItems( );將刪除所有項。
BOOL SetBkImage(HBITMAP hbm, BOOL fTile , int xOffsetPercent, int yOffsetPercent);用於設置背景位圖。
CString GetItemText( int nItem, int nSubItem );用於得到某項的顯示字符。

列表控件的消息映射同樣使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode爲通知代碼,id爲產生該消息的窗口ID,memberFxn爲處理函數,函數的原型如同void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR爲一數據結構,在具體使用時需要轉換成其他類型的結構。對於列表控件可能取值和對應的數據結構爲:

  • LVN_BEGINLABELEDIT 在開始某項編輯字符時發送,所用結構:NMLVDISPINFO

  • LVN_ENDLABELEDIT 在結束某項編輯字符時發送,所用結構:NMLVDISPINFO

  • LVN_GETDISPINFO 在需要得到某項信息時發送,(如得到某項的顯示字符)所用結構:NMLVDISPINFO

關於ON_NOTIFY有很多內容,將在以後的內容中進行詳細講解。

關於動態提供結點所顯示的字符:首先你在項時需要指明lpszItem參數爲:LPSTR_TEXTCALLBACK。在控件顯示該結點時會通過發送 TVN_GETDISPINFO來取得所需要的字符,在處理該消息時先將參數pNMHDR轉換爲LPNMLVDISPINFO,然後填充其中 item.pszText。通過item中的iItem,iSubItem可以知道當前顯示的爲那一項。下面的代碼演示了這種方法:

char szOut[8][3]={"No.1","No.2","No.3"}; //添加結點 m_list.InsertItem(LPSTR_TEXTCALLBACK,...) m_list.InsertItem(LPSTR_TEXTCALLBACK,...) //處理消息 void CParentWnd::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; pLVDI->item.pszText=szOut[pTVDI->item.iItem]; //通過iItem得到需要顯示的字符在數組中的位置 *pResult = 0; } 

關於編輯某項的顯示字符:(在報表風格中只對第一列有效)首先需要設置列表控件的LVS_EDITLABELS風格,在開始編輯時該控件將會發送 LVN_BEGINLABELEDIT,你可以通過在處理函數中返回TRUE來取消接下來的編輯,在編輯完成後會發送LVN_ENDLABELEDIT,在處理該消息時需要將參數pNMHDR轉換爲LPNMLVDISPINFO,然後通過其中的item.pszText得到編輯後的字符,並重置顯示字符。如果編輯在中途中取消該變量爲NULL。下面的代碼說明如何處理這些消息:

//處理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.iItem==0);//判斷是否取消該操作 *pResult = 1; else *pResult = 0; } //處理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.pszText==NULL);//判斷是否已經取消取消編輯 m_list.SetItemText(pLVDI->item.iItem,0,pLVDI->pszText); //重置顯示字符 *pResult = 0; } 

上面講述的方法所進行的消息映射必須在父窗口中進行(同樣WM_NOTIFY的所有消息都需要在父窗口中處理)。

如何得到當前選中項位置:在列表控件中沒有一個類似於ListBox中GetCurSel()的函數,但是可以通過調用GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);得到選中項位置。

4.9 Tab Ctrl

Tab屬性頁控件可以在一個窗口中添加不同的頁面,然後在頁選擇發生改變時得到通知。MFC中使用CTabCtrl類來封裝屬性頁控件的各種操作。通過調用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );創建一個窗口,dwStyle中可以使用以下一些屬性頁控件的專用風格:

TCS_BUTTONS 使用按鈕來表示頁選擇位置
TCS_MULTILINE 分行顯示頁選擇位置
TCS_SINGLELINE 只使用一行顯示頁選擇位置
在控件創建後必需向其中添加頁面纔可以使用,添加頁面的函數爲:
BOOL InsertItem( int nItem, LPCTSTR lpszItem );nItem爲位置,從零開始,lpszItem爲頁選擇位置上顯示的文字。如果你希望在頁選擇位置處顯示一個圖標,你可以調用
BOOL InsertItem( int nItem, LPCTSTR lpszItem, int nImage );nImage指明所使用的圖片位置。(在此之前必須調用CImageList * SetImageList( CImageList * pImageList );設置正確的ImageList)

此外CTabCtrl還提供了一些函數用於得到/修改控件的狀態。
int GetCurSel( )/int SetCurSel( int nItem );用於得到/設置當前被選中的頁位置。
BOOL DeleteItem( int nItem )/BOOL DeleteAllItems( );用於刪除指定/所有頁面。
void RemoveImage( int nImage );用於刪除某頁選擇位置上的圖標。

屬性頁控件的消息映射同樣使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode爲通知代碼,id爲產生該消息的窗口ID,memberFxn爲處理函數,函數的原型如同void OnXXXTab(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR爲一數據結構,在具體使用時需要轉換成其他類型的結構。對於列表控件可能取值和對應的數據結構爲:

TCN_SELCHANGE 在當前頁改變後發送,所用結構:NMHDR
TCN_SELCHANGING 在當前頁改變時發送可以通過返回TRUE來禁止頁面的改變,所用結構:NMHDR

一般來講在當前頁發生改變時需要隱藏當前的一些子窗口,並顯示其它的子窗口。下面的僞代碼演示瞭如何使用屬性頁控件:

CParentWnd::OnCreate(...)
{
m_tab.Create(...);
m_tab.InsertItem(0,"Option 1");
m_tab.InsertItem(1,"Option 2");
Create a edit box as the m_tab's Child
Create a static box as the m_tab's Child
edit_box.ShowWindow(SW_SHOW); // edit box在屬性頁的第一頁
static_box.ShowWindow(SW_HIDE); // static box在屬性頁的第二頁
}
void CParentWnd::OnSelectChangeTab(NMHDR* pNMHDR, LRESULT* pResult)
{//處理頁選擇改變後的消息
if(m_tab.GetCurSel()==0)
{//根據當前頁顯示/隱藏不同的子窗口
edit_box.ShowWindow(SW_SHOW);
static_box.ShowWindow(SW_HIDE);
}
else
{//
edit_box.ShowWindow(SW_HIDE);
static_box.ShowWindow(SW_SHOW);
}
}

 

4.A Tool Bar

工具條也是常用的控件。MFC中使用CToolBar類來封裝工具條控件的各種操作。通過調用
BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR );創建一個窗口,dwStyle中可以使用以下一些工具條控件的專用風格:

  • CBRS_TOP 工具條在父窗口的頂部

  • TCBRS_BOTTOM 工具條在父窗口的底部

  • CBRS_FLOATING 工具條是浮動的

創建一個工具條的步驟如下:先使用Create創建窗口,然後使用BOOL LoadToolBar( LPCTSTR lpszResourceName );直接從資源中裝入工具條,或者通過裝入位圖並指明每個按鈕的ID,具體代碼如下:

UINT uID[5]={IDM_1,IDM_2,IDM_3,IDM_4,IDM_5}; m_toolbar.Create(pParentWnd); m_toolbar.LoadBitmap(IDB_TOOLBAR); m_toolbar.SetSizes(CSize(20,20),CSize(16,16));//設置按鈕大尺寸和按鈕上位圖的尺寸 m_toolbar.SetButtons(uID,5); 

AppWizard在生成代碼時也會同時生成工具條的代碼,同時還可以支持停靠功能。所以一般是不需要直接操作工具條對象。

工具條上的按鈕被按下時發送給父窗口的消息和菜單消息相同,所以可以使用ON_COMMAND宏進行映射,同樣工具條中的按鈕也支持 ON_UPDATE_COMMAND_UI的相關操作,如SetCheck,Enable,你可以將按鈕的當作菜單上的一個具有相同ID菜單項。

在以後的章節4.D 利用AppWizard創建並使用ToolBar StatusBar Dialog Bar會給出使用的方法。

4.B Status Bar

狀態條用於顯示一些提示字符。MFC中使用CStatusBar類來封裝狀態條控件的各種操作。通過調用
BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR );創建一個窗口,dwStyle中可以使用以下一些狀態條控件的專用風格:

  • CBRS_TOP 狀態條在父窗口的頂部

  • TCBRS_BOTTOM 狀態條在父窗口的底部

創建一個狀態條的步驟如下:先使用Create創建窗口,然後調用BOOL SetIndicators( const UINT* lpIDArray, int nIDCount );設置狀態條上各部分的ID,具體代碼如下:

UINT uID[2]={ID_SEPARATOR,ID_INDICATOR_CAPS}; m_stabar.Create(pParentWnd); m_stabar.SetIndicators(uID,2); 

通過CString GetPaneText( int nIndex )/BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE )可以得到/設置狀態條上顯示的文字。

Tip:在創建狀態條時最好將狀態條中所有的部分ID(除MFC自定義的幾個用於狀態條的ID外)都設置爲ID_SEPARATOR,在生成後調用
void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );改變其風格,ID和寬度。

AppWizard在生成代碼時也會同時生成狀態條的代碼。所以一般是不需要直接創建狀態條對象。此外狀態條上會自動顯示菜單上的命令提示(必須先在資源中定義),所以也不需要人爲設置顯示文字。

狀態條支持ON_UPDATE_COMMAND_UI的相關操作,如SetText,Enable。

在以後的章節4.D 利用AppWizard創建並使用ToolBar StatusBar Dialog Bar會給出使用的方法。

4.C Dialog Bar

Dialog Bar類似一個靜態的附在框架窗口上的對話框,由於Dialog Bar可以使用資源編輯器進行編輯所以使用起來就很方便,在設計時就可以對Dialog Bar上的子窗口進行定位。用於顯示一些提示字符。MFC中使用CDialogBar類來Dialog Bar控件的各種操作。通過調用
BOOL Create( CWnd* pParentWnd, UINT nIDTemplate, UINT nStyle, UINT nID );創建一個窗口,nIDTemplate爲對話框資源,nID爲該Dialog Bar對應的窗口ID,nStyle中可以使用以下一些狀態條控件的專用風格:

  • CBRS_TOP Dialog Bar在父窗口的頂部
  • TCBRS_BOTTOM Dialog Bar在父窗口的底部
  • CBRS_LEFT Dialog Bar在父窗口的左部
  • CBRS_RIGHT Dialog Bar在父窗口的右部

對於Dialog Bar的所產生消息需要在父窗口中進行映射和處理,例如Dialog Bar上的按鈕,需要在父窗口中進行ON_BN_CLICKED或ON_COMMAND映射,Dialog Bar上的輸入框可以在父窗口中進行ON_EN_CHANGE,ON_EN_MAXTEXT等輸入框對應的映射。

Dialog Bar支持ON_UPDATE_COMMAND_UI的相關操作,如SetText,Enable。

在以後的章節4.D 利用AppWizard創建並使用ToolBar StatusBar Dialog Bar會給出使用的方法

4.D 利用AppWizard創建並使用ToolBar StatusBar Dialog Bar

運行時程序界面如界面圖,該程序擁有一個工具條用於顯示兩個命令按鈕,一個用於演示如何使按鈕處於檢查狀態,另一個根據第一個按鈕的狀態來禁止/允許自身。(設置檢查狀態和允許狀態都通過OnUpdateCommand實現)此外Dialog Bar上有一個輸入框和按鈕,這兩個子窗口的禁止/允許同樣是根據工具條上的按鈕狀態來確定,當按下Dialog Bar上的按鈕時將顯示輸入框中的文字內容。狀態條的第一部分用於顯示各種提示,第二部分用於利用OnUpdateCommand顯示當前時間。同時在程序中演示瞭如何設置菜單項的命令解釋字符(將在狀態條的第一部分顯示)和如何設置工具條的提示字符(利用一個小的ToolTip窗口顯示)。

生成應用:利用AppWizard生成一個MFC工程,圖例,並設置爲單文檔界面圖例,最後選擇工具條,狀態條和ReBar支持,圖例

修改菜單:利用資源編輯器刪除多餘的菜單並添加一個新的彈出菜單和三個子菜單,圖例,分別是:

名稱

ID

說明字符

Check

IDM_CHECK

SetCheck Demo\nSetCheck Demo

Disable

IDM_DISABLE

Disable Demo\nDisable Demo

ShowText on DialogBar

IDM_SHOW_TXT

ShowText on DialogBar Demo\nShowText on DialogBar

\n前的字符串將顯示在狀態條中作爲命令解釋,\n後的部分將作爲具有相同ID的工具條按鈕的提示顯示在ToolTip窗口中。

修改 Dialog Bar:在Dialog Bar中添加一個輸入框和按鈕,按鈕的ID爲IDM_SHOW_TXT與一個菜單項具有相同的ID,這樣可以利用映射菜單消息來處理按鈕消息(當然使用不同ID值也可以利用ON_COMMAND來映射Dialog Bar上的按鈕消息,但是ClassWizard沒有提供爲Dialog Bar上按鈕進行映射的途徑,只能手工添加消息映射代碼)。圖例

修改工具條:在工具條中添加兩個按鈕,ID值爲IDM_CHECK和IDM_DISABLE和其中兩個菜單項具有相同的ID值。圖例

利用ClassWizard爲三個菜單項添加消息映射和更新命令。圖例

修改MainFrm.h文件

//添加一個成員變量來記錄工具條上Check按鈕的檢查狀態。 protected: BOOL m_fCheck; //手工添加狀態條第二部分用於顯示時間的更新命令,和用於禁止/允許輸入框的更新命令 //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnCheck(); afx_msg void OnUpdateCheck(CCmdUI* pCmdUI); afx_msg void OnDisable(); afx_msg void OnUpdateDisable(CCmdUI* pCmdUI); afx_msg void OnShowTxt(); afx_msg void OnUpdateShowTxt(CCmdUI* pCmdUI); //}}AFX_MSG //上面的部分爲ClassWizard自動產生的代碼 afx_msg void OnUpdateTime(CCmdUI* pCmdUI); //顯示時間 afx_msg void OnUpdateInput(CCmdUI* pCmdUI); //禁止/允許輸入框 

修改MainFrm.cpp文件

//修改狀態條上各部分ID #define ID_TIME 0x705 //作爲狀態條上第二部分ID static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_SEPARATOR, //先設置爲ID_SEPARATOR,在狀態條創建後再進行修改 }; //修改消息映射 //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(IDM_CHECK, OnCheck) ON_UPDATE_COMMAND_UI(IDM_CHECK, OnUpdateCheck) ON_COMMAND(IDM_DISABLE, OnDisable) ON_UPDATE_COMMAND_UI(IDM_DISABLE, OnUpdateDisable) ON_COMMAND(IDM_SHOW_TXT, OnShowTxt) ON_UPDATE_COMMAND_UI(IDM_SHOW_TXT, OnUpdateShowTxt) //}}AFX_MSG_MAP //以上部分爲ClassWizard自動生成代碼 ON_UPDATE_COMMAND_UI(ID_TIME, OnUpdateTime) ////顯示時間 ON_UPDATE_COMMAND_UI(IDC_INPUT_TEST, OnUpdateInput) //禁止/允許輸入框 //修改OnCreate函數,重新設置狀態條第二部分ID值 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { .... // by wenyy 修改狀態條上第二部分信息 m_wndStatusBar.SetPaneInfo(1,ID_TIME,SBPS_NORMAL,60);//set the width return 0; } //修改經過映射的消息處理函數代碼 void CMainFrame::OnCheck() { //在Check按鈕被按下時改變並保存狀態 m_fCheck=!m_fCheck; } void CMainFrame::OnUpdateCheck(CCmdUI* pCmdUI) { //Check按鈕是否設置爲檢查狀態 pCmdUI->SetCheck(m_fCheck); } void CMainFrame::OnDisable() { //Disable按鈕被按下 AfxMessageBox("you press disable test"); } void CMainFrame::OnUpdateDisable(CCmdUI* pCmdUI) { //根據Check狀態決定自身禁止/允許狀態 pCmdUI->Enable(m_fCheck); } void CMainFrame::OnShowTxt() { //得到Dialog Bar上輸入框中文字並顯示 CEdit* pE=(CEdit*)m_wndDlgBar.GetDlgItem(IDC_INPUT_TEST); CString szO; pE->GetWindowText(szO); AfxMessageBox(szO); } void CMainFrame::OnUpdateShowTxt(CCmdUI* pCmdUI) { //Dialog Bar上按鈕根據Check狀態決定自身禁止/允許狀態 pCmdUI->Enable(m_fCheck); } void CMainFrame::OnUpdateInput(CCmdUI* pCmdUI) { //Dialog Bar上輸入框根據Check狀態決定自身禁止/允許狀態 pCmdUI->Enable(m_fCheck); } void CMainFrame::OnUpdateTime(CCmdUI* pCmdUI) { //根據當前時間設置狀態條上第二部分文字 CTime timeCur=CTime::GetCurrentTime(); char szOut[20]; sprintf( szOut, "%02d:%02d:%02d", timeCur.GetHour(), timeCur.GetMinute(),timeCur.GetSecond()); pCmdUI->SetText(szOut); } 

下載演示代碼 17K

4.E General Window

從VC提供的MFC類派生圖中我們可以看出窗口的派生關係,派生圖,所有的窗口類都是由CWnd派生。所有CWnd的成員函數在其派生類中都可以使用。本節介紹一些常用的功能給大家。

改變窗口狀態:
BOOL EnableWindow( BOOL bEnable = TRUE );可以設置窗口的禁止/允許狀態。BOOL IsWindowEnabled( );可以查詢窗口的禁止/允許狀態。
BOOL ModifyStyle( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )/BOOL ModifyStyleEx( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 );可以修改窗口的風格,而不需要調用SetWindowLong
BOOL IsWindowVisible( ) 可以檢查窗口是否被顯示。
BOOL ShowWindow( int nCmdShow );將改變窗口的顯示狀態,nCmdShow可取如下值:

  • SW_HIDE 隱藏窗口
  • SW_MINIMIZE SW_SHOWMAXIMIZED 最小化窗口
  • SW_RESTORE 恢復窗口
  • SW_SHOW 顯示窗口
  • SW_SHOWMINIMIZED 最大化窗口

改變窗口位置:
void MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );可以移動窗口。
void GetWindowRect( LPRECT lpRect ) ;可以得到窗口的矩形位置。
BOOL IsIconic( ) ;可以檢測窗口是否已經縮爲圖標。
BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );可以改變窗口的Z次序,此外還可以移動窗口位置。

使窗口失效,印發重繪:
void Invalidate( BOOL bErase = TRUE );使整個窗口失效,bErase將決定窗口是否產生重繪。
void InvalidateRect( LPCRECT lpRect, BOOL bErase = TRUE )/void InvalidateRgn( CRgn* pRgn, BOOL bErase = TRUE );將使指定的矩形/多邊形區域失效。

窗口查找:
static CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );可以以窗口的類名和窗口名查找窗口。任一參數設置爲NULL表對該參數代表的數據進行任意匹配。如FindWindow("MyWnd",NULL) 表明查找類名爲MyWnd的所有窗口。
BOOL IsChild( const CWnd* pWnd ) 檢測窗口是否爲子窗口。
CWnd* GetParent( ) 得到父窗口指針。
CWnd* GetDlgItem( int nID ) 通過子窗口ID得到窗口指針。
int GetDlgCtrlID( ) 得到窗口ID值。
static CWnd* PASCAL WindowFromPoint( POINT point );將從屏幕上某點座標得到包含該點的窗口指針。
static CWnd* PASCAL FromHandle( HWND hWnd );通過HWND構造一個CWnd*指針,但該指針在空閒時會被刪除,所以不能保存供以後使用。

時鐘:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );可以創建一個時鐘,如果lpfnTimer回調函數爲NULL,窗口將會收到WM_TIMER消息,並可以在afx_msg void OnTimer( UINT nIDEvent );中安排處理代碼
BOOL KillTimer( int nIDEvent );刪除一個指定時鐘。

可以利用重載來添加消息處理的虛函數:
afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );窗口被創建時被調用
afx_msg void OnDestroy( );窗口被銷燬時被調用
afx_msg void OnGetMinMaxInfo( MINMAXINFO FAR* lpMMI );需要得到窗口尺寸時被調用
afx_msg void OnSize( UINT nType, int cx, int cy );窗口改變大小後被調用
afx_msg void OnMove( int x, int y );窗口被移動後時被調用
afx_msg void OnPaint( );窗口需要重繪時時被調用,你可以填如繪圖代碼,對於視圖類不需要重載OnPaint,所有繪圖代碼應該在OnDraw中進行
afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );接收到字符輸入時被調用
afx_msg void OnKeyDown/OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags );鍵盤上鍵被按下/放開時被調用
afx_msg void OnLButtonDown/OnRButtonDown( UINT nFlags, CPoint point );鼠標左/右鍵按下時被調用
afx_msg void OnLButtonUp/OnRButtonUp( UINT nFlags, CPoint point );鼠標左/右鍵放開時被調用
afx_msg void OnLButtonDblClk/OnRButtonDblClk( UINT nFlags, CPoint point );鼠標左/右鍵雙擊時被調用
afx_msg void OnMouseMove( UINT nFlags, CPoint point );鼠標在窗口上移動時被調用

4.F 關於WM_NOTIFY的使用方法

WM_NOTIF在WIN32中得到大量的應用,同時也是隨着CommControl的出現 WM_NOTIFY成爲了CommControl的基本消息。可以這樣說CommControl的所有的新增特性都通過WM_NOTIFY來表達。同時 WM_NOTIFY也爲CommControl的操作帶來了一致性。

WM_NOTIFY消息中的參數如下:
idCtrl = (int) wParam;
pnmh = (LPNMHDR) lParam; 其中lParam爲一個

typedef struct tagNMHDR
{
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR; 結構指針
從消息的參數我們已經可以分辯出消息的來源,但是這些信息還不足以分辯出消息的具體含義。所以我們需要更多的數據來得到更多的信息。MS的做法是對每種不同用途的通知消息都定義另一種結構來表示,同時這中結構裏包含了struct tagNMHDR,所以你只要進行一下類型轉換就可以得到數據指針。例如對於LVN_COLUMNCLICK消息(用於在ListCtrl的列表頭有鼠標點擊是進行通知),結構爲;
typedef struct tagNMLISTVIEW{
NMHDR hdr;
int iItem;
int iSubItem;
UINT uNewState;
UINT uOldState;
UINT uChanged;
POINT ptAction;
LPARAM lParam;
} NMLISTVIEW, FAR *LPNMLISTVIEW;

在這個結構的最開始也就包含了struct tagNMHDR,所以在不損失數據和產生錯誤的情況下向處理消息的進程提供了更多的信息。

此外通過WM_NOTIFY我們可以一種完全一樣的方式進行消息映射,如同在前幾章中所見到的一樣。
使用如下形式:ON_NOTIFY( wNotifyCode, id, memberFxn )。
處理函數也有統一的原型:afx_msg void memberFxn( NMHDR * pNotifyStruct, LRESULT * result );
在MFC消息映射的內部將根據定義消息映射時所使用的wNotifyCode和WM_NOTIFY中參數中pnmh->code(pnmh = (LPNMHDR) lParam)進行匹配,然後調用相應的處理函數。

還有一點是利用WM_NOTIFY/ON_NOTIFY_REFLECT可以在窗口內部處理一些消息,從而建立可重用的控件。

發佈了34 篇原創文章 · 獲贊 7 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章