演練VC中的COMMON一族(轉貼)之一 選擇自 happyparrot 的 Blog

 

聲明:由於在CSDN論壇看到不少VC新手問及VC控件的使用。本人手頭正好有一份以前下載到的一份資料,講述的比較詳細。所以發出來和大家共享。但由於時間久遠,已不及得下載的地址了。所以只能以收藏方式發表。下面有原作者的單位和姓名。在此表示歉意!

演練VC中的COMMON一族
遼寧省鐵嶺市委辦公室(112000)宋立波
    1.表頭控制         Header Control 
    2.圖像列表控制     Image List
    3.列表控制和視     List Control&List View
    4.樹控制和視       Tree Control&Tree View
    5.標籤控制和視     Tab Control&Tab View
    6.工具條控制       Toolbar Control
    7.進度條控制       Progress Control
    8.滑動條控制      Slider Control
    9.旋轉按鈕控制    Spin Button Control
    10.狀態條控制      Status Bar Control
其中,絕大部分通用控制在MFC類庫中都存在兩種封裝形式,即控制類和視類,控制類主要是供直接使用控制而提供的,而視類則是通過間接使用控制而提供的,視類可以更好地把控制類集成到MFC結構中,並且使用視類可以利用引用直接對嵌套在其中的控制進行各種操作。兩者在使用方法上沒有太大區別,就拿列表控制類和視類來說,當創建列表視後可通過CListCtrl&  ctrlList =  GetListCtrl()成員函數取得視類引用ctrlList之後,就可以利用列表視的視函數對視進行各項操作(ctrlList.Add等)。

第1章 演練CHeadCtrl
    表頭控制(CHeaderCtrl)通常應用在窗口中的文本或數據的列表之上。一般爲數據列的標題,可以包括多個部分,用戶可以拖動每個部分並可以控制每列的寬度。表頭控制類提供了普通表頭控制的基本方法,只有在WINDOWS95以後版本系統中才提供,其方法包含在afxcmn.h文件中,一般與標籤控制(CTabCtrl)和列表控制(CListCtrl)組合使用。
1.1 表頭控制的對象結構
1.1.1 表頭控制對象的建立方法
    CHeaderCtrl &cheaderCtrl 建立表頭控制對象
    Create                     建立表頭並綁定對象
    CHeaderCtrl::Create的格式如下:BOOL Create( DWORD dwStyle, const RECT&
    rect, CWnd* pParentWnd, UINT nID );
    其返回值非零時初始化成功,否則失敗。
    參數dwStyle用來確定表頭控制類型;rect用來確定表頭控制的大小和位置;ParentWnd用來確定表頭控制的父窗口;nID用來表示表頭控制的標誌。
    表頭控制風格包括:
HDS_BUTTONS     表示表頭控制外觀類似按鈕;
HDS_HORZ        表示表頭控制爲水平排列;
    HDS_VERT        表示表頭控制爲垂直排列;
    HDS_HIDDEN      表示表頭控制爲隱藏模式。
它也可以使用普通類控制風格,包括:
    CCS_BOTTOM      設置控制位置在父窗口的底部並與父窗口同樣寬度;
    CCS_NODIVIDER   在控制頂部形成兩個像素的高亮區;
    CCS_NOHILITE    在控制頂部形成一個像素的高亮區;
    CCS_NOMOVEY     在響應WM_SIZE消息時重置大小並水平排列;
    CCS_NOPARENTALIGN  使控制自動靠近父窗口的頂部或底部;
    CCS_NORESIZE    設置初始大小或新值時使控制使用默認寬度和高度;
    CCS_TOP         設置在父窗口客戶區域的頂部並與父窗口同樣寬度;
    同樣表頭控制也可以使用窗口控制風格,包括:
    WS_CHILD        建立一個子窗口,不能用於WS_POPUP窗口類型;
    WS_VISIBLE      建立一個初始時不可見的窗口;
    WS_DISABLED     建立一個初始時無效的窗口;
    WS_GROUP        確定可用光標移動的控制羣組;
    WS_TABSTOP      確定可用TAB控制移動站點;
    表頭控制一般分爲兩個步驟,首先確定表頭控制的數據結構,然後建立表頭控制並綁定對象。
1.1.2 表頭控制的屬性
    表頭控制的屬性包括取得表頭控制中項目的數量GetItemCount、取得表頭控制中某一項目的內容GetItem和設置表頭控制中某一項目的內容SetItem。
1.1.3 表頭控制的操作方法
    表頭控制的操作方法包括向表頭控制中插入一個新項目InsertItem、從表頭控制中刪除一個項目DeleteItem和繪製表頭中給定的項目DrawItem等。
1.2 表頭控制的數據結構
    在使用表頭控制時,首先必須建立一個數據結構HD_ITEM,其結構定義如下:
    typedef struct _HD_ITEM
    { UINT    mask;        file://結構成員有效控制位
      int     cxy;         file://表頭項目的寬度
      LPSTR   pszText;     file://表頭項目內容
      HBITMAP hbm;         file://表頭項目的位置句柄
      int     cchTextMax;  file://表頭內容字符串長度
      int     fmt;         file://表頭項目的格式
      LPARAM  lParam;      file://應用程序定義的32位數據
    } HD_ITEM;
    屏蔽控制位說明了數據結構成員中包含的有效數據,可以是下面標誌的組合:
    HDI_BITMAP        hbm成員有效
    HDI_FORMAT        fmt 成員有效
    HDI_LPARAM        lParam成員有效
    HDI_TEXT          pszText 和cchTextMax 成員有效
    HDI_WIDTH         cxy 成員有效並確定項目寬度值
    格式標誌位fmt可以是以下標誌的組合:
    HDF_CENTER        表頭項目居中
    HDF_LEFT          表頭項目左對齊
    HDF_RIGHT         表頭項目右對齊
    HDF_BITMAP        表頭顯示一個位圖
    HDF_OWNERDRAW     由主窗口自繪表頭項目
    HDF_STRING        表頭項目爲一個字符串
1.3 表頭控制的應用技巧
    由於表頭控制無法單獨使用,其主要是配合列表控制和標籤控制,並多以文字表頭應用多見,InsertItem、SetItem和GetItem是常用的方法,如在列表控制時利用InsertColumn屬性就可以增加一個表列的文本標題,具體用法和技巧見列表控制和標籤控制。下面以在列表控制中的增加表列的方法來具體說明:
    lvcol.pszText="品  名";//設置第一列表頭名
    lvcol.iSubItem=i;      file://表列序號
    lvcol.cx=70;           file://表列寬度
    m_ListCtrl.InsertColumn(i++,&lvcol);//插入一個表列
    lvcol.pszText="數  量";//設置第二列表頭名
    lvcol.iSubItem=i;
    lvcol.cx=70;
    m_ListCtrl.InsertColumn(i++,&lvcol);//插入一個表列
    ......//其它代碼


第2章 演練CImageList
    圖像列表控制(CImageList)是相同大小圖像的一個集合,每個集合中均以0爲圖像的索引序號基數,圖像列表通常由大圖標或位圖構成,其中包含透明位圖模式。可以利用WINDOWS32位應用程序接口函數API來繪製、建立和刪除圖像,並能實現增加、刪除、替換和拖動圖像等操作。圖像列表控制提供了控制圖像列表的基本方法,這些方法在WINDOWS95及以後版本才能實現。
2.1 圖像控制的對象結構
2.1.1 圖像控制的數據成員
    m_hImageList         連接圖像對象的控制句柄
2.1.2 圖像控制的建立方法
    CimageList&imageList建立圖像控制對象結構
    Create               初始化圖像列表並綁定對象
    圖像控制的建立方法如下:
    BOOL Create( int cx, int cy, UINT nFlags, int nInitial, int nGrow );
    BOOL Create( UINT nBitmapID, int cx, int nGrow, COLORREF crMask );
    BOOL Create( LPCTSTR lpszBitmapID, int cx, int nGrow, COLORREF crMask );
BOOL Create( CImageList& imagelist1, int nImage1, CImageList& imagelist2
  ,int  nImage2,int dx, int dy );
    其中各項參數的含義爲:cx定義圖像的寬度,單位爲象素;cy定義圖象的高度,單位爲象素;nFlags確定建立圖像列表的類型,可以是以下值的組合:ILC_COLOR、ILC_COLOR4、ILC_COLOR8、ILC_COLOR16、ILC_COLOR24、ILC_COLOR32、ILC_COLORDDB和ILC_MASK;nInitial用來確定圖像列表包含的圖像數量;nGrow用來確定圖像列表可控制的圖像數量。
    NbitmapID    用來確定圖像列表聯繫的位圖標誌值;crMask表示顏色屏蔽位;
    LpszBitmapID 用來確定包含位圖資源的標識串;
imagelist1    指向圖像列表控制對象的一個指針;nImage1圖像列表1中包含的圖像數    量;imagelist2指向圖像列表控制對象的一個指針;nImage2圖像列表2中包含的圖像數量;dx表示以象素爲單位的圖像寬度;dy表示以象素爲單位的圖像高度。
同樣,圖像控制的建立也包括兩個步驟,首先建立圖像列表結構,然後建立圖像列表控制。
2.1.3 圖像控制的屬性類
    圖像控制的屬性類包括返回m_hImageList.控制句柄GetSafeHandle、取得圖像列表中的圖像數量GetImageCount、設置圖像列表的背景顏色SetBkColor、取得圖像列表的背景顏色SetBkColor和取得圖像的有關信息SetBkColor。
2.1.4 圖像控制的操作方法
    圖像控制的操作方法包括將一個圖像列表綁定到一個對象上Attach、將對象上的圖像列表解除綁定並返回句柄Detach、刪除一個圖像列表DeleteImageList、將一個圖像增加到圖像列表中Add和將一個圖像從圖像列表中刪除Remove等。
2.2 圖像控制的應用技巧
    對於圖像控制,同樣不能單獨使用,必須與列表控制、樹控制和標籤控制相互結合應用,下面分別介紹其具體應用技巧。
2.2.1 圖像控制在列表控制中的應用技巧
2.2.1.1 設置圖像控制CListCtrl::SetImageList的調用格式如下:
    CImageList* SetImageList( CImageList* pImageList, int nImageList );
    其返回值是指向前一個圖像列表控制的一個指針,如果不存在前一個圖像列表則爲NULL;其中參數pImageList是指向圖像列表的標識,nImageList是圖像列表的類型,可以是如下值:
    LVSIL_NORMAL     用大圖標方式進行圖像列表;
    LVSIL_SMALL     用小圖標方式進行圖像列表;
    LVSIL_STATE     以圖像狀態進行圖像列表;
2.2.1.2 取得圖像控制CListCtrl::GetImageList的調用格式如下:
    CImageList* GetImageList( int nImageList ) const;
    其返回值爲指向圖像列表控制的指針,其中nImageList用來確定取得返回值的圖像列表的    值,其取值與設置圖像列表函數相同。
    ③圖像控制在列表控制中的應用示例
    CImageList Cil1,Cil2;            file://定義大小圖標像列表
    CVCLISTApp *pApp=(CVCLISTApp *)AfxGetApp();//取得列表控制程序
    Cil1.Create(32,32,TRUE,2,2);     file://建立32位圖像控制
    Cil1.Add(pApp->LoadIcon(IDI_GJ));//增加選中狀態圖像
    Cil1.Add(pApp->LoadIcon(IDI_XS));//增加非選中狀態圖像
    Cil2.Create(16,16,TRUE,2,2);     file://建立16位圖像控制
    Cil2.Add(pApp->LoadIcon(IDI_GJ));//增加選中狀態圖像
    Cil2.Add(pApp->LoadIcon(IDI_XS));//增加非選中狀態圖像
    m_ListCtrl.SetImageList(&Cil1,LVSIL_NORMAL);//設置大圖標控制
    m_ListCtrl.SetImageList(&Cil2,LVSIL_SMALL);//設置小圖標控制
2.2.2 圖像控制在樹控制中的應用技巧
2.2.2.1 設置圖像控制CTreeCtrl::SetImageList的調用格式如下:
    CImageList* SetImageList( CImageList * pImageList, int nImageListType );
    其返回值爲指向前前一個圖像列表的指針,否則爲NULL;參數pImageList爲指向圖像列表的標識,如果pImageList爲NULL則所有的圖像都將從樹控制中被清除;nImageListType爲圖像列表設置的類型,可以是如下值之一:
    TVSIL_NORMAL   設置正常圖像列表,其中包括選中和非選中兩種圖標;
    TVSIL_STATE   設置圖像列表狀態,指用戶自定義狀態;
2.2.2.2 取得圖像控制CTreeCtrl::GetImageList的調用格式如下:
    CImageList* GetImageList( UINT nImage );
    如果調用成功則返回圖像列表控制指針,否則爲NULL;nImage爲取得返回值的圖像列表類型,其取值和取得圖像列表控制完全相同。
2.2.2.3 圖像控制在樹控制中的應用示例
    CImageList Cil1,Cil2;//定義大小圖標像列表
    CVCTREEApp *pApp=(CVCTREEApp *)AfxGetApp();//獲取應用程序指針
    Cil1.Create(16,16,ILC_COLOR,2,2);//建立圖像控制
    Cil1.Add(pApp->LoadIcon(IDI_PM));//增加選中狀態圖像
    Cil1.Add(pApp->LoadIcon(IDI_CJ));//增加非選中狀態圖像
    m_TreeCtrl.SetImageList(&Cil1,TVSIL_NORMAL);//設置圖像控制列表
    然後在樹控制的結構定義中進行如下設置:
    TCItem.item.iImage=0;        file://設置未選中圖像索引號
    TCItem.item.iSelectedImage=1;//設置選中時圖像引號
2.2.3 圖像控制在標2.2.4 籤控制中的應用技巧
2.2.4.1 設置圖像控制CTabCtrl::SetImageList的調用格式
    CImageList * SetImageList( CImageList * pImageList );
    其返回值爲指向前一個圖像列表的指針,如果不存在前一個圖像列表則爲NULL;pImageList爲標識TAB控制的圖像列表指針。
2.2.4.2 取得圖像控制CTabCtrl::GetImageList的調用格式
    HIMAGELIST GetImageList() const;
    其返回值爲指向TAB控制的圖像列表指針,如果調用不成功則爲NULL。
    其應用技巧較前兩種更加簡單,這裏不再贅述。


第3章 演練CList
3.1 列表控制的主要功能
    列表控制和視(List Control&View)主要用來以各種方式顯示一組數據記錄供用戶進行各種操作,Windows98/95中資源管理器中的“查看”標籤下的“大圖標|小圖標|列表|詳細資源”就是一個非常好的典型應用。列表中的記錄可以包括多個數據項,也可以包括表示數據內容的大小圖標,用來表示數據記錄的各種屬性。
    列表控制提供了對Windows列表功能操作的基本方法,而使用列表視的視函數可以對列表視進行各種操作,通過調用視成員GetListCtrl獲取嵌在列表視內列表控制的引用(GetListCtrl&  ctrlList  =  GetListCtrl()),就可以和列表控制一樣進行各種操作。操作一個列表控制和視的基本方法爲:創建列表控制;創建列表控制所需要的圖像列表;向列表控制添加表列和表項;對列表進行各種控制,主要包括查找、排序、刪除、顯示方式、排列方式以及各種消息處理功能等;最後撤消列表控制。
    對於一個列表控制,其最典型最常用的顯示控制方式爲:大圖標方式(LVS_ICON)、小圖標方式(LVS_SMALLICON)、列表顯示方式(LVS_LIST)和詳細資料(即報告LVS_REPORT)顯示方式。這可以通過設置其顯示方式屬性來實現。要控制列表所在窗口的風格,可通過功能函數GetWindowLong和SetWindowLong來實現,要控制列表圖標的對齊方式,可通過設置列表窗口的風格LVS_ALIGNTOP或LVS_ALIGNLEFT來實現,
3.2 列表控制的對象結構
3.2.1 列表控制的建立方法
    CListCtrl&listCtrl  定義列表對象的結構
    Create               建立列表控制並綁定對象
列表控制CListCtrl::Create的調用格式如下:
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
其中參數dwStyle用來確定列表控制的風格;rect用來確定列表控制的大小和位置;pParentWnd用來確定列表控制的父窗口,通常是一個對話框;nID用來確定列表控制的標識。其中列表控制的風格可以是下列值的組合:
    LVS_ALIGNLEFT      用來確定表項的大小圖標以左對齊方式顯示;
    LVS_ALIGNTOP       用來確定表項的大小圖標以頂對齊方式顯示;
    LVS_AUTOARRANGE    用來確定表項的大小圖標以自動排列方式顯示;
    LVS_EDITLABELS     設置表項文本可以編輯,父窗口必須設有LVN_ENDLABELEDIT風格;
    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 用來確定表項排序時是基於表項文本的降序方式;
3.2.2 列表控制的屬性類
列表控制的屬性類包括取得列表控制的背景色GetBkColor、設置列表控制的背景色SetBkColor、取得列表控制的圖像列表GetImageList、設置列表控制的圖像列表SetImageList、取得列表項數目GetItemCount、取得列表控制的屬性GetItem、取得與表項相關的數據GetItemData、設置表項的屬性SetItem、設置與表項相關的數值SetItemData、取得相關聯的下一個表項GetNextItem、設置列表控制的文本顏色SetTextColor、取得列表控制的文本背景顏色GetTextBkColor、設置表項的最大數目SetItemCount和取得被選中表項的數目GetSelectedCount等。
3.2.3 列表控制的操作方法
    列表控制的操作方法包括插入一個新的表項InsertItem、刪除一個表項DeleteItem、排序表項SortItems、測試列表的位置HitTest、重繪表項RedrawItems、插入一個表列InsertColumn、刪除一個表列DeleteColumn、編輯一個表項文本EditLabel和重繪一個表項DrawItem等。
3.3 列表控制的數據結構
列表控制中包含兩個非常重要的數據結構LV_ITEM和LV_COLUMN。LV_ITEM用於定義列表控制的一個表項,LV_COLUMN用於定義列表控制的一個表列,其定義格式分別爲:
typedef struct _LV_ITEM {
   UINT   mask;       file://結構成員屏蔽位
     int    iItem;      file://表項索引號
int    iSubItem;   file://子表項索引號
UINT   state;      file://表項狀態
UINT   stateMask;  file://狀態有效性屏蔽位
LPTSTR  pszText;   file://表項名文本
int    cchTextMax; file://表項名最大長度
int    iImage;     // 表項圖標的索引號
LPARAM lParam;     // 與表項相關的32位數
} LV_ITEM;
    typedef struct _LV_COLUMN {
        UINT mask;         file://結構成員有效性屏蔽位
        int fmt;           file://表列對齊方式
        int cx;            file://表列的象素寬度
        LPTSTR pszText;    file://表列的表頭名
        int cchTextMax;    file://表列名的文本長度
        int iSubItem;      file://與表列關聯的子表項索引號
} LV_COLUMN;
其中fmt可以取如下值:
LVCFMT_CENTER        表列居中對齊
LVCFMT_LEFT          表列左對齊
3.4 列表控制的應用技巧示例
    本文給出具體實例演示列表控制及前面的表頭控制和圖像列表的應用技巧。步驟如下:
1、通過“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名爲VCLIST的工程,在建立過程中選擇基於對話框(Dialog based)的應用;將對話框中的默認控件刪除,並將所有對話框屬性中的Language域設置爲Chinese(P.R.C.),以使應用程序支持中文;
建立兩個圖標IDI_GJ和IDI_XS,用來表示圖標的選中和非選中狀態,對於每個圖標都應建立32X32和16X16兩種大小,以保證程序的需要;
    3、在對話框窗口中設計組合框(Group Box),組合框中設置四個無線按鈕(Radio)“大圖標|小圖標|列表|資料”,同時設置排序、刪除和關閉三個控制按鈕(Button),並在對話框中設置大小合適的列表控制(List Ctrl),其對應標識分別如下:
    控制名稱        標題名稱                標識符號
    列表控制                             IDC_LISTCTRL
    組合框          方式     IDC_STATIC
    無線按鈕        大圖標            IDC_STDICON
                    小圖標              IDC_SMLICON
                 列  表               IDC_LIST
                    資  料               IDC_REPORT
    按鈕            排  序        IDC_SORT
                    刪  除               IDC_DEL
                    關  閉               IDOK
    4、在設置無線按鈕時,需要注意的是隻有大圖標的Group屬性爲選中狀態,而其它無線按鈕的狀態均爲默認值。
    5、選中列表控制控件,選擇“VIEW->ClassWizard->Memory Variables”,並利用IDC_  LISTCTRL引入成員變量,其變量類型爲:
    變量名            種類            變量類型
    m_ListCtrl        Control         ClistCtrl
    同時利用“MESSAGES MAP”爲各無線按鈕和命令按鈕增加控制功能。
    6、然後在包含文件和代碼文件中分別加入如下代碼:
    (1)在VCLISTDlg.h中增加數據結構和定義
    typedef struct tagSPS { file://定義結構
   char szPm[10];     file://品
   int  Lx;           file://0-GJ 1-XS
   char szSl[10];     file://數
   char szDj[10];     file://單
   char szJe[10];     file://金
    } SPS;
    int CALLBACK CompareFunc(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort);
   (2)在VCLISTDlg.CPP中的起始處增加初始化數據和程序定義
    file://在文件開始處增加數據結構初始化
    SPS Sps[]={//信息
        {"紅梅",0,"1000","30","30000"},
        {"黃梅",0,"1000","29","29000"},
        {"綠梅",0,"1000","28","28000"},
        {"青梅",0,"1000","27","27000"},
        {"白梅",0,"1000","31","31000"},
        {"紅梅",1,"1000","30","30000"},
        {"黃梅",1,"1000","29","29000"},
        {"綠梅",1,"1000","28","28000"},
        {"青梅",1,"1000","27","27000"},
       {"白梅",1,"1000","31","31000"}};
    CImageList Cil1,Cil2;//大小圖像列表
    (3)在程序初始化處增加表頭、圖像和列表控制建立代碼
    BOOL CVCLISTDlg::OnInitDialog()
    {CDialog::OnInitDialog();
    file://......//其它代碼
    // TODO: Add extra initialization here此處增加代碼
    LV_ITEM lvitem;
    LV_COLUMN lvcol;
    int i,iPos,iItemNum;
    CVCLISTApp *pApp=(CVCLISTApp *)AfxGetApp();//創建圖象列表
    Cil1.Create(32,32,TRUE,2,2);
    Cil1.Add(pApp->LoadIcon(IDI_GJ));
    Cil1.Add(pApp->LoadIcon(IDI_XS));
    Cil2.Create(16,16,TRUE,2,2);
    Cil2.Add(pApp->LoadIcon(IDI_GJ));
    Cil2.Add(pApp->LoadIcon(IDI_XS));//設置圖象列表
    m_ListCtrl.SetImageList(&Cil1,LVSIL_NORMAL);
    m_ListCtrl.SetImageList(&Cil2,LVSIL_SMALL);//向列表控制中添加表列
    lvcol.mask=LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;
    lvcol.fmt=LVCFMT_CENTER;//居中
    i=0;
    lvcol.pszText="品  名";
    lvcol.iSubItem=i;
    lvcol.cx=70;
    m_ListCtrl.InsertColumn(i++,&lvcol);
    lvcol.pszText="數  量";
    lvcol.iSubItem=i;
    lvcol.cx=70;
    m_ListCtrl.InsertColumn(i++,&lvcol);
    lvcol.pszText="單  價";
    lvcol.iSubItem=i;
    lvcol.cx=70;
    m_ListCtrl.InsertColumn(i++,&lvcol);
    lvcol.pszText="金  額";
    lvcol.iSubItem=i;
    lvcol.cx=70;
    m_ListCtrl.InsertColumn(i++,&lvcol);
    file://向列表控制中添加表項
    iItemNum=sizeof(Sps)/sizeof(SPS);
    for(i=0;i<iItemNum;i++){
  lvitem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
  lvitem.iItem=i;
  lvitem.iSubItem=0;
  lvitem.pszText=Sps[i].szPm;
  lvitem.iImage=Sps[i].Lx;
  lvitem.lParam=i;
  iPos=m_ListCtrl.InsertItem(&lvitem);//返回表項插入後的索引號
  lvitem.mask=LVIF_TEXT;
  lvitem.iItem=iPos;
  lvitem.iSubItem=1;
  lvitem.pszText=Sps[i].szSl;
  m_ListCtrl.SetItem(&lvitem);
  lvitem.iSubItem=2;
  lvitem.pszText=Sps[i].szDj;
  m_ListCtrl.SetItem(&lvitem);
  lvitem.iSubItem=3;
  lvitem.pszText=Sps[i].szJe;
  m_ListCtrl.SetItem(&lvitem);
    }
    CheckRadioButton(IDC_STDICON,IDC_REPORT,IDC_STDICON);
    return TRUE;  // return TRUE  unless you set the focus to a control
    }
    (4)完善列表顯示方式代碼
    在利用Classwizard類嚮導創建各功能按鈕顯示功能函數之後,必須依次完善這些功能函數的代碼,這些功能函數如下:
void CVCLISTDlg::OnStdicon()//設置大圖標顯示方式
{ // TODO: Add your control notification handler code here
 LONG lStyle;
 lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型
 lStyle&=~LVS_TYPEMASK; file://清除顯示方式位
 lStyle|=LVS_ICON;       file://設置顯示方式
 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型
}
void CVCLISTDlg::OnSmlicon() file://設置小圖標顯示方式
{ // TODO: Add your control notification handler code here
 LONG lStyle;
 lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型
 lStyle&=~LVS_TYPEMASK; file://清除顯示方式位
 lStyle|=LVS_SMALLICON;  file://設置顯示方式
 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型
}
void CVCLISTDlg::OnList() file://設置列表顯示方式
{ // TODO: Add your control notification handler code here
 LONG lStyle;
 lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型
 lStyle&=~LVS_TYPEMASK; file://清除顯示方式位
 lStyle|=LVS_LIST;       file://設置顯示方式
 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型
}
void CVCLISTDlg::OnReport() file://詳細資料顯示方式
{ // TODO: Add your control notification handler code here
 LONG lStyle;
 lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型
 lStyle&=~LVS_TYPEMASK; file://清除顯示方式位
 lStyle|=LVS_REPORT;     file://設置顯示方式
 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型
}
    (5)刪除功能的實現
    要實現刪除功能,必須取得選中表項的數和表項總數,並且需要從後向前進行依次刪除,其原因是每個表項被刪除後,其後各表項的索引號均會發生遞減變化,如果採取從前向後刪除的方法,就會造成無法正常刪除選中的表項,其功能代碼如下:
void CVCLISTDlg::OnDel() file://刪除按鈕功能
{ // TODO: Add your control notification handler code here
 int i,iState;
 int nItemSelected=m_ListCtrl.GetSelectedCount();//所選表項數
 int nItemCount=m_ListCtrl.GetItemCount();//表項總數
 if(nItemSelected<1) return;
 for(i=nItemCount-1;i>=0;i--){
  iState=m_ListCtrl.GetItemState(i,LVIS_SELECTED);
  if(iState!=0) m_ListCtrl.DeleteItem(i);
 }
}
    (6)排序功能的實現
    列表控制有一個特殊的功能,當以詳細資料方式顯示時,列表頂部的表頭可以當作按鈕來使用,這可以通過列表控制創建時的風格來控制。當鼠標點擊列表頭名稱時,列表控制就會向其父窗口發送一個LNV_COLUMNCLICK消息,利用類導向中列表控制IDC_LISTCTRL對應的LNV_COLUMNCLICK消息加入相應處理函數,就可將表列按照特定順序進行排列。其函數使用方法見程序,其中iSort爲排序的表列索引號,(PFNLVCOMPARE)CompareFunc爲進行具體排序的回調函數,也就是說,通過鼠標點擊表頭實現的排序過程是由第三方開發的專用排序函數來實現的,排序函數只是實現表項的具體比較操作,而整個排序過程是由SortItemS屬性通過不斷調用這個函數來實現的。正常的排序過程是升序方式,通過調換排序函數中的參數值,就可實現降序排列,即將PARAM1與PARAM2調換位置。這個回調函數的前兩個參數爲表列中表項的索引號,第三個參數爲排序的表列索引號。
void CVCLISTDlg::OnColumnclickListctrl(NMHDR* pNMHDR, LRESULT* pResult)
{   file://鼠標左鍵單擊表頭處理函數
 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 static int iSorted=-1;//排列序號
 if (pNMListView->iSubItem==iSorted) return;
 iSorted=pNMListView->iSubItem;
 m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,iSorted);
 *pResult = 0;
}
    file://排序時比較表項的回調函數
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort)
{ char *text1,*text2;
    switch (lParamSort){
 case 0L:text1=Sps[lParam1].szPm;
    text2=Sps[lParam2].szPm;break;
 case 1L:text1=Sps[lParam1].szSl;
    text2=Sps[lParam2].szSl;break;
 case 2L:text1=Sps[lParam1].szDj;
    text2=Sps[lParam2].szDj;break;
 case 3L:text1=Sps[lParam1].szJe;
    text2=Sps[lParam2].szJe;break;
 }
 return (strcmp(text1,text2));//結果爲>0 =0 <0
}
    同樣,也可以通過專用按鈕來實現排序功能,如本文的排序按鈕對應的功能代碼如下:
void CVCLISTDlg::OnSort()
{ // TODO: Add your control notification handler code here
 m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,0);}
    7、列表視的演練技巧
在使用列表視時,其方法與列表控制基本相同,只不過列表視是在窗口中來實現的而列表控制是在對話框中實現,列表視的各種功能是通過菜單來實現的而列表控制是通過按鈕等方式來實現的,列表控制需要在對話框中創建列表控制控件而列表視直接佔據整個窗口,在設計過程中只要將按鈕和列表控制設計過程變爲菜單設計,並注意在功能增加是在類嚮導中是通過菜單命令來操作,同時在每個功能函數前面增加取得列表視引用的命令( CListCtrl& ListCtrl = GetListCtrl()),而其餘數據結構和代碼均不需要修改,實現起來比較容易。
筆者實現的列表控制和視程序的運行結果如下:
                    列表控制演練示例結果

                  列表視演練示例結果


第4章 演練CTree
4.1 樹控制的主要功能
    樹控制和視(Tree Control&View)主要用來顯示具有一定層次結構的數據項,如資源管理器中的磁盤目錄等,以供用戶在其中進行各種選擇。樹控制中的每個數據項包括數據項名稱的文本字符串和用於表示該數據項的圖像,每個數據項下面均可包含各種子項,整個結構就象目錄樹一樣。對於包含各種子項的數據項,可通過鼠標雙擊來展開或合攏,這可以通過控制樹的不同風格來實現樹控制的不同顯示形態。這些風格主要包括:
    TVS_HASLINES表示用連線來連接父項和它下面的各個子項,這可以使樹的顯示層次結構更加清晰,但在無父項的各子項之間並沒有連線;
    TVS_LINESATROOT表示在無父項的各子項即根下面的各子項之間存在連線;
    TVS_HASBUTTONS表示在帶有子項的父項前面增加一個帶“+”或“-”的按鈕,這使得用戶也可以通過單擊這個小按鈕來實現子項的展開和合攏,當存在子項時,按鈕的初始狀態爲“+”,當子項被展開時,按小按鈕由“+”變爲“-”號,當子項合攏時,小按鈕由“-”變爲“+”號,這一風格同樣對於根項無效,如果需要可通過組合TVS_LINESATROOT風格來實現;
    TVS_EDITLABELS表示允許讓用戶單擊具有輸入焦點的數據項來修改其名稱。
對於樹控制,MFC中也以兩種形式來封裝,即樹控制(CTREECTRL)和樹視(CTREEVIEW),來滿足用戶的不同需求,對於一般要求的用戶如在對話框中應用,使用樹控制比較方便,而對於具有較高要求的用戶,在使用樹視時還具有視窗口的各種方便特性,可以更好地滿足文檔/視結構的要求。當在窗口中使用樹視時,樹視會佔滿兩個窗口的客戶區域並自動隨窗口的框架結構的調整而調整,並能夠很好地處理諸如菜單、加速鍵和工具條中的各種命令消息。在使用樹視時只要利用其成員函數CtreeView取得其一個引用,就可以象樹控制一樣方便地應用:CtreeCtrl &treeCtrl = GetTreeCtrl()。
4.2 樹控制的對象結構
4.2.1 樹控制的建立方法
    CtreeCtrl&treeCtrl  建立樹控制對象結構
    Create               建立樹控制並綁定對象
    樹控制CTreeCtrl::Create的調用格式如下:
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
    其中參數dwStyle用來確定樹控制的類型;rect用來確定樹控制的大小和位置;pParentWnd用來確定樹控制的父窗口,通用是一個對話框並且不能爲NULL;nID用來確定樹控制的標識。樹控制的風格可以是下列值的組合:
    TVS_HASLINES       表示樹控制在各子項之間存在連線;
    TVS_LINESATROOT    表示樹控制在根項之間存在連線;
    TVS_HASBUTTONS     表示樹控制視在父項左側存在展開合攏控制按鈕;
    TVS_EDITLABELS     表示可以控制鼠標單擊修改樹項的名稱;
    TVS_SHOWSELALWAYS  表示選中項即使在窗口失去輸入焦點時仍然保持選中狀態;
    TVS_DISABLEDRAGDROP表示禁止樹控制發送TVN_BEGINDRAG消息
4.2.2 樹控制的屬性類
    樹控制屬性類包括取得樹控制中項數GetCount、取得樹控制中項相對於父項的偏移值GetIndent、取得樹控制圖像列表控制句柄GetImageList、設置樹控制圖像列表控制句柄SetImageList、取得匹配下一個樹項GetNextItem、判斷給定樹項是否包含子項ItemHasChildren、取得樹項子項GetChildItem、取得下一個同屬樹項GetNextSiblingItem、取得前一個同屬樹項GetPrevSiblingItem、取得父樹項GetParentItem、取得第一個可視樹項GetFirstVisibleItem、取得下一個可視樹項GetNextVisible  Item、取得前一個可視的樹項GetPrevVisibleItem、取得被選中的樹項GetSelectedItem、取得根樹項GetRootItem、取得樹項的屬性GetItem、設置樹項的屬性SetItem、取得樹項的狀態GetItemState、設置樹項的狀態SetItemState、取得與樹項關聯圖像GetItemImage、設置與樹項關聯圖像SetItemImage、取得樹項文本GetItemText、設置樹項文本SetItemText和取得樹項編輯控制句柄GetEditControl等。
4.2.3 樹控制的操作方法
    樹控制的操作方法包括插入一個樹項InsertItem、刪除一個樹項DeleteItem、刪除所有樹項DeleteAllItems、展開或合攏樹項的子項Expand、選中特定樹項SelectItem、選擇一個樹項作爲第一個可視樹項SelectSetFirstVisible、編輯一個可視的樹項EditLabel和排序給定父樹項的子樹項SortChildren等。
4.3 樹控制的數據結構
    在使用樹控制時需要了解兩個個非常重要的數據結構TV_ITEM和TV_INSERTSTRUCT,前一個數據結構是用來表示樹控制的樹項信息,後一個數據結構是用來定義將樹項增加到數據控制中所需要的數據內容。另外,還需要NM_TREEVIEW、TV_DISPINFO和TV_HITTESTINFO三個數據結構,這幾個數據結構的定義方法如下:
4.3.1 基本數據項結構
typedef struct _TV_ITEM {
    UINT       mask;       file://結構成員有效性屏蔽位
    HTREEITEM  hItem;      file://數據項控制句柄
    UINT       state;      file://數據項狀態
    UINT       stateMask;  file://狀態有效性屏蔽位
    LPSTR      pszText;    file://數據項名稱字符串
    int        cchTextMax; file://數據項名稱的最大長度
    int        iImage;     file://數據項圖標索引號
    int        iSelectedImage;//選中數據項圖標索引號
    int        cChildren;  file://子項標識
    LPARAM     lParam;     file://程序定義的32位數據
} TV_ITEM, FAR *LPTV_ITEM;
4.3.2 插入樹項結構
    typedef struct _TV_INSER TSTRUCT {
    HTREEITEM hParent;      file://父項控制句柄
    HTREEITEM hInsertAfter; file://插入樹項的位置
    TV_ITEM   item;         file://數據項的結構
    } TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;
    其中插入的位置如果是TVI_FIRST 或TVI_LAST ,則分別插入到樹控制的最前面或最後面,如果是TVI_SORT ,則插入的樹項自動插入到合適的位置。
4.3.3 樹控制通知消息結構
    typedef struct _NM_TREEVIEW {
    NMHDR    hdr;     file://通知消息句柄
    UINT     action;  file://通知消息標誌
    TV_ITEM  itemOld; file://原來的數據結構
    TV_ITEM  itemNew; file://新的數據結構
    POINT    ptDrag;  file://拖動指針
    } NM_TREEVIEW;
4.3.4 取得或設置數據結構
    typedef struct _TV_DISPINFO {  tvdi
    NMHDR   hdr;      file://通知消息控制句柄
    TV_ITEM item;     file://數據項結構
    } TV_DISPINFO;
4.3.5 指4.3.6 針測試數據結構
    typedef struct _TVHITTESTINFO {  tvhtst
    POINT     pt;     file://客戶區域屏幕座標指針
    UINT      flags;  file://存放測試結果的變量
    HTREEITEM hItem;  file://測試的數據項結構
    } TV_HITTESTINFO, FAR *LPTV_HITTESTINFO;
    其中flags測試結果可以是如下值:
    TVHT_ABOVE        在客戶區域上面
    TVHT_BELOW        在客戶區域下面
    TVHT_NOWHERE      在客戶區域中並在最後一項下面
    TVHT_ONITEM       在與樹項關聯的位圖或標籤內
    TVHT_ONITEMBUTTON 在與樹項關聯的按鈕上
    TVHT_ONITEMICON   在與樹項關聯的位圖上
    TVHT_ONITEMINDENT 在與樹項關聯的聯線上
    TVHT_ONITEMLABEL  在與樹項關聯的標籤上
    TVHT_ONITEMRIGHT  在樹項的右側區域中
    TVHT_ONITEMSTATEICON 在用戶定義的狀態圖標上
    TVHT_TOLEFT       在客戶區域的左側
    TVHT_TORIGHT      在客戶區域的右側
4.4 樹控制的應用技巧示例
    這裏仍以基於對話框演示實例來具體介紹樹控制及其和圖像列表相結構的應用技巧:
    通過“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名爲VCTREE的工程,在建立過程中選擇基於對話框(Dialog based)的應用;將對話框中的默認控件刪除,並將所有對話框屬性中的Language域設置爲Chinese(P.R.C.),以使應用程序支持中文;建立兩個圖標IDI_PM和IDI_CJ,用來表示圖標的選中和非選中狀態,對於每個圖標都應建立32X32和16X16兩種大小,以保證程序的需要;在對話框窗口中添加樹控制對象(TREE  CONTROL),並設置五個按鈕“增加|刪除|查看|排序|關閉”,其對應標識分別如下:
   控制名稱        標題名稱                標識符號
    樹控制                                  IDC_TREECTRL
    按鈕            增  加                  IDC_ADD
                    刪  除                  IDC_DEL
                    查  看                  IDC_VIEW
                    排  序                  IDC_SORT
                    關  閉                  IDOK
    5、選中樹控制控件,選擇“VIEW->ClassWizard->Memory Variables。骺刂艻DC_TREECTRL         引入成員變量,其變量類型爲:
      變量名            種類            變量類型
    m_TreeCtrl        Control         CTreeCtrl
    同時利用“MESSAGES MAP”爲各命令按鈕增加控制功能函數。
    6、然後在代碼文件VCTREEDlg.CPP中分別加入如下控制代碼:
    (1)在文件開始處增加圖像列表定義
    CImageList Cil1,Cil2;//大小圖標像列表
    (2)在初始化文件開始處增加代碼
    BOOL CVCTREEDlg::OnInitDialog()
    { CDialog::OnInitDialog();
    ......//原來其它代碼
    // TODO: Add extra initialization here
    // 此處開始增加代碼
    CVCTREEApp *pApp=(CVCTREEApp *)AfxGetApp();//創建圖象列表
    Cil1.Create(16,16,ILC_COLOR,2,2);
    Cil1.Add(pApp->LoadIcon(IDI_PM));
    Cil1.Add(pApp->LoadIcon(IDI_CJ));
    m_TreeCtrl.SetImageList(&Cil1,TVSIL_NORMAL); file://設置圖象列表
    DWORD dwStyles=GetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE);//獲取樹控制原風格
    dwStyles|=TVS_EDITLABELS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT;
    SetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE,dwStyles);//設置風格
    char * CJ[4]={"玉溪捲菸廠","雲南捲菸廠","瀋陽捲菸廠","成都捲菸廠"};//根數據名稱
    char * PM[4][5]={
  {"紅梅一","紅梅二","紅梅三","紅梅四","紅梅五"},//產品數據項
  {"白梅一","白梅二","白梅三","白梅四","白梅五"},
  {"綠梅一","綠梅二","綠梅三","綠梅四","綠梅五"},
  {"青梅一","青梅二","青梅三","青梅四","青梅五"}};
    int i,j;
    HTREEITEM hRoot,hCur;//樹控制項目句柄
    TV_INSERTSTRUCT TCItem;//插入數據項數據結構
    TCItem.hParent=TVI_ROOT;//增加根項
    TCItem.hInsertAfter=TVI_LAST;//在最後項之後
    TCItem.item.mask=TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;//設屏蔽
    TCItem.item.pszText="數據選擇";
    TCItem.item.lParam=0;//序號
    TCItem.item.iImage=0;//正常圖標
    TCItem.item.iSelectedImage=1;//選中時圖標
    hRoot=m_TreeCtrl.InsertItem(&TCItem);//返回根項句柄
    for(i=0;i<4;i++){//增加各廠家
  TCItem.hParent=hRoot;
  TCItem.item.pszText=CJ[i];
  TCItem.item.lParam=(i+1)*10;//子項序號
  hCur=m_TreeCtrl.InsertItem(&TCItem);
  for(j=0;j<5;j++){//增加各產品
   TCItem.hParent=hCur;
   TCItem.item.pszText=PM[i][j];
   TCItem.item.lParam=(i+1)*10+(j+1);//子項序號
   m_TreeCtrl.InsertItem(&TCItem);
  }
     m_TreeCtrl.Expand(hCur,TVE_EXPAND);//展開樹
    }
    m_TreeCtrl.Expand(hRoot,TVE_EXPAND);//展開上一級樹
    return TRUE;  // return TRUE  unless you set the focus to a control
    }
    (3)增加樹項功能的實現
    在增加樹項功能時,除了需要定義和設置插入樹項的數據結構之外,還需要注意的是新增樹項的名稱初始時均爲“新增數據”,增加後允許用戶給數據項設置自定義名稱。在編程時應特別注意m_TreeCtrl.EditLabel(hInsert);後面不能跟任何其它程序命令,否則這條編輯指令無效。
    void CVCTREEDlg::OnAdd()
    { file://增加子項功能函數
    HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選擇項句柄
    if(hSel==NULL) return;//無任何選項則返回
    static int nAddNo=100;//編號大於100爲新增數據
    TV_INSERTSTRUCT TCItem;//定義插入項數據結構
    TCItem.hParent=hSel;   file://設置父項句柄
    TCItem.hInsertAfter=TVI_LAST;//在最後增加
    TCItem.item.mask=TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;//設屏蔽
    TCItem.item.pszText="新增數據";
    TCItem.item.lParam=nAddNo++;//索引號增加
    TCItem.item.iImage=0;//正常圖標
    TCItem.item.iSelectedImage=1;//選中時圖標
    HTREEITEM hInsert=m_TreeCtrl.InsertItem(&TCItem);//增加
    m_TreeCtrl.Expand(hSel,TVE_EXPAND);
    m_TreeCtrl.EditLabel(hInsert);//修改增加的數據
    }
    (4)刪除樹項功能的實現
    在實現刪除功能時,應對存在子項的樹項進行提示,以警告用戶是否連同其子項一起刪除。
    void CVCTREEDlg::OnDel()
    { file://刪除子項功能函數
      HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選項句柄;
     if(hSel==NULL) return;//無任何選項則返回
     if(m_TreeCtrl.ItemHasChildren(hSel))//判斷是否有子項
       if(MessageBox("廠家下存在品名,一同刪除?","警告",MB_YESNO)==IDNO) return;
   m_TreeCtrl.DeleteItem(hSel);
    }
    (5)排序功能的實現
    排序功能是對所選中的樹項的所有子項按字符中順序進行排序,如果想要按照其它規則進行排序,應利用SortChildrenItemBC()函數進行自行開發排序程序,這個自行開發的函數與列表控制中實現的函數基本相同,可興趣的讀可以試驗。
    void CVCTREEDlg::OnSort()
    { file://排序子項功能函數
    HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選項句柄;
    if(hSel==NULL) return;//無任何選項則返回
    m_TreeCtrl.SortChildren(hSel);
    }
    (6)查看功能的實現
    查看功能用來查看選中樹項的有關信息,函數中中顯示了樹項的文本名稱和標識號,可以將這兩個信息作爲查找關鍵字,來查看其它更詳細的信息。
    void CVCTREEDlg::OnView()
    { file://查看選中項功能函數
    HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得選項句柄;
    if(hSel==NULL) return;//無任何選項則返回
    CString cText=m_TreeCtrl.GetItemText(hSel);//取得數據項名
    LONG IDs=m_TreeCtrl.GetItemData(hSel);//取得數據項序號
    char temp[100];
    wsprintf(temp,"廠家:%s 編號:%05d",cText,IDs);
    MessageBox(temp,"選擇信息");
    }
    (7)修改功能的實現
    如果不進行其它處理,當修改樹項的文本名稱後,就會發現其未被修改,這是因爲程序中沒有對修改結果進行保存處理,這就要利用TV_DISPINFO結構和SetItemText函數對TVN_ENDLABELEDIT進行處理,這樣就可以正確地實現修改功能。
    void CVCTREEDlg::OnEndlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult)
    { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
  // TODO: Add your control notification handler code here
      if(pTVDispInfo->item.pszText==0) return;//用戶取消修改操作
     m_TreeCtrl.SetItemText(pTVDispInfo->item.hItem,
  pTVDispInfo->item.pszText);//設置新數據
  *pResult = 0;
    }
7、樹視的演練技巧
樹視的應用技巧在使用樹視時,其方法與樹控制基本相同,只不過樹視是在窗口中來實現的而樹控制是在對話框中實現,樹視的各種功能是通過菜單來實現的而樹控制是通過按鈕等方式來實現的,樹控制需要在對話框中創建樹控制控件而樹視直接佔據整個窗口,在設計過程中只要將按鈕和樹控制設計過程變爲菜單設計,並注意在功能函數是在類嚮導中是通過菜單命令來操作,同時在每個功能函數前面增加取得列表視引用的命令(CTreeCtrl& TreeCtrl = GetTreeCtrl()),而其餘數據結構和代碼均不需要修改,實現起來比較容易。筆者實現的樹控制和視程序的運行結果如下:
                    樹控制的演練示例結果
              樹視演練結果示例
第5章 演練CTab
5.1 標5.2 籤控制的主要功能
    標籤控制(Tab Control)是用來在一個窗口如對話框等中的同一用戶區域控制多組顯示信息或控制信息,由頂部的一組標籤來控制不同的信息提示,標籤即可以是文本說明也可以是一個代表文本含義的圖標,或是兩者的組合。針對不同的選擇標籤,都會有一組提示信息或控制信息與之相對應,供用戶進行交互操作,這在WINDOWS98的屬性表中最常見。另外還存在一種特殊風格的標籤,即TBS_BUTTONS風格的標籤,這種標籤外觀類似按鈕,通過鼠標點擊改變狀態,一般用來執行一些功能而不是用來顯示或控制信息。
    提到標籤,最快想到的應該是屬性表對話(Property Sheet),這兩者的配合應用更是隨處可見。屬性表對話框有時也稱爲多頁對話框(Multiple-Page Dialog)或是標籤對話框(Table Dialog),最多可設置24個屬性頁(Property Page),通過頂部的標籤來選擇不同的屬性頁。另外還有一種特殊的屬性表對話框,就象VC++5.0中的類嚮導AppWizard一樣,其不存在供用戶選擇的標籤,而是按照順序依次控制屬性頁的顯示,並且還有一般屬性頁中不存在的“確認”、“上一步”、“下一步”、“完成”和“幫助”等按鈕。
    標籤控制在MFC中只存在一種封裝形式,即控制類CtabCtrl。在使用標籤時即可以在對話框中直接添加,也可以在窗口中作爲子窗口來使用,只不過這樣應用時需要選創建標籤。
5.3 標5.4 籤控制的對象結構
5.4.1 標5.4.2 籤控制的建立方法
    CTabCtrl&tabCtrl     建立標籤控制對象結構
    Create                建立標籤控制並綁定對象
    標籤控制CTabCtrl::Create的調用格式如下:
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
    其中參數dwStyle用來確定標籤控制的風格;rect用來控制標籤的大小和位置;pParentWnd用來確定標籤控制的父窗口句柄;nID用來確定標籤控制的標識符。
標籤控制的風格可以是如下值的組合:
    TCS_BUTTONS            表示將標籤外觀定義成類似按鈕
    TCS_FIXEDWIDTH         使所有標籤具有相同的寬度
    TCS_FOCUSNEVER         使特定標籤永遠不接收輸入焦點
    TCS_FOCUSONBUTTONDOWN  當標籤被鼠標點擊時接收輸入焦點,其僅與TCS_BUTTONS合用
    TCS_FORCEICONLEFT      強制圖標在左面,剩餘部分使標籤居中
    TCS_FORCELABELLEFT     使圖標和標籤均左對齊
    TCS_MULTILINE          允許標籤控制顯示多行標籤
    TCS_OWNERDRAWFIXED     允許父窗口自繪標籤
    TCS_RIGHTJUSTIFY       使標籤右對齊
    TCS_SHAREIMAGELISTS    當控制被撤消時標籤控制的圖像不被撤消
    TCS_TOOLTIPS           允許標籤控制存在工具提示控制
    TCS_TABS               標籤正常顯示,爲默認狀態
    TCS_SINGLELINE         將標籤只顯示在一行上,默認狀態
    TCS_RAGGEDRIGHT        不使標籤自動填滿控制區域,默認狀態
    同樣,標籤控制還可以使用窗口的一些控制風格:
    WS_CHILD               爲標籤控制創建子窗口,只能與WS_POPUP風格一起使用
    WS_VISIBLE             建立一個初始可視的標籤控制
    WS_DISABLED            建立一個初始不可視的標籤控制
    WS_GROUP               建立標籤控制羣組的第一個控制
    WS_TABSTOP             建立可用TAB鍵移動的標籤控制
5.4.3 標5.4.4 籤控制的屬性類
    標籤控制的屬性類包括取得與標籤控制相關聯的圖像列表GetImageList、設置標籤控制的圖像列表SetImageList、取得標籤控制中標籤的總數GetItemCount、取得標籤控制中特定標答的相關信息GetItem、設置標籤的部分或全部屬性SetItem、檢測當前被選中的標籤GetCurSel、將一個標籤設置爲選中狀態SetCurSel和取得具有當前輸入焦點的標籤SetCurSel等。
5.4.5 標5.4.6 籤控制的操作方法
    標籤控制的操作方法包括在標籤控制中插入一個標籤InsertItem、刪除一個標籤      DeleteItem、從標籤控制中刪除所有項目DeleteAllItems、從標籤控制中刪除一個圖像列表RemoveImage和繪製標籤控制中的特定一項DrawItem等。
5.5 標5.6 籤控制的數據結構
    在使用標籤控制時,必須使用的函數就是在標籤控制中插入標籤。函數InsertItem的原形如下:
    BOOL  InsertItem(int nItem,TC_ITEM * pTabCtrlItem);
    該函數中的TC_ITEM爲添加標籤時所使用信息的數據結構,其數據成員的定義方法及含義如下:
    typedef struct _TC_ITEM {
    UINT mask;         // 確定結構成員的屏蔽或設置位
    UINT lpReserved1;  // 保留未用
    UINT lpReserved2;  // 保留未用
    LPSTR pszText;     // 標籤名稱字符串
    int cchTextMax;    // 標籤名稱字符串緩衝區大小
    int iImage;        // 標籤控制的圖像索引號
    LPARAM lParam;     // 應用程序定義的相關32位數據
    } TC_ITEM;
    當鼠標點擊標籤控制中的標籤時,標籤控制就會向其父窗口發送相關的通知消息,通過處理這些通知消息,程序可以實現各種功能。
5.7 屬性表和屬性頁的基本用法
    在標籤控制過程中,屬性表對話框和屬性頁是必不可少的。在MFC類庫中,屬性表對話框類CpropertySheet是由CWnd類派生而來的,而屬性頁類CpropertyPage是由Cdialog類派生而來的,它們的用法基本相同:
    1、創建所有的屬性頁。創建屬性頁的方法與創建一般對話框資源的方法一樣,利用對話框編輯器可以爲每個屬性頁創建一個對話框模板,其區別在於,當利用類嚮導ClassWizard爲屬性頁生成類時應選擇屬性頁類CpropertyPage作爲基類,而不是將一般的對話框類Cdialog作爲基類;
    2、創建屬性表對話框,並將事先創建好的各屬性頁添加進去,兩者的創建順序可以互換,但在創建完之後將屬性頁添加到屬性表對話框中去這一步是必須要做的;
    3、顯示屬性表對話框。雖然屬性表對話框類CpropertySheet不是由對話框類Cdialog派生而來的,但兩者的操作非常類似,調用DoModal()函數就會顯示一個模態屬性表對話框,而調用Create()操作就會顯示一個非模態的屬性表對話框;
    4、對數據交換的處理。和對話框類似,屬性表對話框與對象之間的數據交換也是通過數據成員2來實現的,只是屬性表本身不帶數據成員,而實際進行數據交換的是屬性頁中的數據成員;
    5、對嚮導對話框的處理。如果要顯示一個嚮導對話框,在顯示之前應首先調用SetWizardMode()函數對嚮導對話框進行特殊處理,對於存在按鈕的嚮導對話框,還應調用SetWizardButtons()來對嚮導對話框的按鈕功能進行定製,在用戶操作結束時還應調用SetFinishText()函數將“完成”按鈕設置爲有效狀態。
5.8 標5.9 籤控制的應用技巧示例程序
  本文給出一個基於文檔的標籤應用實例。實例程序中通過簡單設置菜單、標籤和屬性表來演示標籤控制的實際應用技巧,程序通過選擇菜單選項彈出設置正文顏色、字體和修飾等屬性表對話框來和用戶進行簡單交互。其實現步驟如下:
    1、利用應用程序嚮導AppWizard創建一個基於文檔的工程TAB,在選擇工程類型時應選擇單文檔;
    2、利用資源中的菜單生成器,刪除無用菜單,並增加如下菜單結構
    菜單名                標識符
    設置(S)               (彈出菜單名)
    背景設置(B)           IDM_BKGRND
    前景設置(F)           IDM_FRGRND
    3、利用對話框設計器設置屬性表對話框所需要的四個屬性頁,注意在選擇基類時應將屬性  頁類CpropertyPage作爲基類,並將對話框及菜單等控件的所有屬均改爲中文。四個屬性頁及其包括的控件內容分別爲:(1)文字屬性對話框包括一個輸入文字的文本輸入框,用於輸入和修改在窗口上顯示的文字;(2)字體屬性對話框包括三個選中框,用來確定顯示的字體修飾;(3)字間距屬性對話框包括一個用於顯示提示信息的標籤和用於輸入字間距大小的文本輸入框;(4)顏色屬性對話框包括一個成組框和三個單選圓鈕;(5)窗口中設置一個用於顯示輸入文字的標籤。
    以上控制的設置參數如下:
     控制名稱            標題名稱              標識符串
     標籤控制                                  IDC_TABCTRL
      表態文本            字間距(10-100)        IDC_STATIC1
      編輯框                                    IDC_LIST
      成組框              顏色                  IDC_STATIC2
      單選按鈕            黑色                  IDC_BLACK
                          紅色                  IDC_RED
                          藍色                  IDC_BLUE
      文本框(編輯框)                          IDC_TEXT
      設置字體(複選按鈕)粗體                  IDC_BOLD
                          斜體                  IDC_ITALIC
                          下劃線                IDC_UNDERLINE
      按  鈕              確認                  IDOK
                          取消                  IDCANCEL
    利用類嚮導ClassWizard在屬性表對話框CtabDlg、屬性頁對話框CtextPage和CstylePage中分別加入如下數據成員:
   標識符串              類型                數據成員
    IDC_TABCTRL           CtabCtrl            m_tabCtrl
    IDC_DIST              int                 m_nDist
    IDC_BLACK             int                 m_nColor
    IDC_TEXT              Cstring             m_cText
    IDC_BOLD              BOOL                m_bBold
    IDC_ITALIC            BOOL                m_bItalic
    IDC_UNDERLINE         BOOL                m_bUnderline
    以上數據成員也可以在TABDlg.h、StylePage.h和TextPage.h中利用手工方法增加。
    4、將要顯示的數據成員加入到視類中去,來和對話框之間進行數據交換,並且將其在初始化函數中進行數據初始化。
    (1)在TabView.h中增加如下代碼:
#include "TabDlg.h"
#include "TextPage.h"
#include "StylePage.h"
class CTabView : public CView
{public:
 int nDist;//數值
 int nColor;//顏色
 CString cText;//中文字符串
 BOOL bBold,bItalic,bUnderline;//字體屬性
}
(2)在TabView.cpp中對數據成員進行如下初始化。
CTabView::CTabView()
{ nDist=20;
 nColor=1;
 cText=CString("標籤控制演示實例");
 bBold=bItalic=bUnderline=FALSE;
}
(3)在TabDlg.cpp中向控制中增加標籤,來實現背景設置功能。
BOOL CTabDlg::OnInitDialog()
{ CDialog::OnInitDialog();
 TC_ITEM tcItem;//添加標籤
 tcItem.mask=TCIF_TEXT;
 tcItem.pszText="字 間 距";
 m_tabCtrl.InsertItem(0,&tcItem);
 tcItem.pszText="顏色設置";
 m_tabCtrl.InsertItem(1,&tcItem);
 m_tabCtrl.SetCurSel(1);
return TRUE;
}
    當標籤切換時,標籤控制會自動向對話框窗口發送TCN_SELCHANGE通知消息,這時需要根據所選擇的標籤索引號對屬性頁的顯示和隱藏進行切換控制,應完善OnSelchangeTabctrl()函數:
void CTabDlg::OnSelchangeTabctrl(NMHDR* pNMHDR, LRESULT* pResult)
{ int iPage=m_tabCtrl.GetCurSel();//所選標籤號
 switch(iPage){
   case 0://字間距
   GetDlgItem(IDC_STATIC2)->ShowWindow(SW_HIDE);//隱藏選擇按鈕
   GetDlgItem(IDC_BLACK)->ShowWindow(SW_HIDE);//隱藏選擇按鈕
   GetDlgItem(IDC_RED)->ShowWindow(SW_HIDE);//隱藏選擇按鈕
   GetDlgItem(IDC_BLUE)->ShowWindow(SW_HIDE);//隱藏選擇按鈕
   GetDlgItem(IDC_STATIC1)->ShowWindow(SW_SHOW);//顯示輸入項數
   GetDlgItem(IDC_DIST)->ShowWindow(SW_SHOW);//顯示輸入項數
   break;
    case 1://顏色設置
   GetDlgItem(IDC_STATIC1)->ShowWindow(SW_HIDE);//隱藏項數輸入
   GetDlgItem(IDC_DIST)->ShowWindow(SW_HIDE);//隱藏項數輸入
   GetDlgItem(IDC_STATIC2)->ShowWindow(SW_SHOW);//顯示選項選擇
   GetDlgItem(IDC_BLACK)->ShowWindow(SW_SHOW);//顯示選項選擇
   GetDlgItem(IDC_RED)->ShowWindow(SW_SHOW);//顯示選項選擇
   GetDlgItem(IDC_BLUE)->ShowWindow(SW_SHOW);//顯示選項選擇
   break;
  }
  *pResult = 0;
}
    (4)菜單功能的完善。在執行相應的菜單功能時,必須對類嚮導增加的相應功能函數進行代碼完善,這就要處理TabView.cpp文件,背景設置功能函數如下:
void CTabView::OnBkgrnd()
{ CTabDlg ctd;
ctd.m_nDist=nDist;
ctd.m_nColor=nColor;
if(ctd.DoModal()==IDCANCEL) return;
nDist=ctd.m_nDist;
nColor=ctd.m_nColor;
Invalidate();//重新繪製窗口
}
    同樣,也要對前景設置功能函數進行完善:
void CTabView::OnFrgrnd()
{ CPropertySheet cps("前景設置");//創建屬性表對象
CTextPage ctp; file://顯示文字屬性頁
CStylePage csp;//顯示字體屬性頁
ctp.m_cText=cText;
csp.m_bBold=bBold;
csp.m_bItalic=bItalic;
csp.m_bUnderline=bUnderline;
cps.AddPage(&ctp);//添加屬性頁
cps.AddPage(&csp);
if(cps.DoModal()==IDCANCEL) return;
cText=ctp.m_cText;
bBold=csp.m_bBold;
bItalic=csp.m_bItalic;
bUnderline=csp.m_bUnderline;
Invalidate();//重新繪製窗口
}
    (5)爲了充分演示標籤控制與各屬性頁之間的數據交換功能,應該實現標籤控制各屬性頁與用戶之間數據交換結束後的窗口顯示功能,筆者實現的功能函數顯示了由屬性頁中輸入的字體及背景網格功能,TabView.cpp中的對應函數代碼如下:
void CTabView::OnDraw(CDC* pDC)
{ CTabDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
RECT rc;
GetClientRect(&rc);
int i,j,k;
CPen pen,*pOldPen;
COLORREF color;
switch (nColor){
case 0:color=RGB(0,0,0);   file://設置黑色
 break;
case 1:color=RGB(0xff,0,0);//設置紅色
 break;
case 2:color=RGB(0,0,0xff);//設置藍色
 break;
}
pen.CreatePen(PS_SOLID,1,color);
pOldPen=pDC->SelectObject(&pen);//繪製背景網格
j=rc.right/nDist+1;
k=rc.bottom/nDist+1;
for(i=0;i<j+k;i++){
  pDC->MoveTo(i*nDist,0);
  pDC->LineTo(0,i*nDist);
  if(i<j){
    pDC->MoveTo(i*nDist,0);
    pDC->LineTo(rc.right,(j-i)*nDist);
  } else {
     pDC->MoveTo(0,(i-j)*nDist);
     pDC->LineTo(rc.right,i*nDist);
  }
}
pDC->SelectObject(&pOldPen);
CFont font,*pOldFont;
font.CreateFont(50,0,0,0,bBold?1000:200,
bItalic,bUnderline,0,ANSI_CHARSET,
 OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
 DEFAULT_QUALITY,DEFAULT_PITCH,NULL);
pOldFont=pDC->SelectObject(&font);
pDC->TextOut(20,20,cText);
pDC->SelectObject(pOldFont);
}
標籤控制的整個實現過程雖然比較繁鎖,但只要掌握其實現的本質,設計一個優秀的標籤控制界面也並非很困難的事情。
筆者實現的標籤控制的演練示例結果如下:
                  標籤控制演練示例結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章