程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#實現屬於自己的QQ截圖工具

C#實現屬於自己的QQ截圖工具

編輯:關於C語言

下面就具體介紹下實現截圖工具的實現思路。

為了讓大家更清楚地知道如何去實現自己的截圖工具,首先我來描述下截圖的一個過程——我們使用QQ的截圖工具和Windows 自帶的截圖工具都可以發現,當我們點擊QQ窗體中的截圖按鈕時,此時我們將看到一個全屏圖片,然後我們可以在其上截圖,當鼠標左鍵按下時,即代表開始截圖,並我們可以移動鼠標來改變截圖的大小,鼠標彈起時即代表結束截圖,此時我們可以雙擊矩形區域完全截圖,並且可以通過粘貼操作把截取的圖片粘貼到聊天窗口的發送區,鼠標右鍵點擊則是退出截圖。這樣我們截圖的過程描述就是這樣的,從這個描述中我們就可以抽象出實現我們截圖工具的思路來:

從 “此時我們將看到一個全屏圖片”這句話描述我們應該抽象為——對於QQ截圖工具的實現來說,我們看到的這個全屏圖片其實並不是一張“圖片”(這裡最好不要鑽空子),而是一個窗體,這個窗體我們命名為 “截圖窗體”,只是把窗體的背景圖片設置為全屏圖片。說到這裡,一些沒有研究過QQ截圖工具的人開始有疑問了——我們看到的是窗體?那為什麼邊框的,即沒有最大化按鈕,最下化按鈕的呢?(對於這點的解釋就是,程序中可以設置Form的BorderStyle屬性為none的方式來隱藏掉邊框)。
既然要設置窗體的背景圖片為全屏圖片,我們知道設置背景圖片只需要設置窗體的BackgroundImage屬性就好了,但是全屏圖片怎麼獲取呢?既然是全屏圖片,自然我就應該使窗體最大化話了,不然我們看到只是一個沒有邊框的“小圖片”了,而不是一個全屏的圖片。下面是具體實現這個分析的代碼:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 通過Graphics的CopyFromScreen方法把全屏圖片的拷貝到我們定義好的一個和屏幕大小相同的空白圖片中, // 拷貝完成之後,CatchBmp就是全屏圖片的拷貝了,然後指定為截圖窗體背景圖片就好了。 // 新建一個和屏幕大小相同的圖片 Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height); // 創建一個畫板,讓我們可以在畫板上畫圖 // 這個畫板也就是和屏幕大小一樣大的圖片 // 我們可以通過Graphics這個類在這個空白圖片上畫圖 Graphics g = Graphics.FromImage(CatchBmp); // 把屏幕圖片拷貝到我們創建的空白圖片 CatchBmp中 g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height)); // 創建截圖窗體 cutter = new Cutter(); // 指示窗體的背景圖片為屏幕圖片 cutter.BackgroundImage = CatchBmp;

  3. 從 “然後我們可以在其上截圖”這句話中我們抽象為——其實我們截圖操作,從程序角度來說就是我們在這個最大化的窗體中畫圖,可能這個對一些不了解GDI+畫圖的朋友有些難理解,這裡做個比喻——我們會拿筆在紙上畫圖,我們可以用比畫三角形,矩形已經各種圖形,此時紙就是我們一個畫板,筆是用來畫圖圖形的,同時筆也是有顏色和粗細的,我們可以用紅色水筆畫,畫出來的圖就是紅色的了,也可以用黑色水筆畫,自然畫出來的就是黑色的了,同樣,在GDI+也就是Graphics Device Interface Plus也就是圖形設備接口,在.NET 中也提供了一些這樣的類來讓我們實現對圖像的訪問,也就是我們可以使用.NET中提供的類來進行 “畫畫”,要畫畫當然必須要有畫板吧(我們開始比喻中紙就是畫板),在.NET 類中Graphics類就是對畫板的抽象,畫板可以由三種方式創建:(1)從圖片或繼承自圖像對象中創建;(2)從窗體或控件的Paint事件中創建;(3)利用窗體或控件的CreateGraphics方法創建。有了畫板之後,當然就需要筆來畫畫了,在.NET 中Pen類就是起到筆的作用,在構造函數中可以指定筆的顏色和粗細,有了筆之後就是開始畫圖了,在.Net中也同樣提供了一些方法來完成畫圖,如DrawRectangle方法——畫矩形

  4. 從 “當鼠標左鍵按下時,即代表開始截圖,並我們可以移動鼠標來改變截圖的大小,鼠標彈起時即代表結束截圖,此時我們可以雙擊矩形區域完全截圖,並且可以通過粘貼操作把截取的圖片粘貼到聊天窗口的發送區,鼠標右鍵點擊則是退出截圖”這些描述中可以抽象為——鼠標的移動,按下,彈起等操作,在程序角度來說,也就是實現截圖窗體的MouseMove事件(對應於鼠標移動),MouseDown事件(對應於鼠標左鍵按下),MouseClick事件(對應於鼠標右鍵結束截圖)、MouseUp(對應於鼠標彈起結束截圖)和MouseDoubleClick(鼠標雙擊矩形區域完全截圖,並可以通過粘貼操作把截取的圖片粘貼到聊天窗口的發送區,既然可以進行粘貼操作來獲得截取圖片,所以必須在該事件中對剪切板設置截圖圖片),3和4的分析過程也是截圖功能的核心實現,對應於下面的代碼(代碼中有詳細解釋,並且大家理解的時候可以結合3和4的分析):

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 /// <summary> /// 鼠標右鍵點擊結束截圖 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Cutter_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { this.DialogResult = DialogResult.OK; this.Close(); } } /// <summary> /// 鼠標按下事件處理程序 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Cutter_MouseDown(object sender, MouseEventArgs e) { // 鼠標左鍵按下是開始畫圖,也就是截圖 if (e.Button == MouseButtons.Left) { // 如果捕捉沒有開始 if (!CatchStart) { CatchStart = true; // 保存此時鼠標按下坐標 DownPoint = new Point(e.X, e.Y); } } } /// <summary> /// 鼠標移動事件處理程序,即用戶改變截圖大小的處理 /// 這個方法是截圖功能的核心方法,也就是繪制截圖 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Cutter_MouseMove(object sender, MouseEventArgs e) { // 確保截圖開始 if (CatchStart) { // 新建一個圖片對象,讓它與屏幕圖片相同 Bitmap copyBmp = (Bitmap)originBmp.Clone(); // 獲取鼠標按下的坐標 Point newPoint = new Point(DownPoint.X, DownPoint.Y); // 新建畫板和畫筆 Graphics g = Graphics.FromImage(copyBmp); Pen p = new Pen(Color.Red, 1); // 獲取矩形的長寬 int width = Math.Abs(e.X - DownPoint.X); int height = Math.Abs(e.Y-DownPoint.Y); if (e.X < DownPoint.X) { newPoint.X = e.X; } if (e.Y < DownPoint.Y) { newPoint.Y = e.Y; } CatchRectangle = new Rectangle(newPoint, new Size(width,height)); // 將矩形畫在畫板上 g.DrawRectangle(p, CatchRectangle); // 釋放目前的畫板 g.Dispose(); p.Dispose(); // 從當前窗體創建新的畫板 Graphics g1 = this.CreateGraphics(); // 將剛才所畫的圖片畫到截圖窗體上 // 為什麼不直接在當前窗體畫圖呢? // 如果自己解決將矩形畫在窗體上,會造成圖片抖動並且有無數個矩形 // 這樣實現也屬於二次緩沖技術 g1.DrawImage(copyBmp, new Point(0, 0)); g1.Dispose(); // 釋放拷貝圖片,防止內存被大量消耗 copyBmp.Dispose(); } } /// <summary> /// 鼠標左鍵彈起事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Cutter_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { // 如果截圖已經開始,鼠標左鍵彈起設置截圖完成 if (CatchStart) { CatchStart = false; CatchFinished = true; } } } /// <summary> /// 鼠標雙擊事件,如果鼠標位於矩形內,則將矩形內的圖片保存到剪切板中 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Cutter_MouseDoubleClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left && CatchFinished) { // 新建一個與矩形一樣大小的空白圖片 Bitmap CatchedBmp = new Bitmap(CatchRectangle.Width, CatchRectangle.Height); Graphics g = Graphics.FromImage(CatchedBmp); // 把originBmp中指定部分按照指定大小畫到空白圖片上 // CatchRectangle指定originBmp中指定部分 // 第二個參數指定繪制到空白圖片的位置和大小 // 畫完後CatchedBmp不再是空白圖片了,而是具有與截取的圖片一樣的內容 g.DrawImage(originBmp, new Rectangle(0, 0, CatchRectangle.Width, CatchRectangle.Height), CatchRectangle, GraphicsUnit.Pixel); // 將圖片保存到剪切板中 Clipboard.SetImage(CatchedBmp); g.Dispose(); CatchFinished = false; this.BackgroundImage = originBmp; CatchedBmp.Dispose(); this.DialogResult = DialogResult.OK; this.Close(); } }

  5 到第4點為止,截圖的功能已經分析完了,之後就是當我們使用QQ截圖的時候,我們除了可以點擊聊天窗口中的截圖按鈕來進行截圖外,還可以通過按下Alt+Ctrl+A來進行截圖,要實現這個功能的思路也很簡單——即當聊天窗體加載的時候對熱鍵(程序中我定義的熱鍵是“Alt+Ctrl+C”)進行注冊(此時調用了Win32中RegisterHotKey方法來完成熱鍵的注冊),當聊天窗體關閉時進行對熱鍵的卸載,防止對熱鍵進行多次注冊,此時調用Win32中的UnregisterHotKey方法來完成,具體的實現代碼為:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 /// <summary> /// 窗體加載事件處理 /// 在窗體加載時注冊熱鍵 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void 聊天窗體_Load(object sender, EventArgs e) { uint ctrlHotKey = (uint)(KeyModifiers.Alt|KeyModifIErs.Ctrl); // 注冊熱鍵為Alt+Ctrl+C, "100"為唯一標識熱鍵 HotKey.RegisterHotKey(Handle, 100, ctrlHotKey, Keys.C); } /// <summary> /// 窗體關閉時處理程序 /// 窗體關閉時取消熱鍵注冊 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void 聊天窗體_FormClosing(object sender, FormClosingEventArgs e) { // 卸載熱鍵 HotKey.UnregisterHotKey(Handle, 100); } #endregion // 熱鍵按下執行的方法 private void GlobalKeyProcess() { this.WindowState = FormWindowstate.Minimized; // 窗口最小化也需要一定時間 Thread.Sleep(200); btnCutter.PerformClick(); } /// <summary> /// 重寫WndProc()方法,通過監視系統消息,來調用過程 /// 監視Windows消息 /// </summary> /// <param name="m"></param> protected override void WndProc(ref Message m) { //如果m.Msg的值為0x0312那麼表示用戶按下了熱鍵 const int WM_HOTKEY = 0x0312; switch (m.Msg) { case WM_HOTKEY: if (m.WParam.ToString() == "100") { GlobalKeyProcess(); } break; } // 將系統消息傳遞自父類的WndProc base.WndProc(ref m); }

實現效果
上面已經介紹了實現QQ截圖的一個思路的,朋友們是不是迫不及待想看看該程序的一個效果了?下面就通過一個動畫來讓大家更形象地看到程序的運行效果的:

QQ截圖工具下載:http://xiazai.jb51.net/201603/yuanma/QQjIEtutools(jb51.Net).rar

總結
到這裡QQ截圖的介紹部分就到這裡了,本工具的實現自認為講解的非常通俗易懂的,希望大家可以這樣覺得並且可以更清晰地明白QQ截圖的實現思路。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved