<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      (原創)[C#] GDI+ 之鼠標交互:原理、示例、一步步深入、性能優化

      一、前言

      “GDI+”與“鼠標交互”,乍一聽好像不可能,也無從下手,但是實現原理比想象中要簡單很多。
      基于“GDI+”的“交互”,應用場景也很多,比如:流程圖、數據圖表、思維導圖等等。

      本篇文章就通過多個示例來講解一下 GDI+ 與鼠標交互的原理,以及如何去實現。
      每一個示例實現后,都會對示例進行優化,主要是解決一些在實際應用中比較常見的問題,比如:閃爍、資源占用高等等。
      而在最后,會基于實際的應用場景——在背景圖上繪制圖形并進行鼠標交互——編寫一個示例。
      接著會使用實際應用場景內必備的、也是核心的“局部刷新”技術對示例進行優化。

      相信看完的你,一定會有所收獲!

      本文地址:http://www.rzrgm.cn/lesliexin/p/16554752.html


      二、基本原理

      GDI+ 與鼠標交互的原理非常簡單:判斷鼠標是否在 GID+ 圖形上,然后根據鼠標的不同狀態,執行不同的效果。

      估計很多人看到這句話就直接恍然大悟了。確實,原理就是這么簡單。

      下面,我們首先來簡單實現一個簡單的交互效果:可以用鼠標拖動的矩形。


      三、示例1:可以用鼠標拖動的矩形

      (一)設計器界面

      程序界面如下:

      image

      我們的繪制及交互區域就是 panel1,所以為 panel1 綁定以下幾個鼠標相關的事件:

      image

      (二)代碼實現

      1,添加全局變量

      為了與鼠標交互,我們需要以下兩個全局變量:

      image

      其中,rectShape 是我們所繪制矩形的位置和尺寸;pointLast 是上次鼠標的位置。

      2,繪制矩形方法

      繪制矩形很簡單,直接在背景上畫一個矩形即可。
      GDI+ 中繪制矩形的方法如下:
      (下圖來自MSDN)
      image

      不過為了防止殘留,我們在畫矩形前需要先清空一下背景。
      (下圖來自MSDN)
      image

      原理示意如下:

      image

      對應的代碼如下:

      image

      3,鼠標交互操作實現

      (1)當鼠標在 panel1 中點擊時,我們要判斷鼠標點擊的位置是否處于我們繪制的矩形內。

      如果是,則記錄當前鼠標的位置;
      如果不是,則清空記錄的鼠標位置;

      image

      (2)當按著鼠標按鍵并拖動鼠標時,我們要判斷是否有記錄過之前鼠標的位置。

      如果滿足條件,就證明是現在鼠標是按著所繪制的矩形進行拖動了。
      所以,我們要計算一下這次鼠標的位移量,并計算矩形的新位置,然后重新在新位置繪制矩形
      這一步,就是交互效果的核心。在拖動的過程中,我們會根據鼠標的位置不斷的計算并重新繪制新的矩形。在視覺效果上,就是我們拖動著矩形在動。

      image

      因為不斷在重新繪制矩形,所以這里是最能體現 GDI+ 性能的地方,不同的寫法,性能相差很大,這也是后續所要優化的地方。

      (3)當松開鼠標按鍵時,將記錄的鼠標位置清空。

      上面的 MouseMove 事件會因為不滿足條件,而結束重繪。

      image

      (三)效果演示

      編譯運行程序,我們會發現已經可以使用鼠標拖動矩形了。

      image

      我們會發現,拖動矩形時會出現閃爍的情況。而且窗口越大,閃爍越明顯。
      這是因為我們是先清空背景、然后再繪制矩形,這個清空再繪制的過程,就會閃爍

      下面,我們就來優化一下,解決閃爍的問題。

      (四)“閃爍”問題優化

      解決“閃爍”,我們最先想到的就是開啟“雙緩沖”,不過在這里,開啟“雙緩沖”效果不大,因為閃爍的原因在于我們自己不斷的清空再繪制。
      所以,我們優化的核心就是不再清空背景。
      開啟雙緩沖的方式如下:

      image

      我們會發現,在兩次拖動變化之間,可以看作是先將原矩形填充為背景色,再在新位置繪制一個新的矩形。

      示意圖如下:

      image

      我們按照示意圖編寫代碼如下:

      image

      (五)優化后效果演示

      編譯運行程序,我們再次拖動矩形,會發現不再有閃爍的情況。

      image


      四、示例2:可以用鼠標拖動的圓形

      在實現了可以被鼠標拖動的矩形后,我們再來實現可以被鼠標拖動的圓形。
      因為圓形和矩形是不一樣的:圓形既有可見區域,也有不可見區域。
      如圖所示:

      image

      我們本節就看一下在實現上都有哪些不同。

      (一)設計器界面

      設計器界面同上,增加一個按鈕用來添加圓形。

      image

      (二)代碼實現

      1,添加全局變量

      因為 GDI+ 中繪制圓形的參數和矩形是一樣的,都是一個 Rectangle ,所以我們可以復用之前的全局變量,不用進行修改。
      (下圖來自MSDN)
      image

      2,繪制圓形方法

      這里,我們直接采用上節優化后的方法去實現,即:將舊矩形填充背景色,再在新位置繪制新圓形。

      原理示意見上節,具體代碼如下:

      image

      3,鼠標交互操作實現

      這里與上節繪制矩形的原理一樣,只需要在 MouseMove 事件中將繪制矩形的方法改為繪制圓形的方法即可。
      代碼修改如下:

      image

      (三)效果演示

      編譯運行,可以發現我們可以正常使用鼠標拖動繪制的圓形。
      【注:我們會發現,同樣是優化后的方法,在繪制“矩形”時不會閃爍,但是在繪制“圓形”時會閃爍,這是因為繪制圓形會更加消耗性能,關于如何解決閃爍的問題,參見下面:“六、使用“局部刷新”技術對【示例3】進行優化”。因為本節內容的重點不在于此,所以未在此節解決閃爍問題。】

      image

      在拖動的時候,我們會發現一個問題:就是我們的鼠標即不在圓形上,而是在圓的四個邊角處,也能正常拖動圓形。
      如下:

      image

      這是因為圓形和矩形不一樣,圓形是有可見區域(即顯示的圓形)和不可見區域(即非圓形區域),雖然不可見,但仍然是存在的,所以仍然會正常捕獲到鼠標的點擊。
      這里,我們在繪制圓形時將真正的范圍填充上顏色,效果會很明顯。

      image

      下面,我們就針對這個鼠標捕獲區域的問題進行優化。

      (四)鼠標捕獲區域優化

      首先,最關鍵的地方就是在鼠標點擊的時候,也就是 MouseDown 事件。

      image

      我們判斷鼠標是否落在圓形內,不能再通過當前的方法。因為這個只能判斷矩形。我們要判斷鼠標是否在圓形內,通過通過 Region 去判斷。
      (下圖來自MSDN)
      image

      首先,我們添加一條和圓形同尺寸的圓形路徑,然后基于此路徑創建 Region ,接著判斷鼠標是否在此 Region 內。
      具體的代碼如下:

      image

      (五)優化后效果演示

      我們再次編譯運行程序,會發現只能我們的鼠標點擊在圓形內,才能正常拖動圓形。
      為了更明顯的演示,我們為非圓形區域填充上顏色,再次操作如下:

      image


      五、示例3:可以用鼠標拖動的圓形,但背景圖不受影響

      上面的示例看下來,似乎已經沒有問題了。但是在實際應用過程中,卻有一個不可忽視的元素:背景圖(此處的背景圖是廣義上的背景圖,可指圖片、其它GDI+ 圖形等等,但原理都是一樣的)。

      因為前面的示例背景都是純色,所以我們看不出來,現在我們為 panel1 加上背景圖,再次運行程序,我們看下效果:

      image

      可以看到,拖動過的地方背景直接被擦了。這還是優化后的代碼,如果是最開始的“先清除背景再繪制圖形”,則在第一次拖動的時候,整個背景圖就都沒了。

      本節,我們就來看一下:如何在用鼠標拖動圓形時,背景圖還正常顯示不受影響。

      (一)設計器界面

      設計器界面同上,不作變化。

      (二)代碼實現

      1,生成背景圖

      首先,我們寫一個方法,生成一張背景圖,當然也可以使用現成的圖片。
      然后將這張背景圖保存為全局變量,以供后續使用。

      image

      2,修改繪制圓形方法

      既然背景圖受到影響,我們想到的最直接方法便是在每次繪制圓形時,都重新將背景圖繪制一遍。
      不過將整個背景圖完整的重繪一遍會太過消耗資源,所以我們可以采取之前的優化思路,就是填充原矩形、繪制背后矩形,不過這里的填充不再是背景色,而是背景圖

      首先,我們需要計算一下原矩形在背景圖中對應的位置和尺寸,然后將這塊背景繪制上去,接著再繪制新的矩形。
      我們使用這個重載方法進行背景圖的繪制:
      (下圖來自MSDN)
      image

      具體的代碼如下:

      image

      (三)效果演示

      編譯運行,可以發現背景確實不受影響了。

      image

      不過上節中出現的在繪制圓形閃爍的問題也更嚴重了。
      那么下面,我們就從根本上來解決一下閃爍的問題。


      六、使用“局部刷新”技術對【示例3】進行優化

      在前面的示例中,使用同樣的優化方式,在繪制矩形時不閃爍,而在繪制圓形時卻會閃爍,雖說是因為繪制圓形更耗性能,但也說明了前面的優化還遠遠不足。
      而問題的根源,就在于刷新的面積太大了。所以我們的優化方向,就在于怎么將這個“刷新面積”減小,也就是所謂的“局部刷新”技術。

      下面,我們就以【示例3】為例來演示下如何使用“局部刷新”技術。

      (一)“剪輯區域”

      與“局部刷新”所對應的,就是“剪輯區域”,顧名思義,就是專門剪輯出來用來重繪的區域。

      在計算“剪輯區域”時,為了方便計算和演示,我們直接將拖動時剛好包含“原矩形”和“新矩形”的矩形區域當成“剪輯區域”。

      image

      (二)修改繪制圓形方法

      在繪制圓形時,我們首先要計算剪輯區域,然后獲取剪輯區域所對應的背景圖,接著設置剪輯區域,并繪制新矩形。

      image

      (三)效果演示

      編譯運行程序,可以看到在拖動圓形時,不會再出現閃爍的問題,同時各種資源的占用也很低。

      image


      七、“局部刷新”技術在實際場景中的應用

      在實際應用場景中,并不是簡單的一個背景一個圖形。在需要用到 GDI+ 交互的場景,往往都會在同一個區域內有好多個不同的 GDI+ 圖形。

      這種場景的基本繪制流程一般如下:
      1,將諸多 GDI+ 圖形保存到一個集合內,一般是以類的形式,類里面包含圖形類型、繪制此圖形所需要的參數、附加參數等。
      2,在繪制時,將背景圖(如果有的話)和圖形集合繪制到一個臨時Bitmap 上,然后將此臨時Bitmap 繪制到窗口上。
      3,釋放臨時Bitmap等資源。

      在這種流程下,如果按照“局部刷新”的方式,就不免會出現閃爍、CPU內存占用高等問題。

      所以,這種時候就必然要用到“局部刷新”技術。我們不用再將全部的圖形集合和背景圖繪制到一張臨時Bitmap上,而是先計算剪輯區域,然后判斷圖形集合內有哪些圖形在剪輯區域內,之后僅重新繪制這些圖形即可。


      八、源代碼下載

      本文演示的程序源代碼如下:

      https://files.cnblogs.com/files/lesliexin/GdiInteractive.7z


      九、總結

      在這個新技術層出不窮的時代,GDI+ 已經被冠上諸如“上個時代的技術、落后的技術、性能很差的技術”等等名詞。

      但是 GDI+ 的效率并不低下,只是很少有能夠發揮出 GDI+ 的正常性能,更別說觸摸到 GDI+ 的極限了。
      當然,本人的水平也有限,只能說勉強夠用而已。

      新技術,給了我們更多的選擇,不過技術是沒有先進落后之分的,只有合適與不合適之別。

      所以請對自己掌握的技術多一些信心,多一些耐心。
      在此,作者與諸君共勉!

      本人水平有限,文章難免有所疏漏,歡迎大家評論指正。


      -【END】-

      posted @ 2022-08-08 10:42  leslie_xin  閱讀(7191)  評論(12)    收藏  舉報
      主站蜘蛛池模板: 2021亚洲爆乳无码专区| 亚洲国内精品一区二区| 亚洲一区二区三区在线激情 | 宝贝腿开大点我添添公视频免| 国产午夜无码视频在线观看| 东海县| 亚洲第一视频区| 国产午夜精品一区理论片| 在线日韩日本国产亚洲| 成人国产精品免费网站| 大姚县| 少妇被粗大的猛烈进出动视频 | 久久99精品久久久久久青青| 四虎国产精品永久地址99| 91久久久久无码精品露脸| 亚洲一区成人av在线| 志丹县| 婷婷色综合成人成人网小说| 国产午夜精品亚洲精品国产| 亚洲天堂av日韩精品| 又湿又紧又大又爽A视频男| 亚洲精品乱码久久久久久| 国产精品最新免费视频| 18禁无遮挡啪啪无码网站破解版| 亚洲精品综合一区二区三区| 国产午夜A理论毛片| 日韩av无码中文无码电影| 国产成人无码久久久精品一| 一二三四日本高清社区5| 成人午夜在线观看刺激| 久久精品国产亚洲精品2020| 曲周县| 成人精品视频一区二区三区| 成 人色 网 站 欧美大片| 久久午夜无码免费| 色欲AV无码一区二区人妻| 国产99re热这里只有精品| 成人一区二区不卡国产| 麻豆精品一区二区视频在线| 一本大道卡一卡二卡三乱码全集资源| 亚洲天堂成人黄色在线播放|