<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    6.1 傳統控件

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    在上一課的表5.1已經列出了Windows的傳統控件及其對應的控件類。在這些控件中,讀者應該重點掌握命令按鈕、選擇框、單選按鈕、編輯框、列表框和組合框。

     

    .1.1 傳統控件的控件通知消息

      控件通過向父窗口發送控件通知消息來表明發生了某種事件.例如,當用戶在按鈕上單擊鼠標時,按鈕控件會向父窗口發送BN_CLICKED消息.傳統控件的通知消息實際上是通過WM_COMMAND消息發給父窗口的(滾動條除外),在該消息的wParam中含有通知消息碼(如BN_CLICKED)和控件的ID,在lParam中則包含了控件的句柄.

      利用ClassWizard可以很容易地為控件通知消息加入消息映射和消息處理函數,這在上一章中已經演示過了.傳統控件的消息映射宏是ON_XXXX,其中XXXX表示通知消息碼,如BN_CLICKED.ON_XXXX消息映射如下所示,該宏有兩個參數,一個是控件的ID,一個是消息處理函數名.

    ON_XXXX(nID, memberFxn)

    消息處理函數的聲明應該有如下形式:

    afx_msg void memberFxn( );

    例如,某按鈕的BN_CLICKED消息的消息映射及其處理函數的聲明如下所示

    ON_BN_CLICKED(IDC_ADD,OnAdd)

    afx_msg void OnAdd( );

      有時,為了處理方便,需要把多個ID連續的控件發出的相同消息映射到同一個處理函數上.這就要用到ON_CONTROL_RANGE宏.ON_CONTROL_RANGE消息映射宏的第一個參數是控件消息碼,第二和第三個參數分別指明了一組連續的控件ID中的頭一個和最后一個ID,最后一個參數是消息處理函數名。例如,要處理一組單選按鈕發出的BN_CLICKED消息,相應的消息映射如下所示:

    ON_CONTROL_RANGE(BN_CLICKED, IDC_FIRST, IDC_LAST, OnRadioClicked)

    函數OnRadioClicked的聲明如下,該函數比上面的OnAdd多了一個參數nID以說明發送通知消息的控件ID.

    afx_msg void OnRadioClicked(UINT nID);

    ClassWizard不支持ON_CONTROL_RANGE宏,所以需要手工建立消息映射和消息處理函數.

    提示:事實上,在使用ClassWizard時只要運用一個小小的技巧,就可以把不同控件的通知消息映射到同一個處理函數上,也可以把一個控件的不同通知消息映射到同一個處理函數上.這個技巧就是在用ClassWizard創建消息處理函數時,指定相同的函數名即可.此方法的優點在于控件的ID不必是連續的,缺點是處理函數沒有nID參數,因而不能確定是哪一個控件發送的消息.

     

    6.1.2 靜態控件

      靜態控件包括靜態正文(Static Text)和圖片控件(Picture)。靜態正文控件用來顯示正文。圖片控件可以顯示位圖、圖標、方框和圖元文件,在圖片控件中顯示圖片的好處是不必操心圖片的重繪問題。靜態控件不能接收用戶的輸入。在上一章中,讀者已經用過靜態正文和組框控件。圖片控件的例子可以在AppWizard創建的IDD_ABOUTBOX對話框模板中找到,在該模板中有一個圖片控件用來顯示圖標。

      靜態控件的主要起說明和裝飾作用。MFC的CStatic類封裝了靜態控件。CStatic類的成員函數Create負責創建靜態控件,該函數的聲明為

    BOOL Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );

      參數lpszText指定了控件顯示的正文。dwStyle指定了靜態控件的風格,表6.1顯示了靜態控件的各種風格,dwStyle可將這些風格組合起來。rect是一個對RECT或CRect結構的引用,用來說明控件的位置和尺寸。pParentWnd指向父窗口,該參數不能為NULL。nID則說明了控件的ID。如果創建成功,該函數返回TRUE,否則返回FALSE.

    表6.1 靜態控件的風格

    控件風格

    含義

    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。

      對于用對話框模板編輯器創建的靜態控件,可以在控件的屬性對話框中指定表6.1中列出的控件風格。例如,可以在靜態正文控件的屬性對話框中選擇Simple,這相當于指定了SS_SIMPLE風格。

      Cstatic類主要的成員函數在表6.2中列出。可以利用CWnd類的成員函數GetWindowText,SetWindowText和GetWindowTextLength等函數來查詢和設置靜態控件中顯示的正文.

    表6.2 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指定的圖元文件。

      靜態控件較簡單,故這里就不舉例說明了。

     

    6.1.3 按鈕控件

      按鈕是指可以響應鼠標點擊的小矩形子窗口。按鈕控件包括命令按鈕(Pushbutton)、檢查框(Check Box)、單選按鈕(Radio Button)、組框(Group Box)和自繪式按鈕(Owner-draw Button)。命令按鈕的作用是對用戶的鼠標單擊作出反應并觸發相應的事件,在按鈕中既可以顯示正文,也可以顯示位圖。選擇框控件可作為一種選擇標記,可以有選中、不選中和不確定三種狀態。單選按鈕控件一般都是成組出現的,具有互斥的性質,即同組單選按鈕中只能有一個是被選中的。組框用來將相關的一些控件聚成一組.自繪式按鈕是指由程序而不是系統負責重繪的按鈕。

      按鈕主要是指命令按鈕、選擇框和單選按鈕。后二者實際上是一種特殊的按鈕,它們有選擇和未選擇狀態。當一個選擇框處于選擇狀態時,在小方框內會出現一個“√”,當單選按鈕處于選擇狀態時,會在圓圈中顯示一個黑色實心圓。此外,檢查框還有一種不確定狀態,這時檢查框呈灰色顯示,不能接受用戶的輸入,以表明控件是無效的或無意義的。

      按鈕控件會向父窗口發出如表6.3所示的控件通知消息。

     

    表6.3 按鈕控件的通知消息

    消息

    含義

    BN_CLICKED

    用戶在按鈕上單擊了鼠標。

    BN_DOUBLECLICKED

    用戶在按鈕上雙擊了鼠標。

    FC的CButton類封裝了按鈕控件。CButton類的成員函數Create負責創建按鈕控件,該函數的聲明為

    BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

      參數lpszCaption指定了按鈕顯示的正文。dwStyle指定了按鈕的風格,如表6.4所示,dwStyle可以是這些風格的組合。rect說明了按鈕的位置和尺寸。pParentWnd指向父窗口,該參數不能為NULL。nID是按鈕的ID。如果創建成功,該函數返回TRUE,否則返回FALSE.

     

    表6.4 按鈕的風格

    控件風格

    含義

    BS_AUTOCHECKBOX

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

    BS_AUTORADIOBUTTON

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

    BS_AUTO3STATE

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

    BS_CHECKBOX

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

    BS_DEFPUSHBUTTON

    指定缺省的命令按鈕,這種按鈕的周圍有一個黑框,用戶可以按回車鍵來快速選擇該按鈕。

    BS_GROUPBOX

    指定一個組框。

    BS_LEFTTEXT

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

    BS_OWNERDRAW

    指定一個自繪式按鈕。

    BS_PUSHBUTTON

    指定一個命令按鈕。

    BS_RADIOBUTTON

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

    BS_3STATE

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

     

     

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

    對于用對話框模板編輯器創建的按鈕控件,可以在控件的屬性對話框中指定表6.4中列出的控件風格。例如,在命令按鈕的屬性對話框中選擇Default button,相當于指定了BS_DEFPUSHBUTTON。

    CButton類的主要的成員函數有:

    UINT GetState( ) const;
    該函數返回按鈕控件的各種狀態。可以用下列屏蔽值與函數的返回值相與,以獲得各種信息。

    0x0003。用來獲取檢查框或單選按鈕的狀態。0表示未選中,1表示被選中,2表示不確定狀態(僅用于檢查框)。

    0x0004。用來判斷按鈕是否是高亮度顯示的。非零值意味著按鈕是高亮度顯示的。當用戶點擊了按鈕并按主鼠標左鍵時,按鈕會呈高亮度顯示。

    0x0008。非零值表示按鈕擁有輸入焦點。

    void SetState( BOOL bHighlight );
    當參數bHeightlight值為TRUE時,該函數將按鈕設置為高亮度狀態,否則,去除按鈕的高亮度狀態。

    int GetCheck( ) const;
    返回檢查框或單選按鈕的選擇狀態。返回值0表示按鈕未被選擇,1表示按鈕被選擇,2表示按鈕處于不確定狀態(僅用于檢查框)。

    void SetCheck( int nCheck );
    設置檢查框或單選按鈕的選擇狀態。參數nCheck值的含義與GetCheck返回值相同。

    UINT GetButtonStyle( ) const;
    獲得按鈕控件的BS_XXXX風格。

    void SetButtonStyle( UINT nStyle, BOOL bRedraw = TRUE );
    設置按鈕的風格。參數nStyle指定了按鈕的風格。bRedraw為TRUE則重繪按鈕,否則就不重繪。

    HBITMAP SetBitmap( HBITMAP hBitmap );
    設置按鈕顯示的位圖。參數hBitmap指定了位圖的句柄。該函數還會返回按鈕原來的位圖。

    HBITMAP GetBitmap( ) const;
    返回以前用SetBitmap設置的按鈕位圖。

    HICON SetIcon( HICON hIcon );
    設置按鈕顯示的圖標。參數hIcon指定了圖標的句柄。該函數還會返回按鈕原來的圖標。

    HICON GetIcon( ) const;
    返回以前用SetIcon設置的按鈕圖標。

    HCURSOR SetCursor( HCURSOR hCursor );
    設置按鈕顯示的光標圖。參數hCursor指定了光標的句柄。該函數還會返回按鈕原來的光標。

    HCURSOR GetCursor( );
    返回以前用GetCursor設置的光標。

     

    另外,可以使用下列的一些與按鈕控件有關的CWnd成員函數來設置或查詢按鈕的狀態。用這些函數的好處在于不必構建按鈕控件對象,只要知道按鈕的ID,就可以直接設置或查詢按鈕。

    void CheckDlgButton( int nIDButton, UINT nCheck );
    用來設置按鈕的選擇狀態。參數nIDButton指定了按鈕的ID。nCheck的值0表示按鈕未被選擇,1表示按鈕被選擇,2表示按鈕處于不確定狀態。

    void CheckRadioButton( int nIDFirstButton, int nIDLastButton, int nIDCheckButton );
    用來選擇組中的一個單選按鈕。參數nIDFirstButton指定了組中第一個按鈕的ID,nIDLastButton指定了組中最后一個按鈕的ID,nIDCheckButton指定了要選擇的按鈕的ID。

    int GetCheckedRadioButton( int nIDFirstButton, int nIDLastButton );
    該函數用來獲得一組單選按鈕中被選中按鈕的ID。參數nIDFirstButton說明了組中第一個按鈕的ID,nIDLastButton說明了組中最后一個按鈕的ID。

    UINT IsDlgButtonChecked( int nIDButton ) const;
    返回檢查框或單選按鈕的選擇狀態。返回值0表示按鈕未被選擇,1表示按鈕被選擇,2表示按鈕處于不確定狀態(僅用于檢查框)。

     

    可以調用CWnd成員函數GetWindowText,GetWindowTextLength和SetWindowText來查詢或設置按鈕中顯示的正文.

    MFC還提供了CButton的派生類CBitmapButton。利用該類可以創建一個擁有四幅位圖的命令按鈕,按鈕在不同狀態時會顯示不同的位圖,這樣可以使界面顯得生動活潑。如果讀者對CBitmapButton感興趣,可以參看VC5.0隨盤提供的MFC例子CTRLTEST。

    在上一章的Register例子中已演示了各種按鈕控件的使用,故這里就不再舉例了。

     

     6.1.4 編輯框控件

     

    編輯框(Edit Box)控件實際上是一個簡易的正文編輯器,用戶可以在編輯框中輸入并編輯正文。編輯框既可以是單行的,也可以是多行的,多行編輯框是從零開始編行號的.在一個多行編輯框中,除了最后一行外,每一行的結尾處都有一對回車換行符(用"/r/n"表示).這對回車換行符是正文換行的標志,在屏幕上是不可見的.

    編輯框控件會向父窗口發出如表6.5所示的控件通知消息。

     

    表6.5

    消息

    含義

    EN_CHANGE

    編輯框的內容被用戶改變了。與EN_UPDATE不同,該消息是在編輯框顯示的正文被刷新后才發出的。

    EN_ERRSPACE

    編輯框控件無法申請足夠的動態內存來滿足需要。

    EN_HSCROLL

    用戶在水平滾動條上單擊鼠標。

    EN_KILLFOCUS

    編輯框失去輸入焦點。

    EN_MAXTEXT

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

    EN_SETFOCUS

    編輯框獲得輸入焦點。

    EN_UPDATE

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

    EN_VSCROLL

    用戶在垂直滾動條上單擊鼠標。

     

     

    MFC的CEdit類封裝了編輯框控件。CEdit類的成員函數Create負責創建按鈕控件,該函數的聲明為

    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

     

    參數dwStyle指定了編輯框控件風格,如表6.6所示,dwStyle可以是這些風格的組合。rect指定了編輯框的位置和尺寸。pParentWnd指定了父窗口,不能為NULL。編輯框的ID由nID指定。如果創建成功,該函數返回TRUE,否則返回FALSE.

     

    表6.6 編輯框控件的風格

    控件風格

    含義

    ES_AUTOHSCROLL

    當用戶在行尾鍵入一個字符時,正文將自動向右滾動10個字符,當用戶按回車鍵時,正文總是滾向左邊。

    ES_AUTOVSCROLL

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

    ES_CENTER

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

    ES_LEFT

    左對齊正文。

    ES_LOWERCASE

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

    ES_MULTILINE

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

    ES_NOHIDESEL

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

    ES_OEMCONVERT

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

    ES_PASSWORD

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

    ES_RIGHT

    右對齊正文。

    ES_UPPERCASE

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

    ES_READONLY

    將編輯框設置成只讀的。

    ES_WANTRETURN

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

     

     

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

    對于用對話框模板編輯器創建的編輯框控件,可以在控件的屬性對話框中指定表6.6中列出的控件風格。例如,在屬性對話框中選擇Multi-line項,相當與指定了ES_MULTILINE風格。

    編輯框支持剪貼板操作。CEdit類提供了一些與剪貼板有關的成員函數,如表6.7所示。

     

    表6.7 與剪切板有關的CEdit成員函數

    函數聲明

    用途

    void Clear( )

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

    void Copy( )

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

    void Cut( )

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

    void Paste( )

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

    BOOL Undo( )

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

      

     

    可以用下列CEdit或CWnd類的成員函數來查詢編輯框。在學習下面的函數時,讀者會經常遇到術語字符索引.字符的字符索引是指從編輯框的開頭字符開始的字符編號,它是從零開始編號的.也就是說,字符索引實際上是指當把整個編輯正文看作一個字符串數組時,該字符所在的數組元素的下標.

     

    int GetWindowText( LPTSTR lpszStringBuf, int nMaxCount ) const;
    void GetWindowText( CString& rString ) const;
    這兩個函數均是CWnd類的成員函數,可用來獲得窗口的標題或控件中的正文。第一個版本的函數用lpszStringBuf參數指向的字符串數組作為拷貝正文的緩沖區,參數nMaxCount可以拷貝到緩沖區中的最大字符數,該函數返回以字節為單位的實際拷貝字符數(不包括結尾的空字節)。第二個版本的函數用一個CString對象作為緩沖區。

    int GetWindowTextLength( ) const;
    CWnd的成員函數,可用來獲得窗口的標題或控件中的正文的長度。

    DWORD GetSel( ) const;
    void GetSel( int& nStartChar, int& nEndChar ) const;
    兩個函數都是CEdit的成員函數,用來獲得所選正文的位置。GetSel的第一個版本返回一個DWORD值,其中低位字說明了被選擇的正文開始處的字符索引,高位字說明了選擇的正文結束處的后面一個字符的字符索引,如果沒有正文被選擇,那么返回的低位和高位字節都是當前插入符所在字符的字符索引。GetSel的第二個版本的兩個參數是兩個引用,其含義與第一個版本函數返回值的低位和高位字相同。

    int LineFromChar( int nIndex = –1 ) const;
    CEdit的成員函數,僅用于多行編輯框,用來返回指定字符索引所在行的行索引(從零開始編號)。參數nIndex指定了一個字符索引,如果nIndex是-1,那么函數將返回選擇正文的第一個字符所在行的行號,若沒有正文被選擇,則該函數會返回當前的插入符所在行的行號。

    int LineIndex( int nLine = –1 ) const;
    CEdit的成員函數,僅用于多行編輯框,用來獲得指定行的開頭字符的字符索引,如果指定行超過了編輯框中的最大行數,該函數將返回-1。參數nLine是指定了從零開始的行索引,如果它的值為-1,則函數返回當前的插入符所在行的字符索引。

    int GetLineCount( ) const;
    CEdit的成員函數,僅用于多行編輯框,用來獲得正文的行數。如果編輯框是空的,那么該函數的返回值是1。

    int LineLength( int nLine = –1 ) const;
    CEdit的成員函數,用于獲取指定字符索引所在行的字節長度(行尾的回車和換行符不計算在內)。參數nLine說明了字符索引.如果nLine的值為-1,則函數返回當前行的長度(假如沒有正文被選擇),或選擇正文占據的行的字符總數減去選擇正文的字符數(假如有正文被選擇)。若用于單行編輯框,則函數返回整個正文的長度。

    int GetLine( int nIndex, LPTSTR lpszBuffer ) const;
    int GetLine( int nIndex, LPTSTR lpszBuffer, int nMaxLength ) const;
    CEdit的成員函數,僅用于多行編輯框,用來獲得指定行的正文(不包括行尾的回車和換行符)。參數nIndex是行號,lpszBuffer指向存放正文的緩沖區,nMaxLength規定了拷貝的最大字節數,若。函數返回實際拷貝的字節數,若指定的行號大于編輯框的實際行數,則函數返回0。需要注意的是,GetLine函數不會在緩沖區中字符串的末尾加字符串結束符(NULL).

     

    下列CWnd或CEdit類的成員函數可用來修改編輯框控件。

    void SetWindowText( LPCTSTR lpszString );
    CWnd的成員函數,可用來設置窗口的標題或控件中的正文。參數lpszString可以是一個CString對象,或是一個指向字符串的指針。

    void SetSel( DWORD dwSelection, BOOL bNoScroll = FALSE );
    void SetSel( int nStartChar, int nEndChar, BOOL bNoScroll = FALSE );
    CEdit的成員函數,用來選擇編輯框中的正文。參數dwSelection的低位字說明了選擇開始處的字符索引,高位字說明了選擇結束處的字符索引。如果低位字為0且高位字節為-1,那么就選擇所有的正文,如果低位字節為-1,則取消所有的選擇.參數bNoScroll的值如果是FALSE,則滾動插入符并使之可見,否則就不滾動.參數nStartChar和nEndChar的含義與參數dwSelection的低位字和高位字相同.

    void ReplaceSel( LPCTSTR lpszNewText, BOOL bCanUndo = FALSE );
    CEdit的成員函數,用來將所選正文替換成指定的正文.參數lpszNewText指向用來替換的字符串.參數bCanUndo的值為TRUE說明替換是否可以被撤消的.

     

    在調用上述函數時,如果涉及的是一個多行編輯框,那么除了LineLength和GetLine函數外,都要把回車和換行符考慮在內.例如,假設在編輯框中有如下幾行正文:

    abcd

    efg

    ij

    那么字母"e"的字符索引是6而不是4,因為"abcd"后面還有一對回車換行符.調用LineLength(7)會返回第二行的長度3.調用LineIndex(2)會得到11.調用LineFromChar(8)會返回1.如果沒有選擇任何正文,并且插入符在字母"e"上,那么調用GetSel返回值的低位和高位字都是6.

    通過分析上述函數,我們可以總結出一些查詢和設置編輯框的方法.

    調用CWnd的成員函數GetWindowText和SetWindowText可以查詢和設置編輯框的整個正文,在上一章的Register程序中,我們就使用過這兩個函數.

    如果想對多行編輯框逐行查詢,那么應該先調用GetLineCount獲得總行數,然后再調用GetLine來獲取每一行的正文.下面一段代碼演示了如何對多行編輯框進行逐行查詢.

    char buf[40];

    int total=MyEdit.GetLineCount();

    int i,length;

    for(i=0;i<total;i++)

    {

    length=MyEdit.GetLine(i,buf,39);

    buf[length]=0; //加字符串結束符

    . . . . . .

    }

    可以利用LineIndex和LineFromChar來在字符索引和字符的行列坐標之間相互轉換.下列代碼演示了在已知字符索引的情況下,如何獲得對應的行列坐標:
    int row,column;
    row=MyEdit.LineFromChar(charIndex);
    column=charIndex-MyEdit.LineIndex(row);
    下列代碼演示了在已知字符的行列坐標的情況下,如何獲得對應的字符索引:
    int charIndex;
    charIndex=MyEdit.LineIndex(row)+column;
    不難看出字符索引與對應的行列坐標的關系是:字符索引=LineIndex(行坐標)+列坐標.

    對于選擇正文的查詢和設置,應該利用函數GetSel、SetSel和ReplaceSel.

    可以利用GetSel和SetSel來查詢和設置插入符的位置.SetSel可以使編輯框滾動到插入符的新位置.
    要獲取插入符的行列坐標,可用下面的代碼實現:
    MyEdit.SetSel(-1,0); //取消正文的選擇
    int start,end,row,column;
    MyEdit.GetSel(start,end); //start或end的值就是插入符的字符索引
    row=MyEdit.LineFromChar(start); //獲取插入符的行坐標
    column=start-MyEdit.LineIndex(row); //獲取插入符的列坐標
    下面的代碼演示了如何把插入符移到指定的行和列:
    MyEdit.SetSel(-1,0); //取消正文的選擇
    int charIndex=MyEdit.LineIndex(row)+column;
    MyEdit.SetSel(charIndex,charIndex);

    可以利用ReplaceSel函數在 插入符處插入正文,典型的代碼如下所示:
    MyEdit.SetSel(-1,0); //取消正文的選擇
    MyEdit.ReplaceSel(“......”);

    可以利用ReplaceSel清除編輯框中的正文,典型的代碼如下所示:
    MyEdit.SetSel(0,-1); //選擇全部正文
    MyEdit.ReplaceSel(“”);

     

    在后面的小節中,讀者將會看到使用編輯框的例子.

     

    .1.5 滾動條控件

    滾動條(Scroll Bar)主要用來從某一預定義值范圍內快速有效地進行選擇.滾動條分垂直滾動條和水平滾動條兩種.在滾動條內有一個滾動框,用來表示當前的值.用鼠標單擊滾動條,可以使滾動框移動一頁或一行,也可以直接拖動滾動框.滾動條既可以作為一個獨立控件存在,也可以作為窗口、列表框和組合框的一部分.Windows 95的滾動條支持比例滾動框,即用滾動框的大小來反映頁相對于整個范圍的大小.Windows 3.x使用單獨的滾動條控件來調整調色板、鍵盤速度以及鼠標靈敏度,在Windows 95中,滾動條控件被軌道條取代(參見6.2.3)不提倡使用單獨的滾動條控件.

    需要指出的是,從性質上劃分,滾動條可分為標準滾動條和滾動條控件兩種.標準滾動條是由WS_HSCROLL或WS_VSCROLL風格指定的,它不是一個實際的窗口,而是窗口的一個組成部分(例如列表框中的滾動條),只能位于窗口的右側(垂直滾動條)或底端(水平滾動條).標準滾動條是在窗口的非客戶區中創建的.與之相反,滾動條控件并不是窗口的一個零件,而是一個實際的窗口,可以放置在窗口客戶區的任意地方,它既可以獨立存在,也可以與某一個窗口組合,行使滾動窗口的職能.由于滾動條控件是一個獨立窗口,因此可以擁有輸入焦點,可以響應光標控制鍵,如PgUp、PgDown、Home和End.

    MFC的CScrollBar類封裝了滾動條控件.CScrollBar類的Create成員函數負責創建控件,該函數的聲明為

    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

    參數dwStyle指定了控件的風格.rect說明了控件的位置和尺寸.pParentWnd指向父窗口,該參數不能為NULL。nID則說明了控件的ID。如果創建成功,該函數返回TRUE,否則返回FALSE.

    要創建一個普通的水平滾動條控件,應指定風格WS_CHILD|WS_VISIBLE|BS_HORZ.要創建一個普通的垂直滾動條控件,應指定風格WS_CHILD|WS_VISIBLE|BS_VERT.

    主要的CScrollBar類成員函數如下所示:

    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,則重繪之.

    BOOL GetScrollInfo( LPSCROLLINFO lpScrollInfo, UINT nMask );
    該函數用來獲取滾動條的各種狀態,包括滾動范圍、滾動框的位置和頁尺寸.參數lpScrollInfo指向一個SCROLLINFO結構,該結構如下所示:
    typedef struct tagSCROLLINFO { 
    UINT cbSize; //結構的尺寸(字節為單位)
    UINT fMask; /*說明結構中的哪些參數是有效的,可以是屏蔽值的組合, 如SIF_POS|SIF_PAGE,若為SIF_ALL則整個結構都有效*/
    int nMin; //滾動范圍最大值,當fMask中包含SIF_RANGE時有效
    int nMax; //滾動范圍最小值,當fMask中包含SIF_RANGE時有效
    UINT nPage; /*頁尺寸,用來確定比例滾動框的大小,當fMask中包含 SIF_PAGE時有效*/
    int nPos; //滾動框的位置,當fMask中包含SIF_POS有效
    int nTrackPos; /*拖動時滾動框的位置,當fMask中包含 SIF_TRACKPOS時有效,該參數只能查詢,不能設 置,最好不要用該參數來查詢拖動時滾動框的位置*/
    } SCROLLINFO; 
    typedef SCROLLINFO FAR *LPSCROLLINFO;
    參數nMask的意義與SCROLLINFO結構中的fMask相同.函數在獲得有效值后返回TRUE,否則返回FALSE.

    BOOL SetScrollInfo( LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE );
    該函數用于設置滾動條的各種狀態,一個重要用途是設定頁尺寸從而實現比例滾動框.參數lpScrollInfo指向一個SCROLLINFO結構,參數bRedraw表示是否需要重繪滾動條,如果為TRUE,則重繪之.若操作成功,該函數返回TRUE,否則返回FALSE.

     

    CWnd類也提供了一些函數來查詢和設置所屬的標準滾動條.這些函數與CScrollBar類的函數同名,且功能相同,但每個函數都多了一個參數,用來選擇滾動條.例如,CWnd:: GetScrollPos 的聲明為

    int GetScrollPos( int nBar ) const;
    參數nBar用來選擇滾動條,可以為下列值:
    SB_HORZ //指定水平滾動條
    SB_VERT //指定垂直滾動條

     

    無論是標準滾動條,還是滾動條控件,滾動條的通知消息都是用WM_HSCROLL和WM_VSCROLL消息發送出去的.對這兩個消息的確省處理函數是CWnd::OnHScroll和CWnd::OnVScroll,它們幾乎什么也不做.一般需要在派生類中對這兩個函數從新設計,以實現滾動功能.這兩個函數的聲明為

    afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );

    afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );
    參數nSBCode是通知消息碼,如表6.8所示.nPos是滾動框的位置,只有在nSBCode為SB_THUMBPOSITION或SB_THUMBTRACK時,該參數才有意義.如果通知消息是滾動條控件發來的,那么pScrollBar是指向該控件的指針,如果是標準滾動條發來的,則pScrollBar為NULL.

     

    表6.8 滾動條的通知消息碼

    消息

    含義

    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

    滾動結束.

    6.1.8小節的例子中,讀者將學會如何使用滾動條以及如何編寫自己的OnHScroll函數.

     

    6.1.6 列表框控件

    列表框主要用于輸入,它允許用戶從所列出的表項中進行單項或多項選擇,被選擇的項呈高亮度顯示.列表框具有邊框,并且一般帶有一個垂直滾動條.列表框分單選列表框和多重選擇列表框兩種.單選列表框一次只能選擇一個列表項,而多重選擇列表框可以進行多重選擇.對于列表項的選擇,微軟公司有如下建議:

    單擊鼠標選擇一個列表項,單擊一個按鈕來處理選擇的項.

    雙擊鼠標選擇一個列表項是處理選擇項的快捷方法.

     

    列表框會向父窗口發送如表6.9所示的通知消息.

     

    表6.9 列表框控件的通知消息

    消息

    含義

    LBN_DBLCLK

    用戶用鼠標雙擊了一列表項.只有具有LBS_NOTIFY的列表框才能發送該消息.

    LBN_ERRSPACE

    列表框不能申請足夠的動態內存來滿足需要.

    LBN_KILLFOCUS

    列表框失去輸入焦點.

    LBN_SELCANCEL

    當前的選擇被取消.只有具有LBS_NOTIFY的列表框才能發送該消息.

    LBN_SELCHANGE

    單擊鼠標選擇了一列表項.只有具有LBS_NOTIFY的列表框才能發送該消息.

    LBN_SETFOCUS

    列表框獲得輸入焦點.

    WM_CHARTOITEM

    當列表框收到WM_CHAR消息后,向父窗口發送該消息.只有具有LBS_WANTKEYBOARDINPUT風格的列表框才會發送該消息.

    WM_VKEYTOITEM

    當列表框收到WM_KEYDOWN消息后,向父窗口發送該消息.只有具有LBS_WANTKEYBOARDINPUT風格的列表框才會發送該消息.

     

     

    MFC的CListBox類封裝了列表框.CListBox類的Create成員函數負責列表框的創建,該函數的聲明是

    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

     

    參數dwStyle指定了列表框控件的風格,如表6.10所示,dwStyle可以是這些風格的組合.rect說明了控件的位置和尺寸.pParentWnd指向父窗口,該參數不能為NULL。nID則說明了控件的ID。如果創建成功,該函數返回TRUE,否則返回FALSE.

     

    表6.10 列表框控件的風格

    控件風格

    含義

    LBS_EXTENDEDSEL

    支持多重選擇.在點擊列表項時按住Shift鍵或Ctrl鍵即可選擇多個 項.

    LBS_HASSTRINGS

    指定一個含有字符串的自繪式列表框.

    LBS_MULTICOLUMN

    指定一個水平滾動的多列列表框,通過調用CListBox::SetColumnWidth來設置每列的寬度.

    LBS_MULTIPLESEL

    支持多重選擇.列表項的選擇狀態隨著用戶對該項單擊或雙擊鼠標而翻轉.

    LBS_NOINTEGRALHEIGHT

    列表框的尺寸由應用程序而不是Windows指定.通常,Windows指定尺寸會使列表項的某些部分隱藏起來.

    LBS_NOREDRAW

    當選擇發生變化時防止列表框被更新,可發送WM_SETREDRAW來改變該風格.

    LBS_NOTIFY

    當用戶單擊或雙擊鼠標時通知父窗口.

    LBS_OWNERDRAWFIXED

    指定自繪式列表框,即由父窗口負責繪制列表框的內容,并且列表項有相同的高度.

    LBS_OWNERDRAWVARIABLE

    指定自繪式列表框,并且列表項有不同的高度.

    LBS_SORT

    使插入列表框中的項按升序排列.

    LBS_STANDARD

    相當于指定了WS_BORDER|WS_VSCROLL|LBS_SORT |LBS_NOTIFY.

    LBS_USETABSTOPS

    使列表框在顯示列表項時識別并擴展制表符(‘/t’),缺省的制表寬度是32個對話框單位.

    LBS_WANTKEYBOARDINPUT

    允許列表框的父窗口接收WM_VKEYTOITEM和WM_CHARTOITEM消息,以響應鍵盤輸入.

    LBS_DISABLENOSCROLL

    使列表框在不需要滾動時顯示一個禁止的垂直滾動條.

     

     

    除了上表中的風格外,一般還要為列表框控件指定WS_CHILD、WS_VISIBLE、WS_TABSTOP、WS_BORDER和WS_VSCROLL風格.要創建一個普通的單選擇列表框,應指定的風格為WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_STANDARD.要創建一個多重選擇列表框,應該在單選擇列表框風格的基礎上再加上 LBS_MULTIPLESEL或LBS_ EXTENDEDSEL.如果不希望列表框排序,就不能使用LBS_STANDARD風格.

    對于用對話框模板編輯器創建的列表框控件,可以在控件的屬性對話框中指定表6.10中列出的控件風格。例如,在屬性對話框中選擇Sort項,相當與指定了LBS_SORT風格。

    CListBox類的成員函數有數十個之多.我們可以把一些常用的函數分為三類,在下面列出.需要說明的是,可以用索引來指定列表項,索引是從零開始的.

    首先,CListBox成員函數提供了下列函數用于插入和刪除列表項.

    int AddString( LPCTSTR lpszItem );
    該函數用來往列表框中加入字符串,其中參數lpszItem指定了要添加的字符串.函數的返回值是加入的字符串在列表框中的位置,如果發生錯誤,會返回LB_ERR或LB_ERRSPACE(內存不夠).如果列表框未設置LBS_SORT風格,那么字符串將被添加到列表的末尾,如果設置了LBS_SORT風格,字符串會按排序規律插入到列表中.

    int InsertString( int nIndex, LPCTSTR lpszItem );
    該函數用來在列表框中的指定位置插入字符串.參數nIndex給出了插入位置(索引),如果值為-1,則字符串將被添加到列表的末尾.參數lpszItem指定了要插入的字符串.函數返回實際的插入位置,若發生錯誤,會返回LB_ERR或LB_ERRSPACE.與AddString函數不同,InsertString函數不會導致LBS_SORT風格的列表框重新排序.不要在具有LBS_SORT風格的列表框中使用InsertString函數,以免破壞列表項的次序.

    int DeleteString( UINT nIndex );
    該函數用于刪除指定的列表項,其中參數nIndex指定了要刪除項的索引.函數的返回值為剩下的表項數目,如果nIndex超過了實際的表項總數,則返回LB_ERR.

    void ResetContent( );
    該函數用于清除所有列表項.

    int Dir( UINT attr, LPCTSTR lpszWildCard );
    該函數用來向列表項中加入所有與指定通配符相匹配的文件名或驅動器名.參數attr為文件類型的組合,如表6.11所示.參數lpszWildCard指定了通配符(如*.cpp,*.*等).

     

    表6.11 Dir函數attr參數的含義

    含義

    0x0000

    普通文件(可讀寫的文件).

    0x0001

    只讀文件.

    0x0002

    隱藏文件.

    0x0004

    系統文件.

    0x0010

    目錄.

    0x0020

    文件的歸檔位已被設置.

    0x4000

    包括了所有與通配符相匹配的驅動器.

    0x8000

    排除標志.若指定該標志,則只列出指定類型的文件名,否則,先要列出普通文件,然后再列出指定的文件.

     

     

    下列的CListBox成員函數用于搜索、查詢和設置列表框.

    int GetCount( ) const;
    該函數返回列表項的總數,若出錯則返回LB_ERR.

    int FindString( int nStartAfter, LPCTSTR lpszItem ) const;
    該函數用于對列表項進行與大小寫無關的搜索.參數nStartAfter指定了開始搜索的位置, 合理指定nStartAfter可以加快搜索速度,若nStartAfter為-1,則從頭開始搜索整個列表.參數lpszItem指定了要搜索的字符串.函數返回與lpszItem指定的字符串相匹配的列表項的索引,若沒有找到匹配項或發生了錯誤,函數會返回LB_ERR.FindString函數先從nStartAfter指定的位置開始搜索,若沒有找到匹配項,則會從頭開始搜索列表.只有找到匹配項,或對整個列表搜索完一遍后,搜索過程才會停止,所以不必擔心會漏掉要搜索的列表項.

    int GetText( int nIndex, LPTSTR lpszBuffer ) const;
    void GetText( int nIndex, CString& rString ) const;
    用于獲取指定列表項的字符串.參數nIndex指定了列表項的索引.參數lpszBuffer指向一個接收字符串的緩沖區.引用參數rString則指定了接收字符串的CString對象.第一個版本的函數會返回獲得的字符串的長度,若出錯,則返回LB_ERR.

    int GetTextLen( int nIndex ) const;
    該函數返回指定列表項的字符串的字節長度.參數nIndex指定了列表項的索引.若出錯則返回LB_ERR.

    DWORD GetItemData( int nIndex ) const;
    每個列表項都有一個32位的附加數據.該函數返回指定列表項的附加數據,參數nIndex指定了列表項的索引.若出錯則函數返回LB_ERR.

    int SetItemData( int nIndex, DWORD dwItemData );
    該函數用來指定某一列表項的32位附加數據.參數nIndex指定了列表項的索引.dwItemData是要設置的附加數據值.

    提示:列表項的32位附加數據可用來存儲與列表項相關的數據,也可以放置指向相關數據的指針.這樣,當用戶選擇了一個列表項時,程序可以從附加數據中快速方便地獲得與列表項相關的數據.

     

     

    int GetTopIndex( ) const;
    該函數返回列表框中第一個可見項的索引,若出錯則返回LB_ERR.

    int SetTopIndex( int nIndex );
    用來將指定的列表項設置為列表框的第一個可見項,該函數會將列表框滾動到合適的位置.參數nIndex指定了列表項的索引.若操作成功,函數返回0值,否則返回LB_ERR.

    提示:由于列表項的內容一般是不變的,故CListBox未提供更新列表項字符串的函數.如果要改變某列表項的內容,可以先調用DeleteString刪除該項,然后再用InsertString或AddString將更新后的內容插入到原來的位置.

    下列CListBox的成員函數與列表項的選擇有關.

    int GetSel( int nIndex ) const;
    該函數返回指定列表項的狀態.參數nIndex指定了列表項的索引.如果查詢的列表項被選擇了,函數返回一個正值,否則返回0,若出錯則返回LB_ERR.

    int GetCurSel( ) const;
    該函數僅適用于單選擇列表框,用來返回當前被選擇項的索引,如果沒有列表項被選擇或有錯誤發生,則函數返回LB_ERR.

    int SetCurSel( int nSelect );
    該函數僅適用于單選擇列表框,用來選擇指定的列表項.該函數會滾動列表框以使選擇項可見.參數nIndex指定了列表項的索引,若為-1,那么將清除列表框中的選擇.若出錯函數返回LB_ERR.

    int SelectString( int nStartAfter, LPCTSTR lpszItem );
    該函數僅適用于單選擇列表框,用來選擇與指定字符串相匹配的列表項.該函數會滾動列表框以使選擇項可見.參數的意義及搜索的方法與函數FindString類似.如果找到了匹配的項,函數返回該項的索引,如果沒有匹配的項,函數返回LB_ERR并且當前的選擇不被改變.

    int GetSelCount( ) const;
    該函數僅用于多重選擇列表框,它返回選擇項的數目,若出錯函數返回LB_ERR.

    int SetSel( int nIndex, BOOL bSelect = TRUE );
    該函數僅適用于多重選擇列表框,它使指定的列表項選中或落選.參數nIndex指定了列表項的索引,若為-1,則相當于指定了所有的項.參數bSelect為TRUE時選中列表項,否則使之落選.若出錯則返回LB_ERR.

    int GetSelItems( int nMaxItems, LPINT rgIndex ) const;
    該函數僅用于多重選擇列表框,用來獲得選中的項的數目及位置.參數nMaxItems說明了參數rgIndex指向的數組的大小.參數rgIndex指向一個緩沖區,該數組是一個整型數組,用來存放選中的列表項的索引.函數返回放在緩沖區中的選擇項的實際數目,若出錯函數返回LB_ERR.

    int SelItemRange( BOOL bSelect, int nFirstItem, int nLastItem );
    該函數僅用于多重選擇列表框,用來使指定范圍內的列表項選中或落選.參數nFirstItem和nLastItem指定了列表項索引的范圍.如果參數bSelect為TRUE,那么就選擇這些列表項,否則就使它們落選.若出錯函數返回LB_ERR.

    在6.1.8小節的例子中,讀者將會看到對列表框的測試.

     

    組合框把一個編輯框和一個單選擇列表框結合在了一起.用戶既可以在編輯框中輸入,也可以從列表框中選擇一個列表項來完成輸入.如上一章所提到的,組合框分為簡易式(Simple)、下拉式(Dropdown)和下拉列表式(Drop List)三種.簡易式組合框包含一個編輯框和一個總是顯示的列表框。下拉式組合框同簡易式組合框類似,二者的區別在于僅當單擊下滾箭頭后列表框才會彈出。下拉列表式組合框也有一個下拉的列表框,但它的編輯框是只讀的,不能輸入字符。

    Windows中比較常用的是下拉式和下拉列表式組合框,在Developer Studio中就大量使用了這兩種組合框.二者都具有占地小的特點,這在界面日益復雜的今天是十分重要的.下拉列表式組合框的功能與列表框類似.下拉式組合框的典型應用是作為記事列表框使用,既把用戶在編輯框中敲入的東西存儲到列表框組件中,這樣當用戶要重復同樣的輸入時,可以從列表框組件中選取而不必在編輯框組件中從新輸入.在Developer Studio中的Find對話框中就可以找到一個典型的下拉式組合框.

    要設計一個記事列表框,應采取下列原則:

    在創建組合框時指定CBS_DROPDOWNLIST風格.

    要限制列表項的數目,以防止內存不夠.

    如果在編輯框中輸入的字符串不能與列表框組件中的列表項匹配,那么應該把該字符串插入到列表框中的0位置處.最老的項處于列表的末尾.如果列表項的數目超出了限制,則應把最老的項刪除.

    如果在編輯框中輸入的字符串可以與列表框組件中的某一項完全匹配,則應該先把該項從列表的當前位置刪除,然后在將其插入道列表的0位置處.

     

    組合框控件會向父窗口發送表6.12所示的通知消息.

     

    表6.12 組合框控件的通知消息

    消息

    含義

    CBN_CLOSEUP

    組合框的列表框組件被關閉.簡易式組合框不會發出該消息.

    CBN_DBLCLK

    用戶在某列表項上雙擊鼠標.只有簡易式組合框才會發出該消息.

    CBN_DROPDOWN

    組合框的列表框組件下拉.簡易式組合框不會發出該消息.

    CBN_EDITCHANGE

    編輯框的內容被用戶改變了。與CBN_EDITUPDATE不同,該消息是在編輯框顯示的正文被刷新后才發出的。下拉列表式組合框不會發出該消息.

    CBN_EDITUPDATE

    在編輯框準備顯示改變了的正文時發送該消息。下拉列表式組合框不會發出該消息.

    CBN_ERRSPACE

    組合框無法申請足夠的內存來容納列表項.

    CBN_SELENDCANCEL

    表明用戶的選擇應該取消.當用戶在列表框中選擇了一項,然后又在組合框控件外單擊鼠標時就會導致該消息的發送.

    CBN_SELENDOK

    用戶選擇了一項,然后按了回車鍵或單擊了下滾箭頭.該消息表明用戶確認了自己所作的選擇.

    CBN_KILLFOCUS

    組合框失去了輸入焦點.

    CBN_SELCHANGE

    用戶通過點擊或移動箭頭鍵改變了列表的選擇.

    CBN_SETFOCUS

    組合框獲得了輸入焦點.

     

     

    MFC的CComboBox類封裝了組合框.需要指出的是,雖然組合框是編輯框和列表框的選擇,但是CComboBox類并不是CEdit類和CListBox類的派生類,而是CWnd類的派生類.

    CComboBox的成員函數Create負責創建組合框,該函數的說明如下:

    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

     

    參數dwStyle指定了組合框控件的風格,如表6.10所示,dwStyle可以是這些風格的組合.rect說明的是列表框組件下拉后組合框的位置和尺寸.pParentWnd指向父窗口,該參數不能為NULL。nID則說明了控件的ID。如果創建成功,該函數返回TRUE,否則返回FALSE.

    提示:在用Create函數創建組合框時,參數rect說明的是包括列表框組件在內的組合框的位置和尺寸,而不是列表框組件隱藏時的編輯框組件尺寸.要設置編輯框組件的高度,可以調用成員函數SetItemHeight(-1,cyItemHeight),其中參數cyItemHeight指定了編輯框的高度(以像素為單位).

    表6.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.

    CComboBox類的成員函數較多.其中常用的函數可粗分為兩類,分別針對編輯框組件和列表框組件.可以想象,這些函數與CEdit類和CListBox類的成員函數肯定有很多類似之處,但它們也會有一些不同的特點.如果讀者能從"組合框是由編輯框和列表框組成"這一概念出發,就能夠很快的掌握CComboBox的主要成員函數.

    事實上,絕大部分CComboBox的成員函數都可以看成是CEdit或CListBox成員函數的翻版.函數的功能,函數名,甚至函數的參數都是類似的.為了方便學習,在下面列出CComboBox類的成員函數時,采用了與對應的CEdit或CListBox成員函數相比較的做法.在成員函數的列表中,分別列出了成員函數名,對應的CEdit或CListBox成員函數,以及二者之間的不同之處.不同之處是指函數的功能、參數以及返回值有什么差別.

    針對編輯框組件的主要成員函數如表6.14所示.該表的前三個函數實際上是CWnd類的成員函數,可用來查詢和設置編輯框組件.

     

    表6.14 針對編輯框組件的CComboBox成員函數

    成員函數名

    對應的CEdit成員函數

    與CEdit成員函數的不同之處

    CWnd::GetWindowText

    CWnd::GetWindowText

    無.

    CWnd::SetWindowText

    CWnd::SetWindowText

    無.

    CWnd::GetWindowTextLength

    CWnd::GetWindowTextLength

     

    GetEditSel

    GetSel的第一個版本

    僅函數名不同.

    SetEditSel

    SetSel的第二個版本

    函數名不同,且無bNoScroll參數.

    Clear

    Clear

    無.

    Copy

    Copy

    無.

    Cut

    Cut

    無.

    Paste

    Paste

    無.

     

     

    與CListBox的成員函數類似,針對列表框組件的CComboBox成員函數也可以分為三類.表6.15列出了用于插入和刪除列表項的成員函數,表6.16列出了用于搜索、查詢和設置列表框的成員函數,與列表項的選擇有關的成員函數在表6.17中列出.需要指出的是,如果這些函數出錯,則反回CB_ERR,而不是LB_ERR.另外,排序的組合框具有的是CBS_SORT風格,而不是LBS_SORT.

     

     

    6.15 用于插入和刪除列表項的CComboBox成員函數

    成員函數名

    對應的CListBox成員函數

    與CListBox成員函數的不同之處

    AddString

    AddString

    無.

    InsertString

    InsertString

    無.

    DeleteString

    DeleteString

    無.

    ResetContent

    ResetContent

    無.

    Dir

    Dir

    無.

     

     

    6.16 用于搜索、查詢和設置列表框的CComboBox成員函數

    成員函數名

    對應的CListBox成員函數

    與CListBox成員函數的不同之處

    GetCount

    GetCount

    無.

    FindString

    FindString

    無.

    GetLBText

    GetText

    僅函數名不同.

    GetLBTextLen

    GetTextLen

    僅函數名不同.

    GetItemData

    GetItemData

    無.

    SetItemData

    SetItemData

    無.

    GetTopIndex

    GetTopIndex

    無.

    SetTopIndex

    SetTopIndex

    無.

     

     

    表6.17 與列表項的選擇有關的CComboBox成員函數

    成員函數名

    對應的CListBox成員函數

    與CListBox成員函數的不同之處

    GetCurSel

    GetCurSel

    無.

    SetCurSel

    SetCurSel

    新選的列表項的內容會被拷貝到編輯框組件中.

    SelectString

    SelectString

    新選的列表項的內容會被拷貝到編輯框組件中.

      

     

    另外,CComboBox的ShowDropDown成員函數專門負責顯示或隱藏列表框組件,該函數的聲明為

    void ShowDropDown( BOOL bShowIt = TRUE );

     

    如果參數bShowIt的值為TRUE,那么將顯示列表框組件,否則,就隱藏之.該函數對簡易式組合框沒有作用.

     

     

    現在讓我們編寫一個程序來測試一下上面介紹的一些傳統控件.該程序名為CtrlTest,其界面如圖6.1所示.前面介紹的程序都是基于框架窗口的,而CtrlTest程序是一個基于對話框的應用程序,即以對話框作為程序的主窗口.該程序主要對組合框、列表框、多行編輯框和滾動條控件進行了測試,其中:

    Input組合框是一個記事列表框.在編輯框組件中輸入字符串,或從列表框組件中選擇以前輸入過的字符串,然后按Add按鈕,該字符串就會被加入到List列表框中.

    List列表框是一個多重選擇列表框.該列表框具有LBS_EXTENDEDSEL風格,用戶可以單擊鼠標進行單項選擇,也可以按住Shift或Ctrl鍵后單擊鼠標來進行多重選擇.用戶可以按Delete鍵刪除列表框中選擇的項.

    History of SELCHANGE多行編輯框.該編輯框用于跟蹤Input組合框的列表框組件發出的CBN_SELCHANGE通知消息,編輯框對該消息的響應是顯示XXXX selected,以表明用戶新選擇了一個列表項.讀者通過該編輯框可以了解組合框是在什么情況下發送CBN_SELCHANGE通知消息的.按Clear按鈕將清除編輯框.

    水平滾動條控件的滾動范圍是0 — 50.在滾動條的左邊有一個靜態正文控件用來動態反映當前滾動框的位置.

    T6_1.tif (122740 bytes)

    圖6.1 CtrlTest程序

     

    首先,讓我們用AppWizard建立一個基于對話框的MFC應用程序.這一過程很簡單,先將新建的工程命名為CtrlTest,然后在MFC AppWizard對話框的第一步中選擇Dialog based就行了.

    AppWizard會自動建立一個用于應用程序主窗口的對話框模板IDD_CTRLTEST_DIALOG及其對應的對話框類CCtrlTestDlg.對該對話框的使用與普通對話框并沒有什么不同,只不過在程序啟動后對話框會自動顯示出來,而當用戶關閉對話框后,應用程序也就終止了.如果讀者觀察CCtrlTestApp:: InitInstance函數就會發現,該函數調用DoModal來顯示一個CCtrlTestDlg對話框,并使m_pMainWnd指針指向CCtrlTestDlg對象,從而使該對話框成為程序的主窗口.

    接下來,需要設計IDD_CTRLTEST_DIALOG對話框模板.請讀者將該模板上除OK按鈕以外的控件都刪除掉,將OK按鈕的標題改為Cl&ose,并去掉該按鈕的Default button(缺省按鈕)屬性.當用戶在對話框內按回車鍵時,會激活缺省按鈕,一般應該把用來確認用戶輸入操作的按鈕設計成缺省按鈕.在本例中,顯然應該把Add按鈕設計成缺省按鈕,而不是Close按鈕.這樣,用戶在Input組合框中輸入字符串后,按回車鍵就可以將該串加入到List列表框中.

    請讀者根據圖6.1和表6.18,向IDD_CTRLTEST_DIALOG對話框模板中加入測試用的控件.

     

    表6.18

    控件類型 ID 標題(Caption) 其它屬性

    靜態正文

    缺省

    Input:

    缺省.

    組合框

    ID_COMBOBOX

     

    去掉Sort屬性.

    命令按鈕

    IDC_ADD

    &Add

    選擇Default button屬性.

    靜態正文

    缺省

    List:

    缺省.

    列表框

    IDC_LISTBOX

     

    在Selection欄中選擇Extended,并去掉Sort屬性.

    命令按鈕

    IDC_DELETE

    &Delete

    缺省.

    靜態正文

    缺省

    History of SELCHANGE

    缺省.

    編輯框

    IDC_MULTIEDIT

     

    選擇Multi-line,Vertical scroll,AutoVScroll和Want return屬性.

    命令按鈕

    IDC_CLEAR

    &Clear

    缺省.

    靜態正文

    IDC_INDICATOR

    缺省

    缺省.

    滾動條

    IDC_SCROLLBAR

     

    缺省.

     

     

    接著,利用ClassWizard為CCtrlTestDlg類加入成員變量,如表6.19所示,這些成員變量都是控件對象.

     

    表6.19 CCtrlTestDlg類的成員變量

    控件ID

    變量類型

    變量名

    IDC_COMBOBOX

    CComboBox

    m_ComboBox

    IDC_LISTBOX

    CListBox

    m_ListBox

    IDC_MULTIEDIT

    CEdit

    m_MultiEdit

    IDC_INDICATOR

    CStatic

    m_Indicator

    IDC_SCROLLBAR

    CScrollBar

    m_ScrollBar

     

     

    接下來,用ClassWizard為CCtrlTestDlg類加入控件通知消息處理函數,如表6.20所示.

     

    表6.20 CCtrlTestDlg的控件通知消息處理函數

    Object IDS

    Messages

    Member functions

    IDC_ADD

    BN_CLICKED

    OnAdd(缺省名)

    IDC_DELETE

    BN_CLICKED

    OnDelete(缺省名)

    IDC_CLEAR

    BN_CLICKED

    OnClear(缺省名)

    IDC_COMBOBOX

    CBN_SELCHANGE

    OnSelchangeCombobox(缺省名)

    CCtrlTestDlg

    WM_HSCROLL

    OnHScroll(缺省名)

     

    最后,請讀者按清單6.1修改源代碼,限于篇幅,這里僅列出需要手工修改的那一部分.

     

    清單6.1 CCtrlTestDlg類的部分源代碼

    // CtrlTestDlg.cpp : implementation file

    //

     

    #define MAX_HISTORY 5

    . . . . . .

    BOOL CCtrlTestDlg::OnInitDialog()

    {

     

    . . . . . .

    // TODO: Add extra initialization here

     

    m_ScrollBar.SetScrollRange(0,50);

    m_Indicator.SetWindowText("0");

    m_ComboBox.SetFocus(); //使組合框獲得輸入焦點

     

    return FALSE; // 返回FALSE以表明為某一控件設置了輸入焦點

    }

     

    void CCtrlTestDlg::OnAdd()

    {

    // TODO: Add your control notification handler code here

     

    int i;

    CString str;

    m_ComboBox.GetWindowText(str);

    m_ListBox.AddString(str);

    i=m_ComboBox.FindString(-1,str);

    if(i>=0)

    {

    m_ComboBox.DeleteString(i);

    m_ComboBox.InsertString(0,str); //將匹配項移到0位置

    }

    else

    {

    m_ComboBox.InsertString(0,str);

    if(m_ComboBox.GetCount()>MAX_HISTORY)

    m_ComboBox.DeleteString(m_ComboBox.GetCount()-1); //刪除舊的項

    }

    }

     

    void CCtrlTestDlg::OnClear()

    {

    // TODO: Add your control notification handler code here

     

    m_MultiEdit.SetSel(0,-1);

    m_MultiEdit.ReplaceSel("");

    }

     

    void CCtrlTestDlg::OnDelete()

    {

    // TODO: Add your control notification handler code here

     

    int i,count;

    int *pBuffer;

    count=m_ListBox.GetSelCount();

    if(count<=0)return;

    pBuffer=new int[count];

    m_ListBox.GetSelItems(count,pBuffer);

    for(i=count-1;i>=0;i--) //倒序刪除選擇項

    m_ListBox.DeleteString(pBuffer[i]);

    delete pBuffer;

    }

     

    void CCtrlTestDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)

    {

    // TODO: Add your message handler code here and/or call default

     

    int nScrollMin,nScrollMax,nScrollPos;

    int nPageSize;

    CString str;

    if(&m_ScrollBar!=pScrollBar)return;

    nScrollPos=m_ScrollBar.GetScrollPos();

    m_ScrollBar.GetScrollRange(&nScrollMin,&nScrollMax);

    nPageSize=(nScrollMax-nScrollMin)/10; //指定頁長

    switch(nSBCode)

    {

    case SB_LEFT:

    nScrollPos=nScrollMin;

    break;

    case SB_RIGHT:

    nScrollPos=nScrollMax;

    break;

    case SB_LINELEFT:

    nScrollPos-=1;

    break;

    case SB_LINERIGHT:

    nScrollPos+=1;

    break;

    case SB_PAGELEFT:

    nScrollPos-=nPageSize;

    break;

    case SB_PAGERIGHT:

    nScrollPos+=nPageSize;

    break;

    case SB_THUMBPOSITION:

    nScrollPos=nPos; //由參數nPos獲取滾動框的位置

    break;

    case SB_THUMBTRACK:

    nScrollPos=nPos; //由參數nPos獲取滾動框的位置

    break;

    default:;

    }

    if(nScrollPos<nScrollMin)nScrollPos=nScrollMin;

    if(nScrollPos>nScrollMax)nScrollPos=nScrollMax;

    if(nScrollPos!=m_ScrollBar.GetScrollPos())

    m_ScrollBar.SetScrollPos(nScrollPos); //設置滾動框的新位置

    str.Format("%d",nScrollPos);

    m_Indicator.SetWindowText(str); //更新靜態正文

     

    CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

    }

     

    void CCtrlTestDlg::OnSelchangeCombobox()

    {

    // TODO: Add your control notification handler code here

     

    int length=m_MultiEdit.GetWindowTextLength();

    CString str;

    m_MultiEdit.SetSel(-1,0);

    m_MultiEdit.SetSel(length,length); //移動插入符到編輯正文的末尾

    m_ComboBox.GetLBText(m_ComboBox.GetCurSel(),str);

    str+=" selected/r/n";

    m_MultiEdit.ReplaceSel(str);

    }

      在OnInitDialog成員函數中,對一些控件進行了初始化,包括設置滾動條的范圍,將靜態正文的顯示置為 “0”,以及使組合框獲得輸入焦點.注意,缺省時,OnInitDialog返回TRUE,而新版的函數返回了FALSE.如果OnInitDialog返回TRUE,那么Windows將使tab順序最靠前的可輸入控件獲得輸入焦點,如果返回FALSE,則表明在OnInitDialog函數中人為地使某個控件獲得輸入焦點,函數返回后系統就不會再設置輸入焦點了.有時,只要合理的安排了控件的tab順序,就不必在OnInitDialog中人為設置輸入焦點.

      當用戶點擊Add按鈕或按回車鍵后,成員函數OnAdd被調用.該函數將組合框的編輯框中的字符串加入到List列表框的末尾,并將該字符串存入到記事列表框中.這時函數會判斷,如果在記事列表中沒有匹配的項,則把字符串插入0位置,并在必要時刪除最老的列表項,在本例中,記事列表框最多可以容納5項;如果在記事列表中有匹配的項,那么就把該項移到0位置.

      當用戶點擊Delete按鈕時,成員函數OnDelete被調用,該函數根據CComboBox::GetSelCount獲得選擇項的數目,并根據這個數目動態創建一個整型數組以存放選擇項的索引.然后,調用CComboBox::GetSelItems來獲取選擇項的索引.最后,把這些選擇項刪除.注意,這里是倒序刪除的,如果按順序刪除,則會使選擇項的索引產生錯位.

      成員函數OnSelchangeCombobox是Input組合框的CBN_SELCHANGE消息的處理函數.該函數先把多行編輯框的插入符移到編輯正文的末尾,然后從插入符處加入一行形如"XXXX selected"的字符串,以表明用戶從記事列表框中新選擇了哪個列表項.值得一提的是,上一章的Register程序是用SetWindowText來在編輯正文中插入新的正文的,此方法有一個缺點,就是不能把插入符滾動到新修改過的地方.在本例中,插入編輯正文的方法是先調用CEdit::SetSel移動插入符到指定位置(必要時要滾動以使該位置可見),然后再調用CEdit::ReplaceSel插入新的正文,這樣做的好處是編輯框總是滾動到新修改過的地方,從而使得新修改過的地方總是可見的.

      對滾動條控件的測試是在OnHScroll成員函數中完成的.該函數是對話框也即父窗口對水平滾動條控件產生的WM_HSCROLL消息的處理函數.該函數負責移動滾動框并及時更新靜態正文的顯示以反映滾動框的當前位置.在函數的開頭,首先判斷是不是m_ScrollBar滾動條發來的消息,這是因為可能會有幾個滾動條控件.在該函數中有一個大的switch分枝語句,用來獲取滾動框的新位置.需要指出的是,對于SB_THUMBPOSITION和SB_THUMBTRACK這兩種情況,應該從OnHScroll函數的nPos參數中獲取滾動框的新位置.對于SB_THUMBTRACK,不要企圖用CScrollBar::GetScrollPos來獲取滾動框的新位置,因為該函數不能正確返回拖動時的滾動框位置.另一個要注意的問題是Windows本身不會自動地使滾動框移動到新位置上,所以需要在OnHScroll中調用CScrollBar::SetScrollPos來移動滾動框.

    6.1.8 測試傳統控件的一個例子
    6.1.7 組合框控件
    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全