vc++ mfc中拖动效果的实现 借助于CImageList

拖动是界面编程频繁使用的一个效果,在windows系统下可谓大行其道。纵观时下的应用软件几乎各个都支持各种各样拖动的效果,windows7更是把拖动做到了极致。其实说起来拖动的实现也很简单,对于有句柄的对象都可以通过MoveWindow或SetWindowPos实现位置变动,而没有句柄的对象实现拖动无非就是做些参数修改,说到底实现拖动就是在OnLButtonDown、OnMouseMove和OnLButtonUp中处理数据,当然你可以使用鼠标右键甚至中建消息来实现,基本原理是一样的。
      基本原理是不难,不过要想做到效果二字就要动一番脑筋了。让我们来看看win7下的图标拖放,鼠标会拖起一个半透明的图标副本到你想要的位置,透过这个透明的图标你可以看到其下面的情况,这样的效果其实在windows的早期版本就已经实现了,它有着很好的用户体验。那么我们能不能轻松的实现类似的拖动效果呢?答案当然是肯定的!最近看到论坛里几个讨论拖动的帖子,正巧前一段时间自己也做了一些相关的工作,小研究了一下,于是就想把研究成果拿出来和大家分享,这样才有利于交流和进步嘛。以前我写博客没贴过效果图,以至于很多网友下载示例代码之后发现不是自己想要的东西,这个确实不好,在此我向大家表示歉意。这次把效果图贴上,如果觉得这个效果很一般或者不是你所需要的那就不要浪费你宝贵的时间阅读文章和下载代码了。

18852_12901570587qaW

      从图中可以看出,我的小猪头像是可以被拖动的,半透明的那个就是拖动的副本,截图的时候鼠标没有截到,呵呵。为了让半透明效果能够明显的看出来我特意为对话框贴了张背景图。被拖动的其实是一个picture ctrl,也就是一个静态控件,当然通过后面的介绍大家会发现这个方法的扩展性比较强,可以应用于很多场合,甚至可以应用于非控件的拖动对象的情况。好了,效果就是这样了,下面切入正题开始介绍实现方法。
      对于熟悉拖动效果制作的朋友们都应该知道,实现拖动有一个很简单的方法就是通过CImageList。CImageList提供了BeginDrag、DragEnter、DragMove、DragLeave、EndDrag系列函数,分别在OnLButtonDown、OnMouseMove和OnLButtonUp等消息中合理调用这些函数就可以轻松实现对CImageList的元素的拖动效果。那么我们要做的就是构造一个CImageList,使它的元素是我们想要拖动的图片,这样就大功告成了。那怎样获取图像呢?答案也很简单,就是到被拖动的对象的DC中将所要拖动的区域拷贝到一个内存位图中即可。具体到我的这个例子,我是这样实现的:
      在OnLButtonDown中判断鼠标是否在控件范围内,如果在就将控件范围内的DC内容拷贝到内存位图中,然后创建CImageList将包含有控件内容的位图添加进CImageList作为其元素,接着通过这个ImageList实现拖动。具体代码如下

void CDragDemoDlg::OnLButtonDown(UINT nFlags, CPoint point)  {  CRect   rectPic;  POINT   ptPut   = point;  GetDlgItem(IDC_STATIC_DEMO)->GetWindowRect(rectPic);  ClientToScreen(&ptPut);  if(rectPic.PtInRect(ptPut))  {  CBitmap     bitmapTemp, *pOldBitmap;  CDC         *pDC    = GetDlgItem(IDC_STATIC_DEMO)->GetDC(),  *pMemDC = new CDC;  //创建位图内存  
  bitmapTemp.CreateCompatibleBitmap(pDC, rectPic.Width(), rectPic.Height());  pMemDC->CreateCompatibleDC(pDC);  pOldBitmap  = pMemDC->SelectObject(&bitmapTemp);  pMemDC->BitBlt(0, 0, rectPic.Width(), rectPic.Height(), pDC, 0, 0, SRCCOPY);  pMemDC->SelectObject(pOldBitmap);  delete  pMemDC;  ReleaseDC(pDC);  m_bIsLButtonDown    = TRUE;  m_ptOffset.x    = ptPut.x-rectPic.left;  m_ptOffset.y    = ptPut.y-rectPic.top;  m_imgDrag.DeleteImageList();  m_imgDrag.Create(rectPic.Width(), rectPic.Height(), ILC_COLOR32|ILC_MASK, 0, 1);    }  CDialog::OnLButtonDown(nFlags, point);  }
      这里我说明两个问题: 一是BeginDrag(0, m_ptOffset);的m_ptOffset参数,BeginDrag函数很容易理解了,就是进入拖动状态,而m_ptOffset参数是拖动时鼠标相对于拖动图标的偏移,注意是相对偏移。大家可以自己改一下这个参数,比如改成CPoint(0, 0)来感受一下这个设置的作用。二是DragEnter(NULL, ptPut);的ptPut这个参数指定了初始拖动时图标出现的位置,这里注意这个位置不是图标左上角的位置,而是左上角加上偏移后的位置。这个位置应用的也不是相对坐标或客户区坐标,而是屏幕坐标。
      接下来是移动的处理,其实很简单就是一个DragMove函数。他有一个参数,也是一个点,意义和DragEnter的ptPut参数相似。例子中我限制了图标不能超出窗口范围,也是通过修改这个参数实现的。理论上我们可以拖着图标在屏幕范围内任意移动,不过结合这个例子如果在窗口范围以外释放鼠标那控件就找不到了,所以我做了限制,同时也可以更好的理解m_ptMove参数的意义。具体实现可以参考以下代码。
void CDragDemoDlg::OnMouseMove(UINT nFlags, CPoint point)  {  if(m_bIsLButtonDown)  {  CRect       rtClient, rtPicture;  m_ptMove    = point;  GetDlgItem(IDC_STATIC_DEMO)->GetWindowRect(rtPicture);  GetClientRect(rtClient);  ClientToScreen(&rtClient);  ClientToScreen(&m_ptMove);  if(rtClient.left>m_ptMove.x-m_ptOffset.x)  m_ptMove.x  = rtClient.left+m_ptOffset.x;  if(rtClient.top>m_ptMove.y-m_ptOffset.y)  m_ptMove.y  = rtClient.top+m_ptOffset.y;  if(rtClient.right-rtPicture.Width()         m_ptMove.x  = rtClient.right-rtPicture.Width()+m_ptOffset.x;  if(rtClient.bottom-rtPicture.Height()           m_ptMove.y  = rtClient.bottom-rtPicture.Height()+m_ptOffset.y;  }  CDialog::OnMouseMove(nFlags, point);  }
      好了,现在就剩结束拖动状态的相关操作了,这部分就比较简单了,我代码中还加了一些容错判断和移动控件的操作,大家注意提取有效信息。
void CDragDemoDlg::OnLButtonUp(UINT nFlags, CPoint point)  {  if(m_bIsLButtonDown)  {  CRect   rectPic;  CWnd*   pPic    = GetDlgItem(IDC_STATIC_DEMO);  ScreenToClient(&m_ptMove);  pPic->GetWindowRect(rectPic);  pPic->MoveWindow(m_ptMove.x-m_ptOffset.x, m_ptMove.y-m_ptOffset.y, rectPic.Width(), rectPic.Height());  m_bIsLButtonDown    = FALSE;    pPic->Invalidate();  }  CDialog::OnLButtonUp(nFlags, point);  }
       到此拖动效果就实现了,最后再说一点,例子中有关于鼠标捕获和释放的操作,目的是为了当鼠标离开窗口范围仍然可以响应,而且针对窗口有可能被其它程序抢夺焦点的情况,例程中专门处理了OnActivate消息,具体实现可以参考示例源码,就不在这里赘述了。应该说通过CImageList实现拖动操作是十分方便的,而且效果也很好。据说VS2008下的CImageList还支持PNG,那样就可以做出更炫的拖动效果了。
       再说一个题外话,本文是通过Windows Live Writer编辑并发布的,这个工具是论坛里的muzizongheng推荐的,确实很好用,在此也对muzizongheng表达一下谢意。本文只是对拖动效果的一个简单实现,如果有更好的方法还望大家赐教,在此谢过
void CDragDemoDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{CDialog::OnActivate(nState, pWndOther, bMinimized);if(nState==WA_INACTIVE)//当失去焦点后,
    {m_bIsLButtonDown    = FALSE;CImageList::DragLeave(this);CImageList::EndDrag();ReleaseCapture();}
}

转载于:https://www.cnblogs.com/lujin49/p/4978277.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/286631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从浏览器地址栏输入url到显示页面的步骤

从浏览器地址栏输入url到显示页面的步骤(以HTTP为例)- 在浏览器地址栏输入URL- 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤 - 如果资源未缓存,发起新请求 - 如果已缓存,检验是否足够新鲜,足够…

有序的Map集合--LinkedHashMap

提出问题: 在写一个dao的时候,我的需求是这个dao是一个万能的,目前的方法只有一个查询出实体类对应的表中所有的数据,通过传入的对象,利用反射获取实体类中的属性名,属性类型,利用字符串拼接获取…

Leetcode之仅仅反转字母

1 题目 给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。 示例 1:输入:"ab-cd" 输出:"dc-ba" 示例 2:输入:"a-bC-dEf-ghIj" 输出:"j-Ih-gfE-dCba" 示例 3:输入:&qu…

【SignalR全套系列】之在.Net Core 中实现长轮询

微信公众号:趣编程ACE关注可了解更多的.NET日常实战开发技巧,如需源码 请后台留言 源码;前文回顾【SignalR全套系列】之在.Net Core 中实现Server-Send Events消息推送【SignalR全套系列】之在.NetCore中实现WebSocket双工通信【SignalR全套系列】之在.N…

完美解决ArcGIS10.2和Erdas9.2软件冲突的方法:共存!

用过ArcGIS和Erdas软件的都知道,二者存在着服务的冲突,为了解决共存的问题,笔者曾多次重装系统,但未能如愿以偿。其实不需要相互关闭服务如此麻烦。那如何在安装有arcgis的电脑安装erdas并解决冲突呢?直接上视频教程。…

架构师之路16年精选50篇

2016精选索引,点击标题阅读相关文章。【方法论】《秒杀系统架构优化思路》《分布式ID生成器》《互联网架构,如何进行容量设计》《线程数究竟设多少合理》《单点系统架构的可用性与性能优化》《关于负载均衡的一切》《异构服务器负载均衡及过载保护》《LV…

yii 前后台分离及登陆验证

2019独角兽企业重金招聘Python工程师标准>>> 比较合理的做法其实是分成两个框架来布署;然而这样说法也太绝对。 事实上是针对不同系统,应采用不同的方法。如为CMS系统,则不需很复杂的权限管理,但如果有管理员与会员之分…

双谷人才财务管理(序)

IT是一个迅速发展的行业,教育是一个良心的行业,两者交集——IT培训,在整个市场中占有一个不可或缺的地位。好多大学生,抱怨找不到工作;好多企业找不到合适的程序员,这几年这个问题越来越严重。。。。于是IT…

Android之打开手机系统相册

1、需求 打开系统相册,获取图片进行扫描操作 2、代码实现 Intent pickIntent new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");Ca…

Kibana

2019独角兽企业重金招聘Python工程师标准>>> Kibana是一个基于浏览器页面的Elasticsearch前端展示工具。Kibana全部使用HTML语言和Javascript编写的,查询语法是基于Lucene的查询语法。允许布尔运算符、通配符和字段筛选。注意关键字要大写 全文搜索 在搜…

电脑QQ能登上,网页打不开的解决办法

打开360卫士,在功能大全里选择网络优化,断网急救箱。 可以看到DNS服务异常、浏览器配置异常,点击立即修复。

个人黑名单 抄袭耻辱墙

抄袭耻辱墙 博主抄袭文原文我爱Python数据挖掘https://blog.csdn.net/weixin_38037405/article/details/125862095https://blog.csdn.net/A757291228/article/details/117464313黄埔数据分析https://blog.csdn.net/weixin_39060517/article/details/118024847https://blog.csdn…

快速掌握 ASP.NET 身份认证框架 Identity(一)

推荐关注「码侠江湖」加星标,时刻不忘江湖事ASP.NET Core 内置了一个强大的身份认证框架 Identity,掌握它可以让我们快速开发高安全的身份认证功能,不仅如此,它还是一个基于数据库的用户管理系统,其中包含了大量的辅助…

浅谈大型web系统架构

动态应用,是相对于网站静态内容而言,是指以c/c、php、Java、perl、.net等服务器端语言开发的网络应用软件,比如论坛、网络相册、交友、BLOG等常见应用。动态应用系统通常与数据库系统、缓存系统、分布式存储系统等密不可分。   大型动态应用…

Android之webview长按超链接类型获取链接文字及url、长按图片链接类型分别获取图片和链接的url

1 、需求 webview长按超链接获取链接文字及urlwebview长按图片链接类型获分别获取图片和链接的url 2、解决办法 1)、设置webview的OnLongClickListener事件,关键代码如下 companion object {const val LINK_TYPE = 1const val IMAGE_LINK_TYPE = 2}var mHandler = object :…

PostgreSQL 统计信息pg_statistic格式及导入导出dump_stat - 兼容Oracle

标签 PostgreSQL , dump_stat , 统计信息 , 导出导入 背景 《PostgreSQL 规格评估 - 微观、宏观、精准 多视角估算数据库性能(选型、做预算不求人)》 EXPLAIN是PG数据库用于输出SQL执行计划的语法, 1、生成的执行计划中包含COST一项。 如果校准了成本因子&#xff0…

PHP: 手把手编写自己的 MVC 框架实例教程

1 什么是MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。 …

freemarker 异常处理

SSH2处理方案&#xff1a; freemarker文件如果出错&#xff0c;网站的前台页面会报出很明显的错误-焦黄的背景&#xff0c;血红的文字&#xff0c;很不利于用户体验的。如何修改这个问题呢&#xff1f;首先需要在struts.xml配置文件里添加下面一行代码&#xff1a; 1<consta…

ArcGIS10.8按属性选择中根据关键字like模糊查询方法总结

在实际工作中,通常需要按照某一个或某几个关键字进行模糊查询,已到达快速、准确、高效查询的目的。在ArcGIS中是通过SQL语句,利用关键字like来实现的。例如我们可以借助like快速查询满足以某一个关键字开头,以某一个关键字结尾,或者包含某一个关键字的结果。 在ArcGIS中,…

2021年复盘总结发现了C站博主缺少的赚钱之路

一、 我2021年的六大Flag 其实最开始我是不打算年终总结的&#xff0c;因为2021年我的十大Flag都没有完成&#xff0c;我说出来可能你会嘲笑我&#xff0c;所以我打算还是说出来吧。 这六大Flag如下&#xff1a; C站百万粉百篇实战文其他自媒体平台十万粉公众号一万粉财务自…