win32拖拽编程

勿忘初心2018-12-13 12:05

本文由作者邹启文授权网易云社区发布。


在邮箱大师PC版中,我们需要实现一个功能:账号和邮件夹拖拽排序。

  1. 准备 
    封装win32 API。我们使用到的API有, 
    ImageList_CreateImageList_Destroy、 
    ImageList_AddImageList_AddMaskedImageList_Remove、 
    ImageList_BeginDragImageList_DragEnterImageList_EndDragImageList_DragLeave、 
    ImageList_DragMoveImageList_SetDragCursorImageImageList_DragShowNoLock。 
    For more information,see Using Image Lists

  2. Drag开始 
    拦截鼠标的LButtonDown消息,判断point所在的控件是否符合拖拽要求,如果符合,记住状态(这里使用bool will_drag_和MailFolderNode* drag_from_标识可以拖拽,使用bool is_draging_标识正在拖拽中,使用MailFolderNode* drag_to_标识接受控件)

  3. Drag进行中 
    拦截鼠标的MouseMove消息,判断will_drag_,如果是,那么需要做如下操作: 
    ->ImageList_Create创建ImageList对象 
    ->ImageList_AddMasked加入拖拽时将要显示的图像 
    ->ImageList_BeginDrag即将开始拖拽,并设置鼠标在拖拽图像中的位置 
    ->ImageList_DragEnter进入拖拽,并设置拖拽图像的位置 
    ->修改will_drag_为false,is_draging_为true,保证上面几步只做一次 
    ->判断point是否在拖拽接受范围内,以及point对应控件是否接受拖拽(及时更新drag_to_) 
    ->如果是,那么执行ImageList_DragMove、ImageList_DragShowNoLock(TRUE)、SetCursor(LoadCursor(NULL, IDC_ARROW)); 
    ->如果不是,那么执行ImageList_DragShowNoLock(FALSE)、SetCursor(LoadCursor(NULL, IDC_NO));

  4. Drag结束 
    拦截鼠标的LButtonUp消息,如果is_draging_,那么执行ImageList_EndDrag、ImageList_DragLeave、ImageList_Destroy,然后根据drag_from_和drag_to_处理本次拖拽操作。

  5. 问题 



    Ⅰ、如何使拖拽图像背景透明? 
    使用CreateCompatibleBitmap创建位图,调用FillRect将位图背景刷成白色RGB(255,255,255); 
    在ImageList_Create时指定ILC_COLOR32 | ILC_MASK; 
    调用ImageList_AddMasked(bitmap, RGB(255,255,255)); 
    至此,拖拽图像中的白色会与mask'中和' 

    Ⅱ、在拖拽时出现窗口绘制被'破坏',并且残留痕迹? 
    这是由于在调用ImageList_DragEnter时锁定了窗口导致,我们使用NULL代替HWND即可解决此问题。同时,由于锁定导致了我们在拖拽时对窗口的绘制无法生效的问题亦可解决。另,记得在拖拽结束时ImageList_DragLeave(NULL); 

    Ⅲ、ImageList_BeginDrag和ImageList_DragEnter中的位置是何含义? 
    在ImageList_BeginDrag中,此处位置为鼠标图标相对于拖拽图像的位置。 
    在mageList_DragEnter中,此处位置为鼠标相对于HWND的位置,如果HWND为NULL,那么便是相对于屏幕的位置。 

    Ⅳ、ImageList_DragShowNoLock含义是什么? 
    参数BOOL表示是否显示拖拽图像。当拖拽move在可接受控件时,显示拖拽鼠标,更改鼠标样式(或使用ImageList_SetDragCursorImage设置自定义鼠标样式,注意此时需隐藏ShowCursor(FALSE));否则,不显示拖拽图像,并显示IDC_NO不可操作样式。 

    Ⅴ、will_drag_的标识是否多余? 
    为何要等到MouseMove再去真正开始drag?因为正常的单击操作,我们不希望看到拖拽图像,因此设置此标记。实际应用中发现,有时候单击时发生'抖动',此时也出现拖拽图像,因此我们加入了延时,在按下100ms后才将will_drag_设置成true,可在一定程度上减小抖动出现拖拽图像的情况。


免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

更多网易技术、产品、运营经验分享请访问网易云社区


相关文章:
【推荐】 线上日志集中化可视化管理:ELK
【推荐】 hadoop中的序列化
【推荐】 视觉设计师的进化