WIN32 SDK中树形视图与图像列表的配合使用实例(一)
WIN32 SDK中树形视图与图像列表的配合使用实例(一)
2011年04月20日
树形视图算属于高级控件了,比较特别一点,能够很清晰的反应某种层次关系,日常生活中也比较常见,比如资源管理器左边窗口就正是树形视图。同时,它也不例外的属于窗口,那就可以用CreateWindowEx来创建,需传递一个"SysTreeView32"的类名,特殊之处在于这家伙属于通用控件,因此需要在代码中加入InitCommonControls函数。
InitCommonControls函数是动态链接库comctl32.dll中的一个函数,只要在您的程序中的任意地方引用了该函数就、会使得WINDOWS的程序加载器PE Loader加载该库。函数InitCommonControls其实只有一条指令"ret",它的唯一目的是为了使得在调用了个该函数的应用程序的可执行文件的PE头中的"引入"段中包含有comctl32.dll,这样无论什么时候该应用程序都会为您加载该库。所以真正初始化的工作是在该库的入口点处做的,在这里会注册所有的通用控件类,然后所有的通用控件就可以在这些类上进行创建,这就象创建其它的子窗口控件一样。
树形视图风格介绍:
TVS_HASBUTTONS
在父亲项目中显示+或-,当点击该符号的时候可以展开或者收起该父亲项目下面的儿子孙子项目,如果想在根目录下也有此符号,就要指定TVS_LINESATROOT的style.
TVS_HASLINES
层次之间用线条来连接
TVS_LINESATROOT 在根目录下也有线条来连接,如果没指定TVS_HASLINES风格,则此风格也会被忽略,MSDN这么说的:
The TVS_HASLINES style enhances the graphic representation of a tree-view control's hierarchy by drawing lines that link child items to their parent item. This style does not link items at the root of the hierarchy. To do so, you need to combine the TVS_HASLINES and TVS_LINESATROOT styles.
还有以下三种风格
The TVS_EDITLABELS style makes it possible for the user to edit the labels of tree-view items. For more information about editing labels, see Tree-View Label Editing.
The TVS_SHOWSELALWAYS style causes a selected item to remain selected when the tree-view control loses focus.
The TVS_CHECKBOXES style creates checkboxes next to each item. If you want to use the checkbox style, you must set the TVS_CHECKBOXES style (with SetWindowLong) after you create the tree-view control and before you populate the tree. Otherwise, the checkboxes might appear unchecked, depending on timing issues.
跟其他通用控件一样,树形视图也是靠消息实现通信的,父窗口发送一系列的消息给树形视图,而树形视图则发送Notification消息给他的父亲窗口。
当事件发送时,tree view发送一个WM_NOTIFY消息给父窗口,同时在消息中附带了一些信息。 WM_NOTIFY
wParam ==控件的ID。因为该值不是唯一的,故我们不用它。我们使用NMHDR结构体中的hwndFrom或IDFrom成员变量。
lParam == 指向NMHDR结构体的指针。有一些控件可能传递一个指向更大一点的结构体的指针。但该结构体必须保证它的第一个成员变量是一个NMHDR型的变量。这样,您在处理lParam变量时,至少可以得到一个NMHDR型的变量。
下面我们来看NMHDR:
typedef struct tagNMHDR
{
HWND hwndFrom;
UINT idFrom;
UINT code;
}NMHDR;
hwndFrom是发送WM_NOTIFY消息的控件的窗口句柄。
idFrom是发送WM_NOTIFY消息的控件的ID。
code是控件发送给父窗口的数据。
树型视图发送给父窗口的通知消息以TVN_打头。树型视图接收到的消息以TVM_打头,譬如:TVM_CREATEDRAGIMAGE。树型视图发送TVN_XXX消息时在code变量中放入NMHDR型变量。父窗口发送TVM_消息来控制树型视图。
添加项目:
创建树形视图完毕后,可以发送TVM_INSERTITEM消息向里面加入项目。 To send this message, call the SendMessage function as follows. Inserts a new item in a tree-view control. You can send this message explicitly or by using the TreeView_InsertItem macro. Syntax To send this message, call the SendMessage function as follows. lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) TVM_INSERTITEM, // message ID
(WPARAM) wParam, // = 0; not used, must be zero
(LPARAM) lParam // = (LPARAM) (LPTVINSERTSTRUCT) lpis;
);
Parameters wParam
Must be zero.
lpis
Pointer to a TVINSERTSTRUCT structure that specifies the attributes of the tree-view item.
Return Value Returns the handle to the new item if successful, or NULL otherwise.
出现了一个比较重要的结构体,看看他:
Contains information used to add a new item to a tree-view control. This structure is used with the TVM_INSERTITEM message. The structure is identical to the TV_INSERTSTRUCT structure, but it has been renamed to follow current naming conventions. Syntax Members hParent
Handle to the parent item. If this member is the TVI_ROOT value or NULL, the item is inserted at the root of the tree-view control.
hInsertAfter
Handle to the item after which the new item is to be inserted, or one of the following values:
TVI_FIRST
Inserts the item at the beginning of the list.
TVI_LAST
Inserts the item at the end of the list.
TVI_ROOT
Add the item as a root item.
TVI_SORT
Inserts the item into the list in alphabetical order.
itemex
Version 4.71. TVITEMEX structure that contains information about the item to add.
item
TVITEM structure that contains information about the item to add.
hParent = 父项目的句柄。如果该值为TVI_ROOT value或NULL,该项目插在树型视图的根部。
hInsertAfter = 应该插入在起后面的项目的句柄或下面的值: TVI_FIRST ==> 插在列表的头部。
TVI_LAST ==> 插在列表的尾部。
TVI_SORT ==> 按字母顺序插入。
union
{
TVITEMEX itemex;
TVITEM item;
} DUMMYUNIONNAME;
我们仅使用TVITEM。
typedef struct tagTVITEM {
UINT mask;
HTREEITEM hItem;
UINT state;
UINT stateMask;
LPTSTR pszText;
int cchTextMax;
int iImage;
int iSelectedImage;
int cChildren;
LPARAM lParam;
} TVITEM, *LPTVITEM; 该结构体根据消息类型,用来发送或接收关于一个树型视图的项目的有关信息。譬如:对于消息TVM_INSERTITEM,它用来指定插入树型视图控件的项目的属性。而对于消息TVM_GETITEM,该结构体用来填充关于选定项目的信息。
imask 用来指定TV_ITEM的那些成员变量有效。譬如,如果指定了TVIF_TEXT,这意味着pszText成员变量是有效的。您可以同时指定几个标志位。
hItem 是树型视图项目的句柄。每一个项目都有它自己的句柄,就像窗口一样。如果您想要操作一个项目,就必须选择它的句柄。
pszText是一个字符串指针。它是项目的标签名。
cchTextMax仅在查询项目的名称时使用。由于在pszText中指定了指针,WINDOWS还要知道该缓冲去的大小。所以您必须给出该值。
iImage 和 iSelectedImage用来指定图象列表以及一个索引号。这样就知道当项目被选中或没被选中时用哪个图象来表示该项目。像资源管理器中左边窗口中的文件夹等小图表就是有这两个参数来决定的。
为了在树型视图中插入一个项目,您必须至少设定hParent, hInsertAfter,另外您还要设定imask和pszText值。 向树形视图中加入图形 如果想在项目名称的左边显示图片图标的话,就需要首先创建一个图形列表,还需要把他跟树形视图关联起来。 创建图形列表: Creates a new image list. Syntax HIMAGELIST ImageList_Create(
int cx, int cy, UINT flags, int cInitial, int cGrow );
Parameters cx
The width, in pixels, of each image.
cy
The height, in pixels, of each image.
flags
A set of bit flags that specify the type of image list to create. This parameter can be a combination of the following values, but it can include only one of the ILC_COLOR values.
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
Use 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.
ILC_MIRROR
Version 6.00. Microsoft Windows can be mirrored to display languages such as Hebrew or Arabic that read right-to-left. If the image list is created on a mirrored version of Windows, then the images in the lists are mirrored, that is, they are flipped so they display from right to left. Use this flag on a mirrored version of Windows to instruct the image list not to automatically mirror images.
ILC_PERITEMMIRROR
Version 6.00. Specify this flag if ILC_MIRROR is used on an image list that contains a strip of images. ILC_MIRROR must be specified for this flag to have any effect.
cInitial
The number of images that the image list initially contains.
cGrow
The number of images by which the image list can grow when the system needs to make room for new images. This parameter represents the number of new images that the resized image list can contain.
Return Value Returns the handle to the image list if successful, or NULL otherwise. cx == 以像素为单位的图象的宽度。
cy == 以像素为单位的图象的高度。图象列表中的每一幅的高度都必须相同。否则WINDOWS会对您的图象进行裁剪,如果过大的话就可能裁剪成几小块。所以您必须指定相同大小的图象。
flags == 指定图象列表的图象的颜色深度。详细情况请参考WIN32 API 指南。
cInitial == 指定包含的图象的数目。WINDWOS将依此来分配合适的内存。
cGrow == 在增加新图象是一次增加的数目。 说白了,图像列表不是一个窗口,只是一个为其他窗口提供资源的容器,可以向里面加入自己的资源信息,向其中加入图像: Adds an image or images to an image list. Syntax int ImageList_Add(
HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask );
Parameters himl
A handle to the image list.
hbmImage
A handle to the bitmap that contains the image or images. The number of images is inferred from the width of the bitmap.
hbmMask
A handle to the bitmap that contains the mask. If no mask is used with the image list, this parameter is ignored.
Return Value Returns the index of the first new image if successful, or -1 otherwise. himl == 图象列表的句柄。它是调用ImageList_Create时返回的值。
hbmImage == 加入图象列表的位图的句柄。您通常把位图保存在资源中,然后调用LoadBitmap来把它加载进来。注意您没有必要指定该位图中包含的图象的数目。WINDOWS会根据它的大小,自动计算。
hbmMask == 掩码位图的句柄。如果没有使用掩码位图,可以忽略该值。通常我们加入两种图象到图象列表中。一种时被选中时显示的图象,另一种时没被选中时显示的。
将两者关联起来,借助消息: Sets the normal or state image list for a tree-view control and redraws the control using the new images. You can send this message explicitly or by using the TreeView_SetImageList macro. Syntax To send this message, call the SendMessage function as follows. lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) TVM_SETIMAGELIST, // message ID
(WPARAM) wParam, // = (WPARAM) (int) iImage;
(LPARAM) lParam // = (LPARAM) (HIMAGELIST) himl;
);
Parameters iImage
Type of image list to set. This parameter can be one of the following values:
TVSIL_NORMAL
Indicates the normal image list, which contains selected, nonselected, and overlay images for the items of a tree-view control.
TVSIL_STATE
Indicates the state image list. You can use state images to indicate application-defined item states. A state image is displayed to the left of an item's selected or nonselected image.
himl
Handle to the image list. If himl is NULL, the message removes the specified image list from the tree-view control.
Return Value Returns the handle to the previous image list, if any, or NULL otherwise.
wParam = 图象列表的状态,一共有两种: TVSIL_NORMAL 包含被选中和没有被选中两种状态的图象。
TVSIL_STATE 包含了用户自定义的状态的图象。
lParam = 图象列表的句柄。 检索树形视图的信息: TVM_GETITEM看名字就晓得差不多能胜任 Retrieves some or all of a tree-view item's attributes. You can send this message explicitly or by using the TreeView_GetItem macro. To send this message, call the SendMessage function as follows. Syntax lResult = SendMessage( // returns LRESULT in lResult (HWND) hWndControl, // handle to destination control (UINT) TVM_GETITEM, // message ID (WPARAM) wParam, // = 0; not used, must be zero (LPARAM) lParam // = (LPARAM) (LPTVITEM) pitem - Version 4.71 and later - (WPARAM) wParam, // = 0; not used, must be zero (LPARAM) lParam // = (LPARAM) (LPTVITEMEX) pitem );
Parameters wParam
Must be zero.
pitem
Pointer to a TVITEM structure that specifies the information to retrieve and receives information about the item. With version 4.71 and later, you can use a TVITEMEX structure instead.
Return Value Returns TRUE if successful, or FALSE otherwise.
Remarks wParam = 0
lParam =指向结构体TV_ITEM的指针。该结构体将用来得到相关的信息。
在发送该消息前必须设置成员变量imask的值,以便WINDOWS能告诉相关的信息。当然,最重要的是,您必须传递您想得到信息的项目的句柄。这就引起了一个问题,您如何得到项目的句柄?要保存所有项目的句柄吗?
没有必要。您可以发送消息TVM_GETNEXTITEM到树型视图以检索您想要得到其属性的项目的句柄。譬如:您可以查询第一个子项目的句柄、根目录的句柄、选中的项目的句柄等等。
Retrieves the tree-view item that bears the specified relationship to a specified item. You can send this message explicitly, by using the TreeView_GetNextItem macro. Syntax To send this message, call the SendMessage function as follows. lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) TVM_GETNEXTITEM, // message ID
(WPARAM) wParam, // = (WPARAM) (UINT) flag;
(LPARAM) lParam // = (LPARAM) (HTREEITEM) hitem;
);
Parameters flag
Flag specifying the item to retrieve. This parameter can be one of the following values:
TVGN_CARET
Retrieves the currently selected item. You can use the TreeView_GetSelection macro to send this message.
TVGN_CHILD
Retrieves the first child item of the item specified by the hitem parameter. You can use the TreeView_GetChild macro to send this message.
TVGN_DROPHILITE
Retrieves the item that is the target of a drag-and-drop operation. You can use the TreeView_GetDropHilight macro to send this message.
TVGN_FIRSTVISIBLE
Retrieves the first item that is visible in the tree-view window. You can use the TreeView_GetFirstVisible macro to send this message.
TVGN_LASTVISIBLE
Version 4.71. Retrieves the last expanded item in the tree. This does not retrieve the last item visible in the tree-view window. You can use the TreeView_GetLastVisible macro to send this message.
TVGN_NEXT
Retrieves the next sibling item. You can use the TreeView_GetNextSibling macro to send this message.
TVGN_NEXTSELECTED
Microsoft Windows Vista and later. Retrieves the next selected item. You can use the TreeView_GetNextSelected macro to send this message.
TVGN_NEXTVISIBLE
Retrieves the next visible item that follows the specified item. The specified item must be visible. Use the TVM_GETITEMRECT message to determine whether an item is visible. You can use the TreeView_GetNextVisible macro to send this message.
TVGN_PARENT
Retrieves the parent of the specified item. You can use the TreeView_GetParent macro to send this message.
TVGN_PREVIOUS
Retrieves the previous sibling item. You can use the TreeView_GetPrevSibling macro to send this message.
TVGN_PREVIOUSVISIBLE
Retrieves the first visible item that precedes the specified item. The specified item must be visible. Use the TVM_GETITEMRECT message to determine whether an item is visible. You can use the TreeView_GetPrevVisible macro to send this message.
TVGN_ROOT
Retrieves the topmost or very first item of the tree-view control. You can use the TreeView_GetRoot macro to send this message.
hitem
Handle to an item.
Return Value Returns the handle to the item if successful. For most cases, the message returns a NULL value to indicate an error. See the Remarks section for details.
wParam = 标志
lParam = 树型视图的句柄(仅仅当wParam的值是某些标志位时才是必须的)。
wParam中的值非常重要,我解释如下: TVGN_CARET选中的项目
TVGN_CHILD hitem参数指定项目的第一个子项目
TVGN_DROPHILITE拖-拉操作的目的项目
TVGN_FIRSTVISIBLE第一个可见项目
TVGN_NEXT 下一个同级项目
TVGN_NEXTVISIBLE下一个可见项目,指定的项目必须可见。发送消息TVM_GETITEMRECT 来决定项目是否可见
TVGN_PARENT指定项目的父项目
TVGN_PREVIOUS前一个同级项目
TVGN_PREVIOUSVISIBLE前一个可见项目,指定的项目必须可见。发送消息TVM_GETITEMRECT 来决定项目是否可见
TVGN_ROOT根项目
由此您可以通过发送该消息来得到项目的句柄,然后在发送消息TVM_GETITEM时在结构体变量TV_ITEM的成员变量hItem中放入该项目的句柄就可以得到关于该项目的有关信息了。 到此一些基本的操作就都介绍过了,两个控件之间的关联也OK了,下次内容将会介绍在树形视图中进行拖-拉操作,并介绍如何判断在项目中单击某项获取,右键弹出菜单等等,最终给出一个实例工程方便交流。