1. 程式人生 > >C#軟體開發例項.私人訂製自己的螢幕截圖工具(四)基本截圖功能實現

C#軟體開發例項.私人訂製自己的螢幕截圖工具(四)基本截圖功能實現

本例項全部文章目錄


實現原理

基本截圖的功能主要靠響應主窗體的滑鼠按下、滑鼠移動、滑鼠擡起幾個事件的功能來實現的。擷取的圖片區域使用“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”事件的處理程式,繫結方法參考下圖: