CListCtrl使用方法匯總


回顧:

剛剛寫完,因為是分期寫的,所以最初想好好做一下的文章格式半途而廢了~說的也許會有點啰嗦,但是所有的基礎用到的技術細節應該都用到了。

如果還有什么疑問,請回復留言,我會盡力解答。

如果有錯誤,請指正。

這里所有使用到的內容在VS2010中均能正常運行。

可運行程序的截圖:

CListCtrl控件的創建

如果一個CListCtrl控件對象和dialog上的控件已經綁定,那么可以跳過這個這一步,因為綁定了的對象已經完成了創建。

但是如果要在dialog上憑空創建出來一個列表控件,那么就需要了解CListCtrl類的成員函數:Create

先看這個函數的原型:

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

第一個參數是用來聲明這個列表的風格,具體風格如下 :

    • LVS_ALIGNLEFT Specifies that items are left-aligned in icon and small icon view.
      指定條款是小圖標且左對齊
    • LVS_ALIGNTOP Specifies that items are aligned with the top of the control in icon and small icon view.
      指定條款是頂端對其且為小圖標
    • LVS_AUTOARRANGE Specifies that icons are automatically kept arranged in icon view and small icon view.
      指定圖標自動保存在圖標視圖中,且為小圖標視圖
    • LVS_EDITLABELS Allows item text to be edited in place. The parent window must process the LVN_ENDLABELEDIT notification message.
      允許條目適當的編輯,父窗口必須指定LVN_ENDLABELEDIT消息
    • LVS_ICON Specifies icon view.
      指定圖標視圖
    • LVS_LIST Specifies list view.
      指定列表視圖
    • LVS_NOCOLUMNHEADER Specifies that a column header is not displayed in report view. By default, columns have headers in report view.
      指明列的頭結點不在報告視圖中顯示,默認時,列的頭結點會在報告中顯示出來
    • LVS_NOLABELWRAP Displays item text on a single line in icon view. By default, item text can wrap in icon view.
      在圖標視圖中單獨的顯示出來。默認情況下,項文本能和圖標同時顯示
    • LVS_NOSCROLL Disables scrolling. All items must be within the client area.
      關閉滾動條,全部的條目必須在客戶區內顯示
    • LVS_NOSORTHEADER Specifies that column headers do not work like buttons. This style is useful if clicking a column header in report view does not carry out an action, such as sorting.
      表明列頭不會像一個按鈕那樣。這個選項在report風格下如果不打算讓其實現一些功能會很有用,比如點擊后排序
    • LVS_OWNERDRAWFIXED Enables the owner window to paint items in report view. The list view control sends a WM_DRAWITEM message to paint each item; it does not send separate messages for each subitem. The itemData member of theDRAWITEMSTRUCT structure contains the item data for the specified list view item.
      這個我貌似用不到……不翻譯了
    • LVS_REPORT Specifies report view.
      指明報告窗口
    • LVS_SHAREIMAGELISTS Specifies that the control does not take ownership of the image lists assigned to it (that is, it does not destroy the image lists when it is destroyed). This style enables the same image lists to be used with multiple list view controls.
      指明這個控件並不獲取圖像列表的所有權。這就意味着,在這個對象析構的時候斌不會析構圖像列表。這個風格允許同樣的圖像列表用於多個列表控件
    • LVS_SHOWSELALWAYS Always show the selection, if any, even if the control does not have the focus.
      總是顯示被選中的選項,即便窗口未被鎖定
    • LVS_SINGLESEL Allows only one item at a time to be selected. By default, multiple items can be selected.
      一次只能選擇一個選項,默認的情況下,能同時選擇多個條目
    • LVS_SMALLICON Specifies small icon view.
      指定小圖標視圖
    • LVS_SORTASCENDING Sorts items based on item text in ascending order.
      按照遞增進行排序
    • LVS_SORTDESCENDING Sorts items based on item text in descending order. 
    • 按照遞減排序

一下翻譯這么多,有點累,看來我的英語還是太差,不然怎么會覺得累~

第二個參數:rect

這個參數就是你所創建的CListCtrl的位置,以及大小。不再做過多介紹了

第三個參數:pParentWnd

這個參數用來指定父窗口,一般是一個CDialog對象指針,需要注意的是,千萬不能是NULL。

第四個參數:nID

控件ID,這個不用多說了,每個看控件都有的。

CListCtrl風格修改

但是如果你已經創建好了一個ListCtrl控件,那么你為其聲明了一個CListCtrl控件,那么上面的Create函數你就可以跳過去了~

但是,風格總是要設置的,所以在這里,有一個函數可以調用,專門用來設置風格~

LONG SetWindowLong(
  HWND hWnd,       // handle to window
  int nIndex,      // offset of value to set
  LONG dwNewLong   // new value
);

CListCtrl的窗口句柄是public的,能直接獲取。

第二個參數添加:GWL_STYLE,目的就是為了設置新的風格。

第三個參數就是風格的組合了

這個函數的具體內容請看MSDN,我這就不再多說了~

CListView的擴展風格

CListCtrl可以設置的風格:

LVS_EX_GRIDLINES //繪制表格

LVS_EX_SUBITEMIMAGES

LVS_EX_CHECKBOXES //帶復選框

LVS_EX_TRACKSELECT //自動換行

LVS_EX_HEADERDRAGDROP

LVS_EX_FULLROWSELECT //選擇整行

LVS_EX_ONECLICKACTIVATE//單擊激活

LVS_EX_TWOCLICKACTIVATE//雙擊激活

LVS_EX_FLATSB//扁平滾動條

LVS_EX_REGIONAL

LVS_EX_INFOTIP

LVS_EX_UNDERLINEHOT

LVS_EX_UNDERLINECOLD

LVS_EX_MULTIWORKAREAS//多工作區

以上風格設置可以使用下面的CListCtrl成員函數來設置:

DWORD SetExtendedStyle( DWORD dwNewStyle );

 現在有代碼如下:

 1 void CMyRisingDlg::ListCtrlInitial()
 2 {
 3     CRect lc_rect;
 4     DWORD dwStyle = ::GetWindowLong(m_LCTable.m_hWnd, GWL_STYLE); 
 5     dwStyle &= ~(LVS_TYPEMASK);
 6     dwStyle &= ~(LVS_EDITLABELS);
 7     SetWindowLong(m_LCTable.m_hWnd, GWL_STYLE,dwStyle |LVS_REPORT | LVS_NOLABELWRAP | LVS_SHOWSELALWAYS);
 8     m_LCTable.SetExtendedStyle(LVS_EX_ONECLICKACTIVATE|LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
 9     m_LCTable.GetWindowRect(&lc_rect);
10     DWORD dwListLength = lc_rect.Width() / 3;
11     m_imagelist.Create(16, 16, ILC_COLORDDB|ILC_MASK, 0, 1);
12 
13     m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
14     m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
15     m_LCTable.SetImageList(&m_imagelist, LVSIL_SMALL);
16     m_LCTable.InsertColumn(0, _T("Name"), LVCFMT_LEFT | LVCFMT_IMAGE, dwListLength);
17     m_LCTable.InsertColumn(1, _T("PathName"), LVCFMT_LEFT, dwListLength);
18     m_LCTable.InsertColumn(2, _T("Create Time"), LVCFMT_LEFT, dwListLength + 3);
19 
20     m_LCTable.InsertItem(0, LPSTR_TEXTCALLBACK);21 
22 }

很顯然,這個函數的功能是初始化一個ListCtrl。從代碼里面能夠看出來,在初始化上,其實主要的就是風格設置。然后最一行的函數調用是為了做虛擬列表,CListCtrl的虛擬列表內容我會在新的隨筆中介紹。

  上面的幾個比較主要的成員函數調用,SetExtendedStyle函數就不再多說了,可以參考樣式以及上面的各種風格,或者直接去看MSDN。

  然后下面的SetImageList是為了給列表上主要的首子項添加上文件圖標,正在做,還未完成。不過上面的程序界面截圖中能看到首列有圖標,那個只是目前應付一下的~

接下來要比較重點的介紹InsertClumn函數:

  這個函數是用來完成列的插入的。或者說,建立了一個索引,或者鏈表頭。由此函數調之后才能調用InsertItem函數,否則是無效的,函數剛一調用,估計就直接返回個0了。

  這個函數看下MSDN的介紹:

int InsertColumn( int nCol, const LVCOLUMN* pColumn );

int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1 );

Return Value

The index of the new column if successful or -1 otherwise.

這個函數有兩種形式,但是我只介紹第二種,原因為啥你應該很清楚~。這里第一個參數就是列號了,不多說。第二個參數是列名,也不用太羅嗦,第三個是格式,需要簡單說一下。

nFormat參數有一下的幾種形式:LVCFMT_LEFT, LVCFMT_RIGHT, or LVCFMT_CENTER.另外還有LVCFMT_IMAGE,默認情況下是從左往右的,也就是我們的書寫順序。另外需要注意的是,其實這個參數一般來講的話都是直接使用LEFT參數的,原因就是如果你使用了center或者right參數,會直接導致一個后果:就是這列的全部內容,也都是對應的居中或者置右。另外如果使用了LVCFMT_IMAGE參數,那么就會在最左端添加圖片的基礎上,默認為LEFT風格,這點還是需要注意的。

目前除了InsertItem函數之外,其余的基礎操作設置就差不多了,至於其他的一些操作我等會也還需要再看~

然后接下來講下如何添加首項的圖片。

我覺得添加這個圖片的目的主要還是為了提供更好的用戶體驗。因為如果有圖片的話,對大多數用戶來說會提供一個很便利的途徑來知道這個文件的類型屬性。畢竟大多數的用戶是不會去根據文件后綴來判斷這個文件到底是干什么的~

廢話不多說,先看一個類:CImageList.

接着貼MSDN:

An “image list” is a collection of same-sized images, each of which can be referred to by its zero-based index. Image lists are used to efficiently manage large sets of icons or bitmaps. All images in an image list are contained in a single, wide bitmap in screen device format. An image list may also include a monochrome bitmap that contains masks used to draw images transparently (icon style). The Microsoft Win32 application programming interface (API) provides image list functions that enable you to draw images, create and destroy image lists, add and remove images, replace images, merge images, and drag images.

大意如下:

一個圖像列表是同樣大小圖像的集合,每個成員都能夠通過以0為起始的目錄來訪問(其實就是順序表訪問)。圖像列表控件能夠用來有效的管理大數量的圖標或位圖。在圖像列表中的所有圖片都在屏幕設備格式中包含一個單獨的,寬(這里不知道怎么翻譯)的位圖。一個圖像列表控件也可能包含一個包含繪制透明圖像任務的單色位圖(這里不是很確定)。

后面的就不翻譯了,沒什么用。

上面我貼的那個函數里CImageList的使用也比較明了,簡單介紹下:

對象創建完之后並不需要立即初始化,還不錯。然后首先要調用其中的Create函數,就是創建一個初始化一個列表並付給對象,MSDN基本就這個意思。這里再貼一下函數原型:

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 );

BOOL Create( CImageList* pImageList );

Return Value

Nonzero if successful; otherwise 0.

很顯然,在我的程序里面調用的函數是其中的第一個,所以我這就只介紹第一個了~前兩個參數很明顯,就是這個圖片的尺寸。我在這里的建議還是,提供16*16的圖片比較合適。我曾經想過做8*8的,結果,太小了……實在不合適。這個尺寸是我做列表比較推薦的。第三個參數很顯然就是個標志位,用來設置風格的。

具體風格如下:

ILC_COLOR Use the default behavior if none of the other ILC_COLOR* flags is specified. Typically, the default is ILC_COLOR4; but for older display drivers, the default is ILC_COLORDDB.
ILC_COLOR4 Use a 4-bit (16 color) device-independent bitmap (DIB) section as the bitmap for the image list.
ILC_COLOR8 Use an 8-bit DIB section. The colors used for the color table are the same colors as the halftone palette.
ILC_COLOR16 Use a 16-bit (32/64k color) DIB section.
ILC_COLOR24 Use a 24-bit DIB section.
ILC_COLOR32 Use a 32-bit DIB section.
ILC_COLORDDB Use a device-dependent bitmap.
ILC_MASK Uses a mask. The image list contains two bitmaps, one of which is a monochrome bitmap used as a mask. If this value is not included, the image list contains only one bitmap. 

我上面的函數在這里使用的是后兩個參數的組合。DDB的意思是設備相關位圖,與之相反的就是大名鼎鼎的DIB了,不過這里沒有。我的MSDN版本比較老,是給VC6.0做的,有興趣的可以去MSDN網站上看看,新版的CImageList有沒有提供DIB的。

不過我覺得,似乎我的那個代碼里,ILC-MASK參數貌似沒什么用處,回頭刪掉。

然后nInitial參數,就是Imagelist對象中初始化后就包含的圖像數目,MSDN:Number of images that the image list initially contains.

最后一個參數:nGrow 原文:Number of images by which the image list can grow when the system needs to resize the list to make room for new images. This parameter represents the number of new images the resized image list can contain.

其實這個參數倒不是很重要,但是,能牽扯到效率問題。如果每次新添加一個圖片就要申請一塊新的內存,是不是有點效率太低了?所以不如一次申請多個,這樣效率更高一下些。但是如果你的列表一般只需要10個,但是你每次resize之后會變成100個,就造成了浪費。所以還是需要注意一下的,但是小列表設置為5以內的數應該就行了。

這個函數介紹完了,就要接着講添加的問題。不過這個還是比較簡單的。可以直接調用add成員函數。

int Add( CBitmap* pbmImage, CBitmap* pbmMask );

int Add( CBitmap* pbmImage, COLORREF crMask );

int Add( HICON hIcon );

Return Value

Zero-based index of the first new image if successful; otherwise – 1.

這里提供了三個函數,前兩個都是和Bitmap相關的,暫且不談,只談第三個。

第三個函數,很簡單,只要一個圖標資源的句柄就可以了。獲取這個句柄資源,在MFC中有一種很簡單的方法:直接調用App類的LoadIcon函數。

AfxGetApp()->LoadIcon(IDI_ICON1)

里面直接添加上工程中建立好的圖標資源ID就好了。

不過這個成員函數只限CWinApp類的對象使用。另外一種方法是調用SDK的函數,其中hInstance就是句柄,這里應該直接添加app的m_hwnd,應該是的,我還沒試過。第二參數要使用MAKEINTRESOURCE宏轉一下就可以了。

接下來就是如何將圖片綁定到列表頭部了。

在兩個對象都創建完成后,只要調用CListCtrl函數的一個成員函數就可以了:

CImageList* SetImageList( CImageList* pImageList, int nImageList );

Return Value

A pointer to the previous image list.

Parameters

pImageList

Pointer to the image list to assign.

nImageList

Type of image list. It can be one of these values:

    • LVSIL_NORMAL Image list with large icons.

    • LVSIL_SMALL Image list with small icons.

    • LVSIL_STATE Image list with state images. 

不用說太多,我這里第二個參數直接使用的LVSIL_SMALL選項,畢竟16*16的圖片絕對不大。

然后這樣就實現了綁定,但是此時你需要知道,雖然兩個對象綁定了,但是ImageList對象依舊能夠獨立於ListCtrl進行修改操作。

那么綁定了之后呢?還是要看InsertItem函數。

InsertItem函數形式有好幾個,這里需要使用這種形式:

int InsertItem( int nItem, LPCTSTR lpszItem, int nImage );

這個形式的函數專門添加了nImage這個參數,目的就是為了實現列表的添加。

nImage的選擇是對應ImageList中的圖像尋址功能,如果在ImageList中添加好了圖片,那么InsertItem函數就會根據這個參數的值取尋找對應的圖片,然后直接將其添加到列表中。

虛擬列表我會在新的隨筆中介紹,並會介紹一下我的思考過程。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM