C#软件开发实例.私人订制自己的屏幕截图工具(四)基本截图功能实现

时间:2021-02-20 15:24:57

本实例全部文章目录

(一)功能概览

(二)创建项目、注册热键、显示截图主窗口

(三)托盘图标及菜单的实现

(四)基本截图功能实现

(五)针对拖拽时闪烁卡顿现象的优化

(六)添加配置管理功能

(七)添加放大镜的功能

(八)添加键盘操作截图的功能

(九)使用自定义光标,QQ截图时的光标

(十)在截图中包含鼠标指针形状


实现原理

基本截图的功能主要靠响应主窗体的鼠标按下、鼠标移动、鼠标抬起几个事件的功能来实现的。截取的图片区域使用“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”事件的处理程序,绑定方法参考下图:

C#软件开发实例.私人订制自己的屏幕截图工具(四)基本截图功能实现

到此,基本截图的功能实现已经实现,赶快去截取一张图片,粘贴到QQ的聊天窗口看看吧。
源码下载:http://download.csdn.net/detail/testcs_dn/7261365