深入c# GDI+簡單繪圖的具體操作步驟(三)
更新時(shí)間:2013年05月20日 15:40:02 作者:
前兩篇已經(jīng)基本向大家介紹了繪圖的基本知識.那么,我就用我們上兩篇所學(xué)的,做幾個(gè)例子.我們先來做一個(gè)簡單的--仿QQ截圖
關(guān)于這個(gè)的例子其實(shí)網(wǎng)上已經(jīng)有這方面的資料了,但是為了文章的完整性,還是覺得有必要講解.
我們先來看一下效果:

(圖(圖1)

( 圖2 )
接下來看看這是如何做到的.
思路:聊天窗體上有一個(gè)截圖按鈕,點(diǎn)擊按鈕后,程序?qū)⒄麄€(gè)屏幕畫在一個(gè)新的全屏窗體上,然后顯示這個(gè)窗體.因?yàn)槭侨恋拇绑w,并且隱藏了菜單欄、工具欄等,所以在我們看來就好像是一個(gè)桌面的截圖,然后在這個(gè)新窗體上畫矩形,最后保存矩形中的內(nèi)容并顯示在原來的聊天窗體中.
步驟:
A.新建一個(gè)窗體.命名為Catch.然后設(shè)置這個(gè)窗體的FormBorderStyle為None,WindowState為Maximized.
B.我們對代碼進(jìn)行編輯:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Client
{
public partial class Catch : Form
{
public Catch()
{
InitializeComponent();
}
用戶變量#region 用戶變量
private Point DownPoint = Point.Empty;//記錄鼠標(biāo)按下坐標(biāo),用來確定繪圖起點(diǎn)
private bool CatchFinished = false;//用來表示是否截圖完成
private bool CatchStart = false;//表示截圖開始
private Bitmap originBmp;//用來保存原始圖像
private Rectangle CatchRect;//用來保存截圖的矩形
#endregion
//窗體初始化操作
private void Catch_Load(object sender, EventArgs e)
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
this.UpdateStyles();
//以上兩句是為了設(shè)置控件樣式為雙緩沖,這可以有效減少圖片閃爍的問題,關(guān)于這個(gè)大家可以自己去搜索下
originBmp = new Bitmap(this.BackgroundImage);//BackgroundImage為全屏圖片,我們另用變量來保存全屏圖片
}
//鼠標(biāo)右鍵點(diǎn)擊結(jié)束截圖
private void Catch_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
}
//鼠標(biāo)左鍵按下時(shí)動作
private void Catch_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!CatchStart)
{//如果捕捉?jīng)]有開始
CatchStart = true;
DownPoint = new Point(e.X, e.Y);//保存鼠標(biāo)按下坐標(biāo)
}
}
}
private void Catch_MouseMove(object sender, MouseEventArgs e)
{
if (CatchStart)
{//如果捕捉開始
Bitmap destBmp = (Bitmap)originBmp.Clone();//新建一個(gè)圖片對象,并讓它與原始圖片相同
Point newPoint = new Point(DownPoint.X, DownPoint.Y);//獲取鼠標(biāo)的坐標(biāo)
Graphics g = Graphics.FromImage(destBmp);//在剛才新建的圖片上新建一個(gè)畫板
Pen p = new Pen(Color.Blue,1);
int width = Math.Abs(e.X - DownPoint.X), 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;
}
CatchRect = new Rectangle(newPoint,new Size(width,height));//保存矩形
g.DrawRectangle(p,CatchRect);//將矩形畫在這個(gè)畫板上
g.Dispose();//釋放目前的這個(gè)畫板
p.Dispose();
Graphics g1 = this.CreateGraphics();//重新新建一個(gè)Graphics類
//如果之前那個(gè)畫板不釋放,而直接g=this.CreateGraphics()這樣的話無法釋放掉第一次創(chuàng)建的g,因?yàn)橹皇前训刂忿D(zhuǎn)到新的g了.如同string一樣
g1 = this.CreateGraphics();//在整個(gè)全屏窗體上新建畫板
g1.DrawImage(destBmp,new Point(0,0));//將剛才所畫的圖片畫到這個(gè)窗體上
//這個(gè)也可以屬于二次緩沖技術(shù),如果直接將矩形畫在窗體上,會造成圖片抖動并且會有無數(shù)個(gè)矩形.
g1.Dispose();
destBmp.Dispose();//要及時(shí)釋放,不然內(nèi)存將會被大量消耗
}
}
private void Catch_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (CatchStart)
{
CatchStart = false;
CatchFinished = true;
}
}
}
//鼠標(biāo)雙擊事件,如果鼠標(biāo)位于矩形內(nèi),則將矩形內(nèi)的圖片保存到剪貼板中
private void Catch_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left&&CatchFinished)
{
if (CatchRect.Contains(new Point(e.X, e.Y)))
{
Bitmap CatchedBmp = new Bitmap(CatchRect.Width, CatchRect.Height);//新建一個(gè)于矩形等大的空白圖片
Graphics g = Graphics.FromImage(CatchedBmp);
g.DrawImage(originBmp, new Rectangle(0, 0, CatchRect.Width, CatchRect.Height), CatchRect, GraphicsUnit.Pixel);
//把orginBmp中的指定部分按照指定大小畫在畫板上
Clipboard.SetImage(CatchedBmp);//將圖片保存到剪貼板
g.Dispose();
CatchFinished = false;
this.BackgroundImage = originBmp;
CatchedBmp.Dispose();
this.DialogResult = DialogResult.OK;
this.Close();
}
}
}
}
}
C.創(chuàng)建了Catch窗體后,我們在截圖按鈕(位于聊天窗體上)上加入以下事件:
private void bCatch_Click(object sender, EventArgs e)
{
if (bCatch_HideCurrent.Checked)
{
this.Hide();//隱藏當(dāng)前窗體
Thread.Sleep(50);//讓線程睡眠一段時(shí)間,窗體消失需要一點(diǎn)時(shí)間
Catch CatchForm = new Catch();
Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);//新建一個(gè)和屏幕大小相同的圖片
Graphics g = Graphics.FromImage(CatchBmp);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));//保存全屏圖片
CatchForm.BackgroundImage = CatchBmp;//將Catch窗體的背景設(shè)為全屏?xí)r的圖片
if (CatchForm.ShowDialog() == DialogResult.OK)
{//如果Catch窗體結(jié)束,就將剪貼板中的圖片放到信息發(fā)送框中
IDataObject iData = Clipboard.GetDataObject();
DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap);
if (iData.GetDataPresent(DataFormats.Bitmap))
{
richtextbox1.Paste(myFormat);
Clipboard.Clear();//清除剪貼板中的對象
}
this.Show();//重新顯示窗體
}
}
}
這樣我們的截圖功能便完成了.
我想對于初學(xué)者來說如何消去第一次繪制的圖片是個(gè)比較困難的問題.如果沒有采取措施,你會發(fā)現(xiàn)只要你鼠標(biāo)移動,就會畫一個(gè)矩形,這樣便會出現(xiàn)N多的矩形,而我們只是要最后的那一個(gè).
一般解決這種問題的方法有兩種:
1.就是在繪制第二個(gè)圖形時(shí),我們先用與底色相同的顏色將上次繪制的圖形重新繪制一下.但這往往需要底色為純色時(shí)使用.
2.我們并不直接將圖形畫在畫板上,我們用一個(gè)圖片A來保存原畫板上的圖片.然后再新建一個(gè)與圖片A相同的圖片B,將我們要繪制的圖形畫在該圖片B上,然后再將該圖片B畫在畫板上.這樣圖片A并沒有被改變.于是第二次畫的時(shí)候我們還是同樣新建一個(gè)與圖片A相同的圖片進(jìn)行繪制.那么上一次的圖形就不會被保留下來.問題也就解決了.
我們先來看一下效果:

