實現原理
基本的功能主要靠響應主表單的滑鼠按下、滑鼠移動、滑鼠抬起幾個事件的功能來實現的。截取的圖片地區使用“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”事件的處理常式,Binder 方法參考:
到此,基本的功能實現已經實現,趕快去截取一張圖片,粘貼到QQ的聊天視窗看看吧。