VC++60 第十六章 VC++開發工具和MFC基礎類庫(二)
16.2 MFC類庫的基本控件
1 基本控件
基本控件是WINDOWS V3.1就開始使用的控件,也就是本書前面各章逐一介紹的那些控件。它們是最基本的最常用的,主要有按鈕、靜態正文、編輯框、單選按鈕和複選框(英文名Check,有人翻譯爲檢查框)、列表框、組合框、組框(Group)、垂直和水平的滾動條,它們大部分在圖chap16-05的工具窗口的前三行。
每個控件都包括ID和標題這兩個屬性,其它屬性則因控件而異,所有屬性分三類——Genaral,Styles and Extended Styles。要設計控件屬性用右鍵點擊控件即可,你可以打開屬性窗口一一考察和試驗,我們不可能一一枚舉。下面擇要介紹編輯框的屬性和消息映射。
圖chap16-06是編輯框的屬性對話框的Styles頁。其中,Multiline複選框選中表示創建的是多行編輯框,否則是單行編輯框,那時還可屬性對話框的Styles頁以選中Password選項。複選框Want return被選中表示能夠接受回車鍵,否則,在編輯框中打回車鍵後就自動退出應用程序。選中Want return時必須選定一個按鈕爲默認按鈕,打回車鍵後就自動執行那默認按鈕的響應函數。一般地,創建對話框時系統提供的[OK]按鈕就是默認按鈕,你可以按需要改動。NUmber複選框用來設置“限制輸入爲數字”。Align組合框用來選定文本對齊方式。屬性對話框的其餘兩頁沒有什麼特殊的地方。
編輯框能夠向父窗口發出的控件通知消息鍵下表,其中EN_CHANGE和EN_UPDATE是兩個最重要的。EN_CHANGE消息是是在編輯框顯示的正文被刷新後才發出的。而EN_UPDATE消息是在準備顯示改變了的正文時發送的。EN_CHANGE的消息映射函數爲OnChangeXXXX,EN_UPDATE的消息映射函數爲OnUpdateXXXX。
消息 |
含義 |
EN_CHANGE |
編輯框的內容被用戶改變了。與EN_UPDATE不同,該消息是在編輯框顯示的正文被刷新後才發出的。 |
EN_ERRSPACE |
編輯框控件無法申請足夠的動態內存來滿足需要。 |
EN_HSCROLL |
用戶在水平滾動條上單擊鼠標。 |
EN_KILLFOCUS |
編輯框失去輸入焦點。 |
EN_MAXTEXT |
輸入的字符超過了規定的最大字符數。在沒有ES_AUTOHSCROLL 或 ES_AUTOVSCROLL的編輯框中,當正文超出了編輯框的邊框時也會發出該消息。 |
EN_SETFOCUS |
編輯框獲得輸入焦點。 |
EN_UPDATE |
在編輯框準備顯示改變了的正文時發送該消息。 |
EN_VSCROLL |
用戶在垂直滾動條上單擊鼠標。 |
編輯框控件與剪切板有關的成員函數有:
void Copy(), void Cut(), void Paste(), void Clear(), BOOL Undo()。
在編輯框中獲得和設置文本要使用CWnd的成員函數
void GetWindowText( CString& rString ) const;
void SetWindowText( LPCTSTR lpszString );
CEdit的成員函數還有:
獲得所選正文的位置
DWORD GetSel( ) const;
void GetSel( int& nStartChar, int& nEndChar ) const;
多行編輯框,返回指定字符索引所在行的行索引
int LineFromChar( int nIndex = –1 ) const;
用於多行編輯框,獲得指定行的開頭字符的字符索引
int LineIndex( int nLine = –1 ) const;
用於多行編輯框,獲得正文的行數
int GetLineCount( ) const;
獲取指定字符索引所在行的長度
int LineLength( int nLine = –1 ) const;
用於多行編輯框,用來獲得指定行的正文
int GetLine( int nIndex, LPTSTR lpszBuffer ) const;
int GetLine( int nIndex, LPTSTR lpszBuffer, int nMaxLength ) const;
選擇編輯框中的正文,參數dwSelection的低位字說明了選擇開始處的字符索引,高位字說明了選擇結束處的字符索引。
void SetSel( DWORD dwSelection, BOOL bNoScroll = FALSE );
void SetSel( int nStartChar, int nEndChar, BOOL bNoScroll = FALSE );
用來將所選正文替換成指定的正文
void ReplaceSel( LPCTSTR lpszNewText, BOOL bCanUndo = FALSE );
可以利用LineIndex和LineFromChar來在字符索引和字符的行列座標之間相互轉換.下列代碼演示了在已知字符索引的情況下,如何獲得對應的行列座標:
int row,column;
row=MyEdit.LineFromChar(charIndex);
column=charIndex-MyEdit.LineIndex(row);
下列代碼演示了在已知字符的行列座標的情況下,如何獲得對應的字符索引:
int charIndex;
charIndex=MyEdit.LineIndex(row)+column;
不難看出字符索引與對應的行列座標的關係是:
列座標=字符索引-LineIndex(行座標)
字符索引=LineIndex(行座標)+列座標
2 Win32新控件
從Windows 95開始,Windows提供了一些先進的Win32控件.這些新控件彌補了傳統控件的某些不足之處,並使Windows的界面豐富多彩且更加友好。大概是當時計算機的字長已經從16位擴展到了32位的緣故吧,所以它們稱爲Win32控件。
較之傳統的Windows 3.x控件,新的Win32控件更加複雜和先進.在新控件發送通知消息的同時,往往還需要附加一些數據來描述控件的狀態.傳統的WM_COMMAND消息通知機制顯然不能完成這一任務,因爲WM_COMMAND消息的wParam和lParam已經被佔滿了,無法容納新的數據。在Win32中,採用新的WM_NOTIFY消息來實現新控件的消息通知機制.在該消息的wParam中含有控件的ID,lParam中則有一個指針,這個指針指向一個結構.這個結構是NMHDR結構,或者是一個以NMHDR結構作爲第一個成員的擴充結構。下表給出了新的Win32控件及其功能和控件類。
控件名 |
功能 |
對應的控件類 |
動畫(Animate) |
可播放avi文件. |
CAnimateCtrl |
熱鍵(Hot Key) |
使用戶能選擇熱鍵組合. |
CHotKeyCtrl |
列表視圖(List View) |
能夠以列表、小圖標、大圖標或報告格式顯示數據. |
CListCtrl |
進度條(Progress Bar) |
用於指示進度. |
CProgressCtrl |
滑尺(Slider) |
也叫軌道條(Trackbar),用戶可以移動滑尺來在某一範圍中進行選擇. |
CSliderCtrl |
旋轉按鈕(Spin Button) |
有時被稱爲上下控件.有一對箭頭按鈕,用來調節某一值的大小. |
CSpinButtonCtrl |
標籤(Tab) |
用來作爲標籤使用. |
CTabCtrl |
樹形視圖(Tree View) |
以樹狀結構顯示數據. |
CTreeCtrl |
傳統控件和Win32 控件採用了不同的通知消息機制,下表給出了新的Win32控件共有的通知消息。
通知消息碼 |
含義 |
NM_CLICK |
用戶在控件上單擊鼠標左鍵. |
NM_DBLCLK |
用戶在控件上雙擊鼠標左鍵. |
NM_RCLICK |
用戶在控件上單擊鼠標右鍵. |
NM_RDBLCLK |
用戶在控件上雙擊鼠標右鍵. |
NM_RETURN |
用戶在控件上按回車鍵. |
NM_SETFOCUS |
控件獲得輸入焦點. |
NM_KILLFOCUS |
控件失去輸入焦點. |
NM_OUTOFMEMORY |
內存不夠. |
這些新的Win32控件的設計和使用的方法和技巧是本書下一冊要研究的對象。
3 菜單和公用對話框
1) 菜單
在第四章中我們詳細介紹了在對話框中添加菜單的設計過程。而文檔模式下菜單是可以由系統自動生成的,而修改菜單的方法是一樣的,其屬性窗口中主要有如下內容:
屬性“選中的”使菜單項在開始時置爲選中狀態,這主要用於該菜單設置爲帶BOOL值的情況。屬性“非激活”使該菜單項是不活動的,即鼠標點上去是無效的。“變灰”屬性則使該菜單的外觀變灰色,即無效色,同時屬性“非激活”自動被設定。如果您選中“彈出”選項,那它就成了一個彈出式子菜單,如圖08所示。
如果菜單標題有中文去不能正確顯示,那一定是菜單的語言屬性設置爲英文了。在工作區的資源頁中右擊該菜單,在快捷菜單中選“屬性\語言”, 把它設置爲簡體中文就行了。
如果要給窗口添加一個快捷菜單,那就需要打開VC++的菜單項“工程/添加到工程”;從中選擇Compoents and Contorls;在對話框中選擇Visual C++ Components;在組件對話框中選擇POP_UP MENU組件,點擊[Ineart]按鈕;此時彈出的對話框要您選擇快捷菜單是添加到哪個窗口上的;最後點[結束]按鈕就OK了。快捷菜單項的屬性和命令函數等的設計和普通菜單一樣。
2) 公用對話框
公用對話框是指文件對話框、字體、顏色、查找和替換以及打印對話框,他們是VC++封裝好了的MFC的公用對話框。公用對話框的創建過程與一般對話框類似,首先是在堆棧上構建一個CFileDialog對象,然後調用DoModal()來啓動對話框。
(1) 文件對話框
文件對話框CFileDialog類用於文件的打開和保存操作。首先是在堆棧上構建一個CFileDialog對象,然後調用CFileDialog::DoModal函數來啓動對話框。文件對話框的構造函數爲
CFileDialog( BOOL bOpenFileDialog,
LPCTSTR lpszDefExt = NULL,
LPCTSTR lpszFileName = NULL,
DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL );
如果參數bOpenFileDialog的值爲TRUE,將創建Open(打開文件)對話框,否則就創建Save As(保存文件)對話框。參數lpszDefExt用來指定缺省的文件擴展名。lpszFileName用於規定初始文件名。dwFlags用於設置對話框的一些屬性。lpszFilter指向一個過濾字符串,用戶如果只想選擇某種或某幾種類型的文件,就需要指定過濾字符串。參數pParentWnd是指向父窗口或擁有者窗口的指針。
過濾字符串有特定的格式,它實際上是由多個子串組成,每個子串由兩部分組成,第一部分是過濾器的字面說明,如“Text file (*.txt)”,第二部分是用於過濾的匹配字符串,如“*.txt”,子串的兩部分用豎線字符“ | ”分隔開。各子串之間也要用“ | ”分隔,且整個串的最後兩個字符必須是兩個連續的豎線字符“ || ”。一個典型的過濾字符串如下面所示:
char szFilter[]=“All files (*.*)|*.*|Text files(*.txt)|*.txt|Word documents(*.doc)|*.doc||”;
若CFileDialog::DoModal返回的是IDOK,那麼可以用下表列出的CFileDialog類的成員函數來獲取相關的文件信息。
函數名 |
用途 |
GetPathName |
返回一個包含有全路徑文件名的CString對象。 |
GetFileName |
返回一個包含有文件名(不含路徑)的CString對象。 |
GetFileExt |
返回一個只含文件擴展名的CString對象。 |
GetFileTitle |
返回一個只含文件名(不含擴展名)的CString對象。 |
(2)字體對話框
字體對話框CFontDialog類的構造函數如下所示
CFontDialog( LPLOGFONT lplfInitial = NULL,
DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
CDC* pdcPrinter = NULL,
CWnd* pParentWnd = NULL );
參數lplfInitial指向一個LOGFONG結構,用來初始化對話框中的字體設置。dwFlags用於設置對話框。pdcPrinter指向一個代表打印機的CDC對象,若設置該參數,則選擇的字體就爲打印機所用。pParentWnd用於指定對話框的父窗口或擁有者窗口。若DoModal返回IDOK,那麼可以調用CFontDialog的下列成員函數來獲得所選字體的信息。
函數名 |
用途 |
GetCurrentFont |
用來獲得所選字體的屬性。該函數有一個參數,該參數是指向LOGFONT結構的指針,函數將所選字體的各種屬性寫入這個LOGFONT結構中。 |
GetFaceName |
返回一個包含所選字體名字的CString對象。 |
GetStyleName |
返回一個包含所選字體風格名字的CString對象。 |
GetSize |
返回所選字體的尺寸(以10個象素爲單位)。 |
GetColor |
返回一個含有所選字體的顏色的COLORREF型值。 |
GetWeight |
返回所選字體的權值。 |
IsStrikeOut |
若用戶選擇了空心效果則返回TRUE,否則返回FALSE。 |
IsUnderline |
若用戶選擇了下劃線效果則返回TRUE,否則返回FALSE。 |
IsBold |
若用戶選擇了黑體風格則返回TRUE,否則返回FALSE。 |
IsItalic |
若用戶選擇了斜體風格則返回TRUE,否則返回FALSE。 |
(3)顏色對話框
顏色對話框CColorDialog的構造函數爲
CColorDialog( COLORREF clrInit = 0,
DWORD dwFlags = 0,
CWnd* pParentWnd = NULL );
參數clrInit用來指定初始的顏色選擇,dwFlags用來設置對話框,pParentWnd用於指定對話框的父窗口或擁有者窗口。根據DoModal返回的是IDOK還是IDCANCEL可知道用戶是否確認了對顏色的選擇。DoModal返回後,調用CColorDialog::GetColor()可以返回一個COLORREF類型的結果來指示在對話框中選擇的顏色。COLORREF是一個32位的值,用來說明一個RGB顏色。GetColor返回的COLORREF的格式是0x00bbggrr,即低位三個字節分別包含了藍、綠、紅三種顏色的強度。
(4)打印對話框
打印對話框CPrintDialog類的構造函數:
CPrintDialog( BOOL bPrintSetupOnly,
DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS |
IDEPRINTTOFILE |
PD_NOSELECTION,
CWnd* pParentWnd = NULL );
參數bPrintSetupOnly的值若爲TRUE,則創建的是Print對話框,否則,創建的是Print Setup對話框。dwFlags用來設置對話框,缺省設置是打印出全部頁,禁止From和To編輯框(即不用確定要打印的頁的範圍),PD_USEDEVMODECOPIES使對話框判斷打印設備是否支持多份拷貝和校對打印(Collate),若不支持,就禁止相應的編輯控件和Collate檢查框。pParentWnd用來指定對話框的父窗口或擁有者窗口。程序可以調用CPrintDialog的成員函數來獲得打印參數。
函數名 |
用途 |
GetCopies |
返回要求的拷貝數。 |
GetDefaults |
在不打開對話框的情況下返回缺省打印機的缺省設置,返回的設置放在m_pd數據成員中。 |
GetDeviceName |
返回一個包含有打印機設備名的CString對象。 |
GetDevMode |
返回一個指向DEVMODE結構的指針,用來查詢打印機的設備初始化信息和設備環境信息。 |
GetDriverName |
返回一個包含有打印機驅動程序名的CString對象。 |
GetFromPage |
返回打印範圍的起始頁碼。 |
GetToPage |
返回打印範圍的結束頁碼。 |
GetPortName |
返回一個包含有打印機端口名的CString對象。 |
GetPrinterDC |
返回所選打印設備的一個 HDC 句柄。 |
PrintAll |
若要打印文檔的所有頁則返回TRUE。 |
PrintCollate |
若用戶選擇了Collate Copies檢查框(需要校對打印拷貝)則返回TRUE。 |
PrintRange |
如果用戶要打印文檔的一部分頁,則返回TRUE。 |
PrintSelection |
若用戶想打印當前選擇的部分文檔,則返回TRUE。 |
(5)查找和替換對話框
查找替換對話框CFindReplaceDialog類用於實現Find(搜索)和Replace(替換)對話框,由於Find和Replace對話框這兩個對話框都是非模式對話框,它們的創建方式與其它四類公用對話框不同。CFindReplaceDialog對象是用new操作符在堆中創建的,而不是象普通對話框那樣以變量的形式創建。要啓動Find/Replace對話框,應該調用CFindReplaceDialog::Create函數,而不是DoModal。Create函數的聲明是
BOOL Create( BOOL bFindDialogOnly,
LPCTSTR lpszFindWhat,
LPCTSTR lpszReplaceWith = NULL,
DWORD dwFlags = FR_DOWN,
CWnd* pParentWnd = NULL );
當參數bFindDialogOnly的值爲TRUE時,創建的是Find對話框,爲FALSE時創建的是Replace對話框。參數lpszFindWhat指定了要搜索的字符串,lpszReplaceWith指定了用於替換的字符串。dwFlags用來設置對話框,其缺省值是FR_DOWN(向下搜索),該參數可以是幾個FR_XXX常量的組合,用戶可以通過該參數來決定諸如是否要顯示Match case、Match Whole Word檢查框等設置。參數pParentWnd指明瞭對話框的父窗口或擁有者窗口。
Find/Replace對話框與其它公用對話框的另一個不同之處在於它在工作過程中可以重複同一操作而對話框不被關閉,這就方便了頻繁的搜索和替換。CFindReplaceDialog類只提供了一個界面,它並不會自動實現搜索和替換功能。CFindReplaceDialog使用了一種特殊的通知機制,當用戶按下了操作的按鈕後,它會向父窗口發送一個通知消息,父窗口應在該消息的消息處理函數中實現搜索和替換。
CFindReplaceDialog類提供了一組成員函數用來獲得與用戶操作有關的信息,如下表8所示,這組函數一般應在通知消息處理函數中調用。
函數名 |
用途 |
FindNext |
如果用戶點擊了Findnext按鈕,該函數返回TRUE。 |
GetNotifier |
返回一個指向當前CFindReplaceDialog對話框的指針。 |
GetFindString |
返回一個包含要搜索字符串的CString對象。 |
GetReplaceString |
返回一個包含替換字符串的CString對象。 |
IsTerminating |
如果對話框終止了,則返回TRUE。 |
MatchCase |
如果選擇了對話框中的Match case檢查框,則返回TRUE。 |
MatchWholeWord |
如果選擇了對話框中的Match Whole Word檢查框,則返回TRUE。 |
ReplaceAll |
如果用戶點擊了Replace All按鈕,該函數返回TRUE。 |
ReplaceCurrent |
如果用戶點擊了Replace按鈕,該函數返回TRUE。 |
SearchDown |
返回TRUE表明搜索方向向下,返回FALSE則向上。 |
CEditView類自動實現了Find和Replace對話框的功能,但MFC AppWizard並未提供相應的菜單命令。讀者可以在前面的Register工程的Edit菜單中加入&Find...和&Replace...兩項,並令其ID分別爲ID_EDIT_FIND和ID_EDIT_REPLACE,則Find/Replace對話框的功能就可以實現。