(圖(圖1)

( 圖2 )
接下來看看這是如何做到的.
思路:聊天窗體上有一個(gè)截圖按鈕,點(diǎn)擊按鈕后,程序?qū)⒄麄€(gè)屏幕畫在一個(gè)新的全屏窗體上,然后顯示這個(gè)窗體.因?yàn)槭侨恋拇绑w,并且隱藏了菜單欄、工具欄等,所以在我們看來就好像是一個(gè)桌面的截圖,然后在這個(gè)新窗體上畫矩形,最后保存矩形中的內(nèi)容并顯示在原來的聊天窗體中.
步驟:
A.新建一個(gè)窗體.命名為Catch.然后設(shè)置這個(gè)窗體的FormBorderStyle為None,WindowState為Maximized.
B.我們對代碼進(jìn)行編輯:
復(fù)制代碼 代碼如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Client
{
public partial class Catch : Form
{
public Catch()
{
InitializeComponent();
}
用戶變量#region 用戶變量
private Point DownPoint = Point.Empty;//記錄鼠標(biāo)按下坐標(biāo),用來確定繪圖起點(diǎn)
private bool CatchFinished = false;//用來表示是否截圖完成
private bool CatchStart = false;//表示截圖開始
private Bitmap originBmp;//用來保存原始圖像
private Rectangle CatchRect;//用來保存截圖的矩形
#endregion
//窗體初始化操作
private void Catch_Load(object sender, EventArgs e)
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
this.UpdateStyles();
//以上兩句是為了設(shè)置控件樣式為雙緩沖,這可以有效減少圖片閃爍的問題,關(guān)于這個(gè)大家可以自己去搜索下
originBmp = new Bitmap(this.BackgroundImage);//BackgroundImage為全屏圖片,我們另用變量來保存全屏圖片
}
//鼠標(biāo)右鍵點(diǎn)擊結(jié)束截圖
private void Catch_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
}
//鼠標(biāo)左鍵按下時(shí)動作
private void Catch_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!CatchStart)
{//如果捕捉?jīng)]有開始
CatchStart = true;
DownPoint = new Point(e.X, e.Y);//保存鼠標(biāo)按下坐標(biāo)
}
}
}
private void Catch_MouseMove(object sender, MouseEventArgs e)
{
if (CatchStart)
{//如果捕捉開始
Bitmap destBmp = (Bitmap)originBmp.Clone();//新建一個(gè)圖片對象,并讓它與原始圖片相同
Point newPoint = new Point(DownPoint.X, DownPoint.Y);//獲取鼠標(biāo)的坐標(biāo)
Graphics g = Graphics.FromImage(destBmp);//在剛才新建的圖片上新建一個(gè)畫板
Pen p = new Pen(Color.Blue,1);
int width = Math.Abs(e.X - DownPoint.X), 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;
}
CatchRect = new Rectangle(newPoint,new Size(width,height));//保存矩形
g.DrawRectangle(p,CatchRect);//將矩形畫在這個(gè)畫板上
g.Dispose();//釋放目前的這個(gè)畫板
p.Dispose();
Graphics g1 = this.CreateGraphics();//重新新建一個(gè)Graphics類
//如果之前那個(gè)畫板不釋放,而直接g=this.CreateGraphics()這樣的話無法釋放掉第一次創(chuàng)建的g,因?yàn)橹皇前训刂忿D(zhuǎn)到新的g了.如同string一樣
g1 = this.CreateGraphics();//在整個(gè)全屏窗體上新建畫板
g1.DrawImage(destBmp,new Point(0,0));//將剛才所畫的圖片畫到這個(gè)窗體上
//這個(gè)也可以屬于二次緩沖技術(shù),如果直接將矩形畫在窗體上,會造成圖片抖動并且會有無數(shù)個(gè)矩形.
g1.Dispose();
destBmp.Dispose();//要及時(shí)釋放,不然內(nèi)存將會被大量消耗
}
}
private void Catch_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (CatchStart)
{
CatchStart = false;
CatchFinished = true;
}
}
}
//鼠標(biāo)雙擊事件,如果鼠標(biāo)位于矩形內(nèi),則將矩形內(nèi)的圖片保存到剪貼板中
private void Catch_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left&&CatchFinished)
{
if (CatchRect.Contains(new Point(e.X, e.Y)))
{
Bitmap CatchedBmp = new Bitmap(CatchRect.Width, CatchRect.Height);//新建一個(gè)于矩形等大的空白圖片
Graphics g = Graphics.FromImage(CatchedBmp);
g.DrawImage(originBmp, new Rectangle(0, 0, CatchRect.Width, CatchRect.Height), CatchRect, GraphicsUnit.Pixel);
//把orginBmp中的指定部分按照指定大小畫在畫板上
Clipboard.SetImage(CatchedBmp);//將圖片保存到剪貼板
g.Dispose();
CatchFinished = false;
this.BackgroundImage = originBmp;
CatchedBmp.Dispose();
this.DialogResult = DialogResult.OK;
this.Close();
}
}
}
}
}
C.創(chuàng)建了Catch窗體后,我們在截圖按鈕(位于聊天窗體上)上加入以下事件:
復(fù)制代碼 代碼如下:
private void bCatch_Click(object sender, EventArgs e)
{
if (bCatch_HideCurrent.Checked)
{
this.Hide();//隱藏當(dāng)前窗體
Thread.Sleep(50);//讓線程睡眠一段時(shí)間,窗體消失需要一點(diǎn)時(shí)間
Catch CatchForm = new Catch();
Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);//新建一個(gè)和屏幕大小相同的圖片
Graphics g = Graphics.FromImage(CatchBmp);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));//保存全屏圖片
CatchForm.BackgroundImage = CatchBmp;//將Catch窗體的背景設(shè)為全屏?xí)r的圖片
if (CatchForm.ShowDialog() == DialogResult.OK)
{//如果Catch窗體結(jié)束,就將剪貼板中的圖片放到信息發(fā)送框中
IDataObject iData = Clipboard.GetDataObject();
DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap);
if (iData.GetDataPresent(DataFormats.Bitmap))
{
richtextbox1.Paste(myFormat);
Clipboard.Clear();//清除剪貼板中的對象
}
this.Show();//重新顯示窗體
}
}
}
這樣我們的截圖功能便完成了.
我想對于初學(xué)者來說如何消去第一次繪制的圖片是個(gè)比較困難的問題.如果沒有采取措施,你會發(fā)現(xiàn)只要你鼠標(biāo)移動,就會畫一個(gè)矩形,這樣便會出現(xiàn)N多的矩形,而我們只是要最后的那一個(gè).
一般解決這種問題的方法有兩種:
1.就是在繪制第二個(gè)圖形時(shí),我們先用與底色相同的顏色將上次繪制的圖形重新繪制一下.但這往往需要底色為純色時(shí)使用.
2.我們并不直接將圖形畫在畫板上,我們用一個(gè)圖片A來保存原畫板上的圖片.然后再新建一個(gè)與圖片A相同的圖片B,將我們要繪制的圖形畫在該圖片B上,然后再將該圖片B畫在畫板上.這樣圖片A并沒有被改變.于是第二次畫的時(shí)候我們還是同樣新建一個(gè)與圖片A相同的圖片進(jìn)行繪制.那么上一次的圖形就不會被保留下來.問題也就解決了.
您可能感興趣的文章:
- C#利用GDI+給圖片添加文字(文字自適應(yīng)矩形區(qū)域)
- C#利用GDI+畫圖的基礎(chǔ)實(shí)例教程
- C# 使用 GDI+ 實(shí)現(xiàn)添加中心旋轉(zhuǎn)(任意角度)的文字
- C#使用GDI+創(chuàng)建縮略圖實(shí)例
- C#利用GDI+繪制旋轉(zhuǎn)文字等效果實(shí)例
- C#常用GDI+文字操作匯總
- 深入c# GDI+簡單繪圖的具體操作步驟(四)
- 深入c# GDI+簡單繪圖的具體操作步驟(二)
- 深入c# GDI+簡單繪圖的具體操作步驟(一)
- BarCode條形碼基于C# GDI+ 的實(shí)現(xiàn)方法詳解
- C#圖形編程GDI+基礎(chǔ)介紹
相關(guān)文章
使用DateTime的ParseExact方法實(shí)現(xiàn)特殊日期時(shí)間的方法詳解
本篇文章是對使用DateTime的ParseExact方法實(shí)現(xiàn)特殊日期時(shí)間的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C#中如何在Excel工作表創(chuàng)建混合型圖表實(shí)例
本篇文章主要介紹了C#中如何在Excel工作表創(chuàng)建混合型圖表實(shí)例,具有一定的參考價(jià)值,有需要的可以了解一下。2016-11-11
Visual C#類的定義及實(shí)現(xiàn)方法實(shí)例解析
這篇文章主要介紹了Visual C#類的定義及實(shí)現(xiàn)方法實(shí)例解析,對于新手來說有不錯(cuò)的借鑒學(xué)習(xí)價(jià)值,需要的朋友可以參考下2014-07-07
C#?WPF實(shí)現(xiàn)播放音頻文件的示例詳解
這篇文章主要為大家詳細(xì)介紹了利用C#?WPF實(shí)現(xiàn)播放音頻文件的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
C#使用Pipelines實(shí)現(xiàn)處理Socket數(shù)據(jù)包
這篇文章主要為大家詳細(xì)介紹了C#如何使用Pipelines實(shí)現(xiàn)處理Socket數(shù)據(jù)包,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
C#實(shí)現(xiàn)讀取USB轉(zhuǎn)串口參數(shù)并顯示在ComboBox
在很多應(yīng)用程序中,尤其是那些需要與外部硬件通信的程序中,自動檢測和讀取串口參數(shù)是一個(gè)非常有用的功能,下面我們就來看看如何在C#中實(shí)現(xiàn)這一功能吧2024-01-01
C#中結(jié)構(gòu)(struct)的部分初始化和完全初始化實(shí)例分析
這篇文章主要介紹了C#中結(jié)構(gòu)(struct)的部分初始化和完全初始化,通過實(shí)例分析了結(jié)構(gòu)初始化中常見的錯(cuò)誤及技巧,有助于加深對C#結(jié)構(gòu)(struct)的認(rèn)識,需要的朋友可以參考下2014-09-09
WPF+ASP.NET SignalR實(shí)現(xiàn)動態(tài)折線圖的繪制
這篇文章將以一個(gè)簡單的動態(tài)折線圖示例,簡述如何通過ASP.NET SignalR實(shí)現(xiàn)后臺通知功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-01-01

