本主题演示用于处理树视图项拖放的代码。 示例代码由三个函数组成。 第一个函数开始拖动作,第二个函数拖动图像,第三个函数结束拖动作。
注释
拖动树视图项通常涉及处理 TVN_BEGINDRAG (或 TVN_BEGINRDRAG)通知代码、 WM_MOUSEMOVE 消息和 WM_LBUTTONUP (或 WM_RBUTTONUP)消息。 它还涉及使用 图像列表 函数在拖动时绘制项。
需要了解的内容
技术
先决条件
- 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;
}