如何拖动树视图项
本主题演示了处理拖放树视图项目的代码。 示例代码由三个函数组成。 第一个函数开始拖动操作,第二个函数拖动图像,第三个函数结束拖动操作。
注意
拖动树视图项通常涉及处理 TVN_BEGINDRAG(或 TVN_BEGINRDRAG) 通知代码、WM_MOUSEMOVE 消息和 WM_LBUTTONUP(或 WM_RBUTTONUP)消息。 它还涉及使用 Image Lists 函数在拖动时绘制项。
需要了解的事项
技术
先决条件
- C/C++
- Windows 用户界面编程
说明
步骤 1:开始树视图拖动操作
每当用户开始拖动项时,树视图控件就会向父窗口发送 TVN_BEGINDRAG(或 TVN_BEGINRDRAG)通知代码。 父窗口以 WM_NOTIFY 消息的形式接收通知,其 lParam 参数是 NMTREEVIEW 结构的地址。 此结构的成员包括鼠标指针的屏幕坐标和包含要拖动的项信息的 TVITEM 结构。
以下示例演示如何处理 WM_NOTIFY 消息以获取 TVN_BEGINDRAG。
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case TVN_BEGINDRAG:
Main_OnBeginDrag(((LPNMHDR)lParam)->hwndFrom, (LPNMTREEVIEW)lParam);
break;
// Handle other cases here.
}
break;
开始拖动操作涉及使用 ImageList_BeginDrag 函数。 该函数的参数包括图像列表的句柄,其中包含拖动操作和图像索引期间要使用的图像。 可以提供自己的图像列表和图像,也可以使用 TVM_CREATEDRAGIMAGE 消息通过树视图控件创建。
由于拖动图像可替换拖动操作期间的鼠标指针,因此 ImageList_BeginDrag 需要指定图像中的热点。 热点的坐标相对于图像的左上角。 ImageList_BeginDrag 还需要指定拖动图像的初始位置。 应用程序通常设置初始位置,以便拖动图像的热点对应于用户开始拖动操作时鼠标指针的热点。
以下函数演示如何开始拖动树视图项。 它使用树视图控件提供的拖动图像,并获取项的边框,以确定适合热点的点。 边框的尺寸与图像的尺寸相同。
该函数捕获鼠标输入,导致鼠标消息发送到父窗口。 父窗口需要后续 WM_MOUSEMOVE 消息来确定拖动图像的位置,并需要 WM_LBUTTONUP 消息来确定何时结束拖动操作。
// Begin dragging an item in a tree-view control.
// hwndTV - handle to the image list.
// lpnmtv - address of information about the item being dragged.
//
// g_fDragging -- global BOOL that specifies whether dragging is underway.
void Main_OnBeginDrag(HWND hwndTV, LPNMTREEVIEW lpnmtv)
{
HIMAGELIST himl; // handle to image list
RECT rcItem; // bounding rectangle of item
// Tell the tree-view control to create an image to use
// for dragging.
himl = TreeView_CreateDragImage(hwndTV, lpnmtv->itemNew.hItem);
// Get the bounding rectangle of the item being dragged.
TreeView_GetItemRect(hwndTV, lpnmtv->itemNew.hItem, &rcItem, TRUE);
// Start the drag operation.
ImageList_BeginDrag(himl, 0, 0, 0);
ImageList_DragEnter(hwndTV, lpnmtv->ptDrag.x, lpnmtv->ptDrag.x);
// Hide the mouse pointer, and direct mouse input to the
// parent window.
ShowCursor(FALSE);
SetCapture(GetParent(hwndTV));
g_fDragging = TRUE;
return;
}
步骤 2:拖动树视图项
在父窗口收到 WM_MOUSEMOVE 消息时,通过调用 ImageList_DragMove 函数来拖动树视图项,如以下示例所示。 该示例还演示如何在拖动操作期间执行命中测试,以确定是否将树视图中的其他项目突出显示为拖放操作的目标。
// Drag an item in a tree-view control,
// highlighting the item that is the target.
// hwndParent - handle to the parent window.
// hwndTV - handle to the tree-view control.
// xCur and yCur - coordinates of the mouse pointer,
// relative to the parent window.
//
// g_fDragging - global BOOL that specifies whether dragging is underway.
void Main_OnMouseMove(HWND hwndParent, HWND hwndTV, LONG xCur, LONG yCur)
{
HTREEITEM htiTarget; // Handle to target item.
TVHITTESTINFO tvht; // Hit test information.
if (g_fDragging)
{
// Drag the item to the current position of the mouse pointer.
// First convert the dialog coordinates to control coordinates.
POINT point;
point.x = xCur;
point.y = yCur;
ClientToScreen(hwndParent, &point);
ScreenToClient(hwndTV, &point);
ImageList_DragMove(point.x, point.y);
// Turn off the dragged image so the background can be refreshed.
ImageList_DragShowNolock(FALSE);
// Find out if the pointer is on the item. If it is,
// highlight the item as a drop target.
tvht.pt.x = point.x;
tvht.pt.y = point.y;
if ((htiTarget = TreeView_HitTest(hwndTV, &tvht)) != NULL)
{
TreeView_SelectDropTarget(hwndTV, htiTarget);
}
ImageList_DragShowNolock(TRUE);
}
return;
}
步骤 3:结束树视图拖动操作
下面的示例演示如何结束拖动操作。 父窗口收到 WM_LBUTTONUP 消息时调用 ImageList_EndDrag 函数。 树视图控件的句柄将传递给函数。
// Stops dragging a tree-view item, releases the
// mouse capture, and shows the mouse pointer.
//
// g_fDragging - global BOOL that specifies whether dragging is underway.
void Main_OnLButtonUp(HWND hwndTV)
{
if (g_fDragging)
{
// Get destination item.
HTREEITEM htiDest = TreeView_GetDropHilight(hwndTV);
if (htiDest != NULL)
{
// To do: handle the actual moving of the dragged node.
}
ImageList_EndDrag();
TreeView_SelectDropTarget(hwndTV, NULL);
ReleaseCapture();
ShowCursor(TRUE);
g_fDragging = FALSE;
}
return;
}
相关主题