C#軟體開發例項.私人訂製自己的螢幕截圖工具(四)基本截圖功能實現
阿新 • • 發佈:2019-02-19
本例項全部文章目錄
實現原理
基本截圖的功能主要靠響應主窗體的滑鼠按下、滑鼠移動、滑鼠擡起幾個事件的功能來實現的。擷取的圖片區域使用“Label”元件來顯示,需要重新實現“Label”元件的“Paint”方法。
左鍵單擊開始截圖,右鍵單擊取消截圖,雙擊滑鼠左鍵完成截圖,將擷取的圖片儲存到Windows剪貼簿中。
新增“Label”元件
工具箱》公共元件》雙擊“Label”元件,修改元件屬性:
Name=lbl_CutImage,
AutoSize=False,
BackColor=Transparent,
Text = “”
“Form1_Load”事件新增程式碼:
this.lbl_CutImage.Hide();
定義截圖功能依賴的基本變數
#region 截圖基本變數 /// <summary> /// 用於判斷是否已經開始截圖,控制資訊框是否顯示。 /// </summary> private bool isCuting; /// <summary> /// 滑鼠按下的點 /// </summary> private Point beginPoint; /// <summary> /// 最終確定的繪圖基點 /// </summary> private Point endPoint; /// <summary> /// 用於記錄截圖顯示區域的大小(包括調整塊的區域,調整區域邊框寬度2px) /// </summary> private Rectangle cutImageRect = new Rectangle(0, 0, 5, 5); #endregion
定義列舉型別:更新UI的模式
/// <summary> /// 更新UI的模式,用於標記哪些需要顯示,哪些需要隱藏; /// </summary> [FlagsAttribute] public enum UpdateUIMode : uint { //值得注意的是,如果要使用組合值,那麼就不能用連線的數字表示,必須是幾何級增長! None = 0, ShowTextPro = 1, ShowPenStyle = 2, ShowToolBox = 4, ShowInfoBox = 8, ShowZoomBox = 16, ShowCutImage = 32, HideTextPro = 64, HidePenStyle = 128, HideToolBox = 256, HideInfoBox = 512 }
新增方法:計算並儲存截圖的區域框的大小
/// <summary>
/// 計算並儲存截圖的區域框的大小
/// </summary>
private void SaveCutImageSize(Point beginPoint, Point endPoint)
{
// 儲存最終的繪圖基點,用於擷取選中的區域
this.endPoint = beginPoint;
// 計算擷取圖片的大小
int imgWidth = Math.Abs(endPoint.X - beginPoint.X) + 1;
int imgHeight = Math.Abs(endPoint.Y - beginPoint.Y) + 1;
int lblWidth = imgWidth + 4;
int lblHeight = imgHeight + 4;
// 設定截圖區域的位置和大小
this.cutImageRect = new Rectangle(beginPoint.X - 2, beginPoint.Y - 2, lblWidth, lblHeight);
}
新增方法:執行截圖,將選定區域的圖片儲存到剪貼簿
/// <summary>
/// 執行截圖,將選定區域的圖片儲存到剪貼簿
/// </summary>
/// <param name="saveToDisk">
/// 是否將圖片儲存到磁碟
/// </param>
private void ExecCutImage(bool saveToDisk, bool uploadImage) //bool saveToDisk = false, bool uploadImage = false
{
// 如果圖片獲取區域不可見,則退出儲存圖片過程
if (!this.lbl_CutImage.Visible) { return; }
Rectangle srcRect = new Rectangle();
srcRect.X = this.lbl_CutImage.Location.X + 2;
srcRect.Y = this.lbl_CutImage.Location.Y + 2;
srcRect.Width = this.lbl_CutImage.Width - 4;
srcRect.Height = this.lbl_CutImage.Height - 4;
Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height);
Bitmap bmp = new Bitmap(srcRect.Width, srcRect.Height);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(this.screenImage, destRect, srcRect, GraphicsUnit.Pixel);
Clipboard.SetImage(bmp);
ExitCutImage(true);
}
新增方法:退出截圖過程
/// <summary>
/// 退出截圖過程
/// </summary>
private void ExitCutImage(bool hideWindow) // = true
{
this.lbl_CutImage.Visible = false;
this.isCuting = false;
if (hideWindow)
{
this.screenImage.Dispose();
this.Hide();
}
}
主視窗滑鼠按下事件處理程式
/// <summary>
/// 截圖視窗滑鼠按下事件處理程式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
// 左鍵單擊事件
if (e.Button == MouseButtons.Left && e.Clicks == 1)
{
if (!this.lbl_CutImage.Visible)
{
this.isCuting = true;
this.beginPoint = e.Location;
this.endPoint = e.Location;
SaveCutImageSize(e.Location, e.Location);
UpdateCutInfoLabel(UpdateUIMode.ShowCutImage | UpdateUIMode.ShowInfoBox);
}
}
// 左鍵雙擊事件
if (e.Button == MouseButtons.Left && e.Clicks == 2)
{
if (this.lbl_CutImage.Visible)
{
ExecCutImage(false, false);
}
}
// 右鍵單擊事件
if (e.Button == MouseButtons.Right)
{
ExitCutImage(!this.lbl_CutImage.Visible);
}
}
主視窗滑鼠移動事件處理程式
/// <summary>
/// 截圖視窗滑鼠移動事件處理程式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
// 如果擷取區域不可見,則退出處理過程
if (!this.lbl_CutImage.Visible)
{
UpdateCutInfoLabel(UpdateUIMode.None);
return;
}
Point pntBgn = this.beginPoint;
Point pntEnd = e.Location;
// 如果是反向拖動,重新設定起始點
if (e.Location.X < this.beginPoint.X && e.Location.Y < this.beginPoint.Y)
{
pntBgn = e.Location;
pntEnd = this.beginPoint;
}
else
{
if (e.Location.X < this.beginPoint.X)
{
pntBgn = new Point(e.Location.X, this.beginPoint.Y);
pntEnd = new Point(this.beginPoint.X, e.Location.Y);
}
else
{
if (e.Location.Y < this.beginPoint.Y)
{
pntBgn = new Point(this.beginPoint.X, e.Location.Y);
pntEnd = new Point(e.Location.X, this.beginPoint.Y);
}
}
}
if (this.isCuting)
{
SaveCutImageSize(pntBgn, pntEnd);
}
UpdateCutInfoLabel(UpdateUIMode.None);
}
主視窗滑鼠擡起事件處理程式
/// <summary>
/// 截圖視窗滑鼠擡起事件處理程式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (this.isCuting)
{
this.isCuting = false;
UpdateCutInfoLabel(UpdateUIMode.None);
}
}
}
擷取區域圖片繪製
/// <summary>
/// 擷取區域圖片的繪製事件處理程式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lbl_CutImage_Paint(object sender, PaintEventArgs e)
{
int imgWidth = this.lbl_CutImage.Width - 4;
int imgHeight = this.lbl_CutImage.Height - 4;
if (imgWidth < 1) { imgWidth = 1; }
if (imgHeight < 1) { imgHeight = 1; }
// 建立快取影象,先將要繪製的內容全部繪製到快取中,最後再一次性繪製到 Label 上,
// 這樣可以提高效能,並且可以防止螢幕閃爍的問題
Bitmap bmp_lbl = new Bitmap(this.lbl_CutImage.Width, this.lbl_CutImage.Height);
Graphics g = Graphics.FromImage(bmp_lbl);
// 將要擷取的部分繪製到快取
Rectangle destRect = new Rectangle(2, 2, imgWidth, imgHeight);
Point srcPoint = this.lbl_CutImage.Location;
srcPoint.Offset(2, 2);
Rectangle srcRect = new Rectangle(srcPoint, new System.Drawing.Size(imgWidth, imgHeight));
g.DrawImage(this.screenImage, destRect, srcRect, GraphicsUnit.Pixel);
SolidBrush brush = new SolidBrush(Color.FromArgb(10, 124, 202));
Pen pen = new Pen(brush, 1.0F);
//以下部分(邊框和調整塊)的繪製放在(編輯內容)的後面,是解決繪製編輯內容會覆蓋(邊框和調整塊)的問題
// 繪製邊框外的區域,解決會被編輯內容覆蓋的問題
// 上邊
destRect = new Rectangle(0, 0, this.lbl_CutImage.Width, 2);
srcPoint = this.lbl_CutImage.Location;
//srcPoint.Offset(2, 2);
srcRect = new Rectangle(srcPoint, new System.Drawing.Size(this.lbl_CutImage.Width, 2));
g.DrawImage(this.BackgroundImage, destRect, srcRect, GraphicsUnit.Pixel);
// 下邊
destRect = new Rectangle(0, this.lbl_CutImage.Height - 2, this.lbl_CutImage.Width, 2);
srcPoint = this.lbl_CutImage.Location;
srcPoint.Offset(0, this.lbl_CutImage.Height - 2);
srcRect = new Rectangle(srcPoint, new System.Drawing.Size(this.lbl_CutImage.Width, 2));
g.DrawImage(this.BackgroundImage, destRect, srcRect, GraphicsUnit.Pixel);
// 左邊
destRect = new Rectangle(0, 2, 2, this.lbl_CutImage.Height - 4);
srcPoint = this.lbl_CutImage.Location;
srcPoint.Offset(0, 2);
srcRect = new Rectangle(srcPoint, new System.Drawing.Size(2, this.lbl_CutImage.Height - 4));
g.DrawImage(this.BackgroundImage, destRect, srcRect, GraphicsUnit.Pixel);
// 右邊
destRect = new Rectangle(this.lbl_CutImage.Width - 2, 2, 2, this.lbl_CutImage.Height - 4);
srcPoint = this.lbl_CutImage.Location;
srcPoint.Offset(this.lbl_CutImage.Width - 2, 2);
srcRect = new Rectangle(srcPoint, new System.Drawing.Size(2, this.lbl_CutImage.Height - 4));
g.DrawImage(this.BackgroundImage, destRect, srcRect, GraphicsUnit.Pixel);
// 繪製邊框
g.DrawLine(pen, 2, 2, this.lbl_CutImage.Width - 3, 2);
g.DrawLine(pen, 2, 2, 2, this.lbl_CutImage.Height - 3);
g.DrawLine(pen, this.lbl_CutImage.Width - 3, 2, this.lbl_CutImage.Width - 3, this.lbl_CutImage.Height - 3);
g.DrawLine(pen, 2, this.lbl_CutImage.Height - 3, this.lbl_CutImage.Width - 3, this.lbl_CutImage.Height - 3);
// 繪製四個角的調整塊
g.FillRectangle(brush, 0, 0, 4, 5);
g.FillRectangle(brush, this.lbl_CutImage.Width - 4, 0, 4, 5);
g.FillRectangle(brush, 0, this.lbl_CutImage.Height - 5, 4, 5);
g.FillRectangle(brush, this.lbl_CutImage.Width - 4, this.lbl_CutImage.Height - 5, 4, 5);
// 繪製中間的四個調整塊
int blockX = this.lbl_CutImage.Width / 2 - 2;
int blockY = this.lbl_CutImage.Height / 2 - 2;
g.FillRectangle(brush, blockX, 0, 4, 5);
g.FillRectangle(brush, 0, blockY, 4, 5);
g.FillRectangle(brush, blockX, this.lbl_CutImage.Height - 5, 4, 5);
g.FillRectangle(brush, this.lbl_CutImage.Width - 4, blockY, 4, 5);
// 繪製到 Label 上
e.Graphics.DrawImage(bmp_lbl, 0, 0);
bmp_lbl.Dispose();
}
雙擊滑鼠左鍵完成截圖功能
/// <summary>
/// 擷取區域圖片的滑鼠按下事件處理程式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lbl_CutImage_MouseDown(object sender, MouseEventArgs e)
{
// 左鍵雙擊事件
if (e.Button == MouseButtons.Left && e.Clicks == 2)
{
if (this.lbl_CutImage.Visible)
{
ExecCutImage(false, false);
}
}
}
注意:程式碼都貼完了,別忘了為窗體或元件繫結事件處理程式;
例如:擷取區域圖片的滑鼠按下事件處理程式“lbl_CutImage_MouseDown”,就是“lbl_CutImage”元件的“MouseDown”事件的處理程式,繫結方法參考下圖: