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.pswp.cn/news/286631.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/286631.shtml
英文地址,請注明出處:http://en.pswp.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站百萬粉百篇實戰文其他自媒體平臺十萬粉公眾號一萬粉財務自…