En este tutorial aprenderemos a usar el control Tree View (vista de árbol). Es más, también aprenderemos cómo arrastrar objetos y ponerlos en el control Tree View; además veremos cómo usar una lista de imágenes en este control. Puedes bajar el ejemplo aquí.
Un control Tree View es un tipo especial de ventana que representa objetos en orden jerárquico. Un ejemplo es el panel izquierdo del Explorador de Windows. Se puede personalizar este control para mostrar relaciones entre los objetos.
Puedes crear un control Tree View llamando CreateWindowEx y pasando la cadena "SysTreeView32" como el nombre de la clase o puedes incorporarlo en una caja de diálogo. No hay que olvidar poner una llamada a InitCommonControls en el código fuente. Hay varios estilos específicos al control Tree View. Estos tres son los más usados.
TVS_HASBUTTONS == Despliega botones
más (+) y menos (-) al lado de los elementos [items] padres. El usuario
hace click con los botones del ratón sobre los elementos para expandir
o contraer una lista de elementos hijos subordinada a un elemento padre. Para
incluir botones con elementos en la raiz del tree view, debe especificarse el
estilo TVS_LINESATROOT.
TVS_HASLINES == Usa líneas para
mostrar la jerarquía de elementos.
TVS_LINESATROOT == Usa líneas
para enlazar elementos en la raiz del control tree-view. Este valor es ignorado
ignored si TVS_HASLINES tampoco es especificado.
El control Tree View, como otros controles comunes, se comunica con su ventana padre a través de mensajes. La ventana padre le puede enviar varios mensajes y el control Tree View puede enviar mensajes de "notificación" a su ventana padre. En este proceso, el control Tree View no difiere de las otras ventanas: cuando algo interesante ocurre en él, envía un mensaje WM_NOTIFY con información a la ventana padre.
WM_NOTIFY
wParam == ID del control, nada garantiza
que este valor sea el único, así que nosotros
no lo usamos. Es mejor usar
hwndFrom o el miembro IDFrom de la estructura
NMHDR a la que apunta lParam
lParam == Puntero a la
estructura NMHDR. Algunos controles pueden pasar un puntero
más largo pero debe tener una estructura NMHDR
como primer miembro.
Es decir, cuando tenemos lParam, podemos estar seguros que apunta a una
estructura NMHDR.
Ahora examinaremos la estructura NMHDR.
NMHDR struct DWORD
hwndFrom DWORD ?
idFrom DWORD ?
code DWORD ?
NMHDR ends
hwndFrom es el manejador de la ventana
que envía este mensaje WM_NOTIFY.
idFrom es el ID del control que
envía este mensaje.
code es el mensaje actual que el control quiere enviar a su ventana padre.
Las notificaciones del control Tree view tienen TVN_ al comienzo, como TVM_CREATEDRAGIMAGE. El control tree view envía TVN_xxxx en el miembro código de NMHDR. La ventana padre puede enviar TVM_xxxx para controlarlo.
Después de crear un control Tree View, podemos agregarle elementos. Puedes hacer esto enviándole TVM_INSERTITEM.
TVM_INSERTITEM
wParam = 0;
lParam = pointer to a TV_INSERTSTRUCT;
A estas alturas, bebes conocer cierta terminología sobre la relación entre los elementos en el control Tree View. Un elemento puede ser al mismo tiempo padre, hijo, o ambos. Un elemento padre es el que tiene algún(os) otro(s) subelemento(s) asociado(s) con él. Al mismo tiempo, el el elemento padre puede ser un hijo de algún otro elemento. Un elemento sin un padre se llama elemento raíz. Puede haber muchos elementos raíz en un control tree view. Ahora examinemos la estructura TV_INSERTSTRUCT
TV_INSERTSTRUCT STRUCT DWORD
hParent DWORD ?
hInsertAfter DWORD ?
ITEMTYPE < >
TV_INSERTSTRUCT ENDS
hParent
= Manejador del elemento padre. Si este miembro es el valor TVI_ROOT
o NULL, el elemento es insertado en la raiz del control tree-view.
hInsertAfter
= Manejador del elemento después del cual el nuevo elemento va a ser
insertado o uno de los siguientes valores:
ITEMTYPE UNION
itemex TVITEMEX
< >
item TVITEM
< >
ITEMTYPE ENDS
Aquí usaremos solamente TVITEM.
TV_ITEM STRUCT DWORD
imask
DWORD ?
hItem
DWORD ?
state
DWORD ?
stateMask DWORD
?
pszText DWORD
?
cchTextMax DWORD
?
iImage
DWORD ?
iSelectedImage
DWORD ?
cChildren
DWORD ?
lParam
DWORD ?
TV_ITEM ENDS
Esta estructura es empleada para enviar y recibir información sobre un elemento del tree view, dependiendo de los mensajes. Por ejemplo, con TVM_INSERTITEM, es usada para especificar el atributo del elemento a ser insertado dentro del control tree view. Con TVM_GETITEM, será llenado con información sobre el elemento seleccionado.
imask es
usado para especificar cual(es) miembro(s) de la estructura TV_ITEM es
(son) valido(s). Por ejemplo, si el valor en imask es TVIF_TEXT, significa
sólo que el miembro pszText es válido. Puede cpmbinarse con algunas
banderas.
hItem es
el manejador del elemento en el control tree view. Cada elemento tiene su propio
manejador, lo mismo que una ventana tiene su manejador. Si se quiere hacer algo
con un elemento, debe seleccionarse ese elemento por su manejador.
pszText
es el puntero a una cadena terminada en cero que indica el nivel de un elemento
dentro de un control tree view.
cchTextMax
es usado sólo cuando se quiere regresar el nivel de un elemento dentro
de un control tree view. Como el prgramador debe suministrar el puntero al bufer
en pszText, Windows debe saber el tamaño del buffer proveído.
Hay que suministrar el tamaño del buffer en este miembro.
iImage y
iSelectedImage refieren al índice dentro de una lista de imágenes
que contienen las imágenes a ser mostradas cuando el elemento no es seleccionado
(iImage) y cuando es seleccionado (iSelectedImage). Si corres el Explorador
de Windows, verás que en el panel izquierdo unas imágenes que
representan las carpetas; esas imágenes están especificadas por
estos dos miembros.
Con el fin de insertar un elemento dentro del control tree view, al menos deben llenarse los miembros hParent, hInsertAfter, así como imask and pszText.
Si quieres poner una imagen a la izquierda de la etiqueta de un elemento del control tree view, se debe crear una lista de imágenes y asociarla con el control tree view. Se puede crear una lista de imágenes llamando a ImageList_Create.
ImageList_Create PROTO cx:DWORD, cy:DWORD, flags:DWORD, \
cInitial:DWORD, cGrow:DWORD
Si esta función tiene éxito, regresa el manejador a una lista de imágenes vacía.
cx ==
ancho de cada imagen en esta lista, en pixeles.
cy
== altura de cada imagen en esta lista, en pixeles. Todas las imágenes
en una lista deben ser iguales en tamaño. Si se especifica un gran bitmap,
Windows usará cx y cy para *cortarla* en varios pedazos. Así que
las imágenes propias deben prepararse como una secuencia de "pinturas"
del mismo tamaño.
flags
== especifica el tipo de imágnes en esta lista: si son de color o monócromos
y su profundidad de color. Consulta la refencia de la API de Win32 para mayor
información.
cInitial
== El número de imágenes que esta lista contendrá inicialmente.
Windows usará esta información para localizar memoria para las
imágenes.
cGrow
== Cantidad de imágenes a las que la lista de imágenes puede expandirse
cuando el sistema necesita cambiar el tamaño de la lista para hacer disponibles
más imágnes. Este parámetro representa el número
de imágenes nuevas que puede tener una lista de imágenes que ha
cambiado de tamaño.
¡Una lista de imágenes no es una ventana! Es sólo un depósito de imágenes que ha de ser usado por otras ventanas. Después de crear una lista de imágens, se deben agregar imágenes llamando a ImageList_Add
ImageList_Add PROTO himl:DWORD, hbmImage:DWORD, hbmMask:DWORD
Esta función regresa -1 si no tiene
éxito.
himl ==
manejador de la lista de imágenes a la cual quieres agregar imágenes.
Es el valor regresado por una llamada satisfactoria a ImageList_Create
hbmImage
== manejador del bitmap a ser agregado a la lista de imágenes. Usualmente
almacenas el bitmap en el recurso y lo cargas en la llamada a LoadBitmap.
Nota que no tienes que especificar los parámetros pasados con el número
de imágenes contenidas en este bitmap porque esta información
es inferida a partir de los parámetros cx y cy pasados con la llamada
a ImageList_Create.
hbmMask
== Manejador [handle] al bitmap que contiene la máscara. Si no se usa
ninguna máscara con la lista de imágenes, se ignora este parámetro.
Normalmente, agregaremos sólo dos imágenes a la lista de imágenes para usar con el control treeview: una usada cuando el elemento del control tree view no está seleccionado, y otra para cuando el elemento es seleccionado.
Cuando la lista de imágenes ya está lista, la asociamos con el control treeview enviando TVM_SETIMAGELIST al control.
TVM_SETIMAGELIST
wParam = tipo de lista de imagen a
establecer. Hay dos posibilidades:
lParam = Manejador de la lista de imágenes
Puedes recuperar información sobre un elemento de un control tree view enviando el mensaje TVM_GETITEM.
TVM_GETITEM
wParam = 0
lParam = puntero a la estructura TV_ITEM
structure a ser llenada con la información
antes de enviar este mensaje, debe llenarse el miembro imask con la(s) bandera(s) que especifica(n) cual(es) miembro(s) de TV_ITEM queires que llene Windows. Y lo más importante, debes llenar hItem con el manejador al elemento del cual deseas obtener información. Pero esto tiene un problema: ¿Cómo puedes conocer el manejador del elemento del cual deseas recuperar información? ¿Habrá que almacenar todos los manejadores del control Tree View? La respuesta es simple: no tienes necesidad de hacerlo. Puedes enviar el mensaje TVM_GETNEXTITEM al control tree view para recuperar el manejador al elemento del tree view elemento que tiene el (o los) que tú especificaste. Por ejemplo, puedes solicitar el manejador del primer elemento hijo, del elemento raiz, del elemento seleccionado, etc.
TVM_GETNEXTITEM
wParam = bandera
lParam = manejador a un elemento tree
view (sólo necesario para algunos valores de la bandera)
El valor en wParam es tan importante que prefiero presentar abajo todas las banderas:
Como puede verse, si se quiere recuperar el manejador a un elemento del control tree view este mensaje resulta de gran interés. SendMessage regresa el manejador al elemento del tree view si tiene éxito. Se puede llenar el valor regresado dentro del miembro hItem de TV_ITEM a ser usado con el mensaje TVM_GETITEM.
Esta parte es la razón por la cual decidí escribir este tutorial. Cuando intenté seguir el ejemplo en la referencia de la api win32 (el win32.hlp desde InPrise), quedé muy frustrado porque carecía de la información vital sobre este punto. Por error y prueba, finalmente esbozé como implementar drag & drop [arrastrar y soltar] en un control tree view y no quiero que nadie pase por lo mismo que yo.
Abajo están los pasos para implementar operaciones drag & drop en un control tree view.
ImageList_BeginDrag PROTO himlTrack:DWORD,
\
iTrack:DWORD , \
dxHotspot:DWORD, \
dyHotspot:DWORD
himlTrack
es el manejador a la lista de imágenes que contiene la imagen de arratre.
iTrack
es el índice a la lista de imágenes que especifica la imagen
de arrastre
dxHotspot
especifica la distancia relativa al "punto caliente" [hotspot]
en el plano horizontal en la imagen de arrastre ya que esta imagen será
usada en el lugar del cursor del ratón, así que especificamos
usar cual parte de la imagen es el "punto caliente" .
dyHotspot
especifica la distancia relativa del "punto caliente" en el plano
vertical.
Normalmente, iTrack debería ser
0 si le dices al control tree view que cree la imagen de arrastre para tí,
y dxHotspot y dyHotspot pueden ser 0 si quieres que la esquina izquierda superior
de la imagen de arrastre sea el hotspot.
ImageList_DragEnter PROTO hwndLock:DWORD,
x:DWORD, y:DWORD
hwndLock
es el manejador [handle] de la imagen propietaria de la imagen de arrastre.
La imagen de arrastre no será capaz de moverse fuera de esa ventana.
x e y
son las coordenadas x- e y- del lugar donde la imagen de arrastre debería
estar desplegada inicialmente. Nota que estos valores son relativos a la esquina
izquierda superior de la ventana, no del área cliente.
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comctl32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
.const
IDB_TREE equ 4006
; ID del recurso bitmap
.data
ClassName db "TreeViewWinClass",0
AppName db "Tree View Demo",0
TreeViewClass db "SysTreeView32",0
Parent db "Parent Item",0
Child1 db "child1",0
Child2 db "child2",0
DragMode dd FALSE
; una bandera para determinar si estamos en modo de arrastre
.data?
hInstance HINSTANCE ?
hwndTreeView dd ?
; manjeador del control tree view
hParent dd ? ;
manejador del elemento raíz del control tree view
hImageList dd ? ;
manejador de la lista de imágenes usadas en el control tree view
hDragImageList dd ?
; manejador de la lista de imágenes
usada para almacenar la imagen de arrastre
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
invoke ExitProcess,eax
invoke InitCommonControls
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_APPWORKSPACE
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
CW_USEDEFAULT,200,400,NULL,NULL,\
hInst,NULL
mov hwnd,eax
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp
WndProc proc uses edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL tvinsert:TV_INSERTSTRUCT
LOCAL hBitmap:DWORD
LOCAL tvhit:TV_HITTESTINFO
.if uMsg==WM_CREATE
invoke CreateWindowEx,NULL,ADDR TreeViewClass,NULL,\
WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT,0,\
0,200,400,hWnd,NULL,\
hInstance,NULL ; Create the tree view control
mov hwndTreeView,eax
invoke ImageList_Create,16,16,ILC_COLOR16,2,10 ; crear la
lista de imágenes asociada
mov hImageList,eax
invoke LoadBitmap,hInstance,IDB_TREE
; cargar el bitmap desde el recurso
mov hBitmap,eax
invoke ImageList_Add,hImageList,hBitmap,NULL; Agregar el bitmap
a la lista de imágenes
invoke DeleteObject,hBitmap ; borrar siempre el recurso bitmap
invoke SendMessage,hwndTreeView,TVM_SETIMAGELIST,0,hImageList
mov tvinsert.hParent,NULL
mov tvinsert.hInsertAfter,TVI_ROOT
mov tvinsert.item.imask,TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
mov tvinsert.item.pszText,offset Parent
mov tvinsert.item.iImage,0
mov tvinsert.item.iSelectedImage,1
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
mov hParent,eax
mov tvinsert.hParent,eax
mov tvinsert.hInsertAfter,TVI_LAST
mov tvinsert.item.pszText,offset Child1
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
mov tvinsert.item.pszText,offset Child2
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
.elseif uMsg==WM_MOUSEMOVE
.if DragMode==TRUE
mov eax,lParam
and eax,0ffffh
mov ecx,lParam
shr ecx,16
mov tvhit.pt.x,eax
mov tvhit.pt.y,ecx
invoke ImageList_DragMove,eax,ecx
invoke ImageList_DragShowNolock,FALSE
invoke SendMessage,hwndTreeView,TVM_HITTEST,NULL,addr tvhit
.if eax!=NULL
invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,eax
.endif
invoke ImageList_DragShowNolock,TRUE
.endif
.elseif uMsg==WM_LBUTTONUP
.if DragMode==TRUE
invoke ImageList_DragLeave,hwndTreeView
invoke ImageList_EndDrag
invoke ImageList_Destroy,hDragImageList
invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_DROPHILITE,0
invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_CARET,eax
invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,0
invoke ReleaseCapture
mov DragMode,FALSE
.endif
.elseif uMsg==WM_NOTIFY
mov edi,lParam
assume edi:ptr NM_TREEVIEW
.if [edi].hdr.code==TVN_BEGINDRAG
invoke SendMessage,hwndTreeView,TVM_CREATEDRAGIMAGE,0,[edi].itemNew.hItem
mov hDragImageList,eax
invoke ImageList_BeginDrag,hDragImageList,0,0,0
invoke ImageList_DragEnter,hwndTreeView,[edi].ptDrag.x,[edi].ptDrag.y
invoke SetCapture,hWnd
mov DragMode,TRUE
.endif
assume edi:nothing
.elseif uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
end start
Dentro del manejador WM_CREATE, se crea el control tree view
invoke CreateWindowEx,NULL,ADDR TreeViewClass,NULL,\
WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT,0,\
0,200,400,hWnd,NULL,\
hInstance,NULL
Notar los estilos. TVS_xxxx son los estilos específicos del control tree view.
invoke ImageList_Create,16,16,ILC_COLOR16,2,10
mov hImageList,eax
invoke LoadBitmap,hInstance,IDB_TREE
mov hBitmap,eax
invoke ImageList_Add,hImageList,hBitmap,NULL
invoke DeleteObject,hBitmap
invoke SendMessage,hwndTreeView,TVM_SETIMAGELIST,0,hImageList
Después, se crea una lista de imágenes vacía para que acepte imágenes de 16x16 pixeles en tamaño, 16-bit de color e inicialmente, contendrá 2 imágenes pero puede ser expandido hasta 10 si se necesita. Luego cargamos el bitmap desde el recurso y lo agregamos a la lista de imágenes. Después de eso, borramos el manejador del bitmap ya que no será usado más. Cuando la lista de imágenes esté toda establecida, la asociamos con el control tree view control enviando TVM_SETIMAGELIST al control tree view.
mov tvinsert.hParent,NULL
mov tvinsert.hInsertAfter,TVI_ROOT
mov tvinsert.u.item.imask,TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
mov tvinsert.u.item.pszText,offset Parent
mov tvinsert.u.item.iImage,0
mov tvinsert.u.item.iSelectedImage,1
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
Insertamos elementos en el control tree view y empezamos del elemento de la raíz. Puesto que será el elemento raíz, el miembro del hParent es NULL y hInsertAfter es TVI_ROOT. El miembro imask especifica a ese pszText, iImage y miembros del iSelectedImage de la estructura de TV_ITEM es válido. Llenamos a esos tres miembros de valores apropiados. pszText contiene la etiqueta del elemento raíz, iImage es el índice a la imagen en la lista de la imagen que se desplegará a la izquierda del elemento del no seleccionado, y iSelectedImage es el índice a la imagen en la lista de la imagen que se desplegará cuando el elemento se selecciona. Cuando todos los miembros apropiados estén llenos, enviamos el mensaje TVM_INSERTITEM al control tree view para agregar el elemento raíz a él.
mov hParent,eax
mov tvinsert.hParent,eax
mov tvinsert.hInsertAfter,TVI_LAST
mov tvinsert.u.item.pszText,offset Child1
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
mov tvinsert.u.item.pszText,offset Child2
invoke SendMessage,hwndTreeView,TVM_INSERTITEM,0,addr tvinsert
Después de agregar el elemento [item] raiz, podemos enganchar los elementos a la ventana hija. El miembro hParent es llenado ahora con el manejador del elemento padre. Y usaremos imágenes idénticas en la lista de imágenes, así que no cambiemos los miembros iImage e iSelectedImage.
.elseif uMsg==WM_NOTIFY
mov edi,lParam
assume edi:ptr NM_TREEVIEW
.if [edi].hdr.code==TVN_BEGINDRAG
invoke SendMessage,hwndTreeView,TVM_CREATEDRAGIMAGE,0,[edi].itemNew.hItem
mov hDragImageList,eax
invoke ImageList_BeginDrag,hDragImageList,0,0,0
invoke ImageList_DragEnter,hwndTreeView,[edi].ptDrag.x,[edi].ptDrag.y
invoke SetCapture,hWnd
mov DragMode,TRUE
.endif
assume edi:nothing
Ahora cuando el usuario trata de arrastrar [drag] un elemento, el control tree view control envía un mensaje WM_NOTIFY con el código TVN_BEGINDRAG. lParam es el puntero a una estructura NM_TREEVIEW que contiene algunas piezas de información que necesitamos para poner su valor dentro de edi y usar edi como el puntero a la estructura NM_TREEVIEW. assume edi:ptr NM_TREEVIEW es una manera de decirle a MASM que trate a edi como el puntero a la estructura NM_TREEVIEW. Luego creamos una imagen de arrastre enviando TVM_CREATEDRAGIMAGE al control tree view. Regresa el manejador de la lista de imágenes nuevamente creada con una imagen drag image dentro. Llamamos a ImageList_BeginDrag para establecer el "punto caliente" en la imagen de arrastre. Luego introducimos la operación de arrastre llamando a ImageList_DragEnter. Esta función emplea la imagen de arrastre en el lugar especificado de la ventana. Usamos la estructura ptDrag que es un miembro de la estructura NM_TREEVIEW como el punto donde la imagen de arratre debería ser inicializada. Después de eso capturamos la entrada del ratón y ponemos la bandera para indicar que ahora introducimos el modo de arrastre.
.elseif uMsg==WM_MOUSEMOVE
.if DragMode==TRUE
mov eax,lParam
and eax,0ffffh
mov ecx,lParam
shr ecx,16
mov tvhit.pt.x,eax
mov tvhit.pt.y,ecx
invoke ImageList_DragMove,eax,ecx
invoke ImageList_DragShowNolock,FALSE
invoke SendMessage,hwndTreeView,TVM_HITTEST,NULL,addr tvhit
.if eax!=NULL
invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,eax
.endif
invoke ImageList_DragShowNolock,TRUE
.endif
Ahora nos concentramos en WM_MOUSEMOVE. Cuando el usuario arrastra [drags] la imagen de arrastre [the drag image along], nuestra ventana padre recibe el mesaje WM_MOUSEMOVE. En respuesta a estos mensajes, actualizamos la posición de la imagen de arrastre con ImageList_DragMove. Después de eso, chequeamos si la drag image está sobre algún elemento. Hacemos eso enviando el mensaje TVM_HITTEST al control tree view con un punto para que él lo chequee. Si la imagen de arrastre está sobre el elemento, iluminamos [hilite] ese elemento enviando el mensaje TVM_SELECTITEM con la bandera TVGN_DROPHILITE al control tree view. Durante la operación de iluminación, escondemos la imagen de arrastre de manera que no deje desagradables manchas sobre el control tree view.
.elseif uMsg==WM_LBUTTONUP
.if DragMode==TRUE
invoke ImageList_DragLeave,hwndTreeView
invoke ImageList_EndDrag
invoke ImageList_Destroy,hDragImageList
invoke SendMessage,hwndTreeView,TVM_GETNEXTITEM,TVGN_DROPHILITE,0
invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_CARET,eax
invoke SendMessage,hwndTreeView,TVM_SELECTITEM,TVGN_DROPHILITE,0
invoke ReleaseCapture
mov DragMode,FALSE
.endif
Cuando el usuario suelta el botón izquierdo del ratón, llega a su final la operación de arrastre. Abandonamos el modo de arrastre llamando a ImageList_DragLeave, seguido por ImageList_EndDrag y ImageList_Destroy. Para hacer que los elementos del cotrol tree view se vean bien, también chequeamos el último elemento iluminado [hilited], y lo seleccionamos. También debemos quitar la iluminación [un-hilite], sino los otros elementos no serán iluminaods cuando ellos sean seleccionados. Y finalmente, liberamos la captura del ratón.
[Iczelion's Win32 Assembly HomePage]
n u M I T_o r's Programming Page
Este tutorial, original de Iczelion, ha sido traducido por n u M I T_o r