C#實現(xiàn)屬于自己的QQ截圖工具
下面就具體介紹下實現(xiàn)截圖工具的實現(xiàn)思路。
為了讓大家更清楚地知道如何去實現(xiàn)自己的截圖工具,首先我來描述下截圖的一個過程——我們使用QQ的截圖工具和Windows 自帶的截圖工具都可以發(fā)現(xiàn),當我們點擊QQ窗體中的截圖按鈕時,此時我們將看到一個全屏圖片,然后我們可以在其上截圖,當鼠標左鍵按下時,即代表開始截圖,并我們可以移動鼠標來改變截圖的大小,鼠標彈起時即代表結(jié)束截圖,此時我們可以雙擊矩形區(qū)域完全截圖,并且可以通過粘貼操作把截取的圖片粘貼到聊天窗口的發(fā)送區(qū),鼠標右鍵點擊則是退出截圖。這樣我們截圖的過程描述就是這樣的,從這個描述中我們就可以抽象出實現(xiàn)我們截圖工具的思路來:
從 “此時我們將看到一個全屏圖片”這句話描述我們應(yīng)該抽象為——對于QQ截圖工具的實現(xiàn)來說,我們看到的這個全屏圖片其實并不是一張“圖片”(這里最好不要鉆空子),而是一個窗體,這個窗體我們命名為 “截圖窗體”,只是把窗體的背景圖片設(shè)置為全屏圖片。說到這里,一些沒有研究過QQ截圖工具的人開始有疑問了——我們看到的是窗體?那為什么邊框的,即沒有最大化按鈕,最下化按鈕的呢?(對于這點的解釋就是,程序中可以設(shè)置Form的BorderStyle屬性為none的方式來隱藏掉邊框)。
既然要設(shè)置窗體的背景圖片為全屏圖片,我們知道設(shè)置背景圖片只需要設(shè)置窗體的BackgroundImage屬性就好了,但是全屏圖片怎么獲取呢?既然是全屏圖片,自然我就應(yīng)該使窗體最大化話了,不然我們看到只是一個沒有邊框的“小圖片”了,而不是一個全屏的圖片。下面是具體實現(xiàn)這個分析的代碼:
// 通過Graphics的CopyFromScreen方法把全屏圖片的拷貝到我們定義好的一個和屏幕大小相同的空白圖片中, // 拷貝完成之后,CatchBmp就是全屏圖片的拷貝了,然后指定為截圖窗體背景圖片就好了。 // 新建一個和屏幕大小相同的圖片 Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height); // 創(chuàng)建一個畫板,讓我們可以在畫板上畫圖 // 這個畫板也就是和屏幕大小一樣大的圖片 // 我們可以通過Graphics這個類在這個空白圖片上畫圖 Graphics g = Graphics.FromImage(CatchBmp); // 把屏幕圖片拷貝到我們創(chuàng)建的空白圖片 CatchBmp中 g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height)); // 創(chuàng)建截圖窗體 cutter = new Cutter(); // 指示窗體的背景圖片為屏幕圖片 cutter.BackgroundImage = CatchBmp;
3. 從 “然后我們可以在其上截圖”這句話中我們抽象為——其實我們截圖操作,從程序角度來說就是我們在這個最大化的窗體中畫圖,可能這個對一些不了解GDI+畫圖的朋友有些難理解,這里做個比喻——我們會拿筆在紙上畫圖,我們可以用比畫三角形,矩形已經(jīng)各種圖形,此時紙就是我們一個畫板,筆是用來畫圖圖形的,同時筆也是有顏色和粗細的,我們可以用紅色水筆畫,畫出來的圖就是紅色的了,也可以用黑色水筆畫,自然畫出來的就是黑色的了,同樣,在GDI+也就是Graphics Device Interface Plus也就是圖形設(shè)備接口,在.NET 中也提供了一些這樣的類來讓我們實現(xiàn)對圖像的訪問,也就是我們可以使用.NET中提供的類來進行 “畫畫”,要畫畫當然必須要有畫板吧(我們開始比喻中紙就是畫板),在.NET 類中Graphics類就是對畫板的抽象,畫板可以由三種方式創(chuàng)建:(1)從圖片或繼承自圖像對象中創(chuàng)建;(2)從窗體或控件的Paint事件中創(chuàng)建;(3)利用窗體或控件的CreateGraphics方法創(chuàng)建。有了畫板之后,當然就需要筆來畫畫了,在.NET 中Pen類就是起到筆的作用,在構(gòu)造函數(shù)中可以指定筆的顏色和粗細,有了筆之后就是開始畫圖了,在.NET中也同樣提供了一些方法來完成畫圖,如DrawRectangle方法——畫矩形
4. 從 “當鼠標左鍵按下時,即代表開始截圖,并我們可以移動鼠標來改變截圖的大小,鼠標彈起時即代表結(jié)束截圖,此時我們可以雙擊矩形區(qū)域完全截圖,并且可以通過粘貼操作把截取的圖片粘貼到聊天窗口的發(fā)送區(qū),鼠標右鍵點擊則是退出截圖”這些描述中可以抽象為——鼠標的移動,按下,彈起等操作,在程序角度來說,也就是實現(xiàn)截圖窗體的MouseMove事件(對應(yīng)于鼠標移動),MouseDown事件(對應(yīng)于鼠標左鍵按下),MouseClick事件(對應(yīng)于鼠標右鍵結(jié)束截圖)、MouseUp(對應(yīng)于鼠標彈起結(jié)束截圖)和MouseDoubleClick(鼠標雙擊矩形區(qū)域完全截圖,并可以通過粘貼操作把截取的圖片粘貼到聊天窗口的發(fā)送區(qū),既然可以進行粘貼操作來獲得截取圖片,所以必須在該事件中對剪切板設(shè)置截圖圖片),3和4的分析過程也是截圖功能的核心實現(xiàn),對應(yīng)于下面的代碼(代碼中有詳細解釋,并且大家理解的時候可以結(jié)合3和4的分析):
/// <summary>
/// 鼠標右鍵點擊結(jié)束截圖
/// </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)
{
// 如果捕捉?jīng)]有開始
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();
// 從當前窗體創(chuàng)建新的畫板
Graphics g1 = this.CreateGraphics();
// 將剛才所畫的圖片畫到截圖窗體上
// 為什么不直接在當前窗體畫圖呢?
// 如果自己解決將矩形畫在窗體上,會造成圖片抖動并且有無數(shù)個矩形
// 這樣實現(xiàn)也屬于二次緩沖技術(shù)
g1.DrawImage(copyBmp, new Point(0, 0));
g1.Dispose();
// 釋放拷貝圖片,防止內(nèi)存被大量消耗
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)
{
// 如果截圖已經(jīng)開始,鼠標左鍵彈起設(shè)置截圖完成
if (CatchStart)
{
CatchStart = false;
CatchFinished = true;
}
}
}
/// <summary>
/// 鼠標雙擊事件,如果鼠標位于矩形內(nèi),則將矩形內(nèi)的圖片保存到剪切板中
/// </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中指定部分
// 第二個參數(shù)指定繪制到空白圖片的位置和大小
// 畫完后CatchedBmp不再是空白圖片了,而是具有與截取的圖片一樣的內(nèi)容
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點為止,截圖的功能已經(jīng)分析完了,之后就是當我們使用QQ截圖的時候,我們除了可以點擊聊天窗口中的截圖按鈕來進行截圖外,還可以通過按下Alt+Ctrl+A來進行截圖,要實現(xiàn)這個功能的思路也很簡單——即當聊天窗體加載的時候?qū)徭I(程序中我定義的熱鍵是“Alt+Ctrl+C”)進行注冊(此時調(diào)用了Win32中RegisterHotKey方法來完成熱鍵的注冊),當聊天窗體關(guān)閉時進行對熱鍵的卸載,防止對熱鍵進行多次注冊,此時調(diào)用Win32中的UnregisterHotKey方法來完成,具體的實現(xiàn)代碼為:
/// <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>
/// 窗體關(guān)閉時處理程序
/// 窗體關(guān)閉時取消熱鍵注冊
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void 聊天窗體_FormClosing(object sender, FormClosingEventArgs e)
{
// 卸載熱鍵
HotKey.UnregisterHotKey(Handle, 100);
}
#endregion
// 熱鍵按下執(zhí)行的方法
private void GlobalKeyProcess()
{
this.WindowState = FormWindowState.Minimized;
// 窗口最小化也需要一定時間
Thread.Sleep(200);
btnCutter.PerformClick();
}
/// <summary>
/// 重寫WndProc()方法,通過監(jiān)視系統(tǒng)消息,來調(diào)用過程
/// 監(jiān)視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;
}
// 將系統(tǒng)消息傳遞自父類的WndProc
base.WndProc(ref m);
}
實現(xiàn)效果
上面已經(jīng)介紹了實現(xiàn)QQ截圖的一個思路的,朋友們是不是迫不及待想看看該程序的一個效果了?下面就通過一個動畫來讓大家更形象地看到程序的運行效果的:
QQ截圖工具下載:下載地址
總結(jié)
到這里QQ截圖的介紹部分就到這里了,本工具的實現(xiàn)自認為講解的非常通俗易懂的,希望大家可以這樣覺得并且可以更清晰地明白QQ截圖的實現(xiàn)思路。
上一篇:C# 面向?qū)ο笕筇匦裕悍庋b、繼承、多態(tài)
欄 目:C#教程
下一篇:C#利用時間和隨即字符串創(chuàng)建唯一的訂單編號
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6604.html
您可能感興趣的文章
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新聞效果的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已安裝軟件變化的方法
- 01-10C#實現(xiàn)多線程下載文件的方法
- 01-10C#實現(xiàn)Winform中打開網(wǎng)頁頁面的方法
- 01-10C#實現(xiàn)遠程關(guān)閉計算機或重啟計算機的方法
- 01-10C#自定義簽名章實現(xiàn)方法
- 01-10C#文件斷點續(xù)傳實現(xiàn)方法
- 01-10winform實現(xiàn)創(chuàng)建最前端窗體的方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已
隨機閱讀
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10C#中split用法實例總結(jié)


