前言

通过创建客制化组件(继承pictureBox),新增属性和构造方法,实现屏幕截图时需要用到的功能点。再通过监控鼠标按下、移动和释放,来获取起始点区域。最后通过操作BMP图像,实现截图的新增、修改和保存功能。

核心点

  • 组件的创建(重写)
  • 鼠标监控事件
  • BMP图像重绘

核心代码

     /// <summary>
/// 重写图片控件
/// </summary>
[Serializable]
public partial class HexPictureBox : PictureBox
{
#region 属性和构造函数 public HexPictureBox()
{
InitializeComponent();
} private bool startDraw = false; public bool StartDraw
{
get { return startDraw; } set { startDraw = value; }
} private List<HLine> lineHistory = new List<HLine>(); public List<HLine> LineHistory
{
get { return lineHistory; } private set { lineHistory = value; }
} private HLine curLine = new HLine() { LineColor = Color.White, LineWidth = , PointList = new List<Point>() }; /// <summary>
/// 当前绘制线
/// </summary>
public HLine CurLine
{
get { return curLine; } private set { curLine = value; }
} private HRectangle curRect = new HRectangle() { LineColor = Color.White, LineWidth = , Start = new Point(, ), End = new Point(, ) }; /// <summary>
/// 当前需要绘制的矩形
/// </summary>
public HRectangle CurRect
{
get { return curRect; } set { curRect = value; }
} private List<HRectangle> rectHistory = new List<HRectangle>(); public List<HRectangle> RectHistory
{
get { return rectHistory; } private set { rectHistory = value; }
} private DrawType drawTypes = DrawType.None; public DrawType DrawTypes
{
get { return drawTypes; } set { drawTypes = value; }
} #endregion #region 绘制功能 protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Graphics g = pe.Graphics;
DrawHistory(g);
//绘制当前线
if (startDraw && this.curLine.PointList != null && this.curLine.PointList.Count > )
{
DrawLine(g, this.curLine);
}
if (startDraw && this.curRect.Start != null && this.curRect.End != null && this.curRect.Start != this.curRect.End)
{
DrawRectangle(g, this.curRect);
}
} public void DrawHistory(Graphics g)
{
//绘制线历史记录
if (LineHistory != null)
{
foreach (HLine lh in LineHistory)
{
if (lh.PointList.Count > )
{
DrawLine(g, lh);
}
}
}
//绘制矩形历史记录
if (RectHistory != null)
{
foreach (HRectangle lh in RectHistory)
{
if (lh.Start != null && lh.End != null && lh.Start != lh.End)
{
DrawRectangle(g, lh);
}
}
}
} /// <summary>
/// 绘制线
/// </summary>
/// <param name="g"></param>
/// <param name="line"></param>
private void DrawLine(Graphics g, HLine line)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
using (Pen p = new Pen(line.LineColor, line.LineWidth))
{
//设置起止点线帽
p.StartCap = LineCap.Round;
p.EndCap = LineCap.Round; //设置连续两段的联接样式
p.LineJoin = LineJoin.Round;
g.DrawCurve(p, line.PointList.ToArray()); //画平滑曲线
}
} /// <summary>
/// 绘制矩形
/// </summary>
/// <param name="g"></param>
/// <param name="rect"></param>
private void DrawRectangle(Graphics g, HRectangle rect)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
using (Pen p = new Pen(rect.LineColor, rect.LineWidth))
{
//设置起止点线帽
p.StartCap = LineCap.Round;
p.EndCap = LineCap.Round; //设置连续两段的联接样式
p.LineJoin = LineJoin.Round;
g.DrawRectangle(p, rect.Start.X, rect.Start.Y, rect.End.X - rect.Start.X, rect.End.Y - rect.Start.Y); //画平滑曲线
}
} public void Earser(Point p0)
{
for (int i = lineHistory.Count - ; i >= ; i--)
{
HLine line = lineHistory[i];
bool flag = false;
foreach (Point p1 in line.PointList)
{
double distance = GetDistance(p0, p1);
if (Math.Abs(distance) < )
{
//需要删除
flag = true;
break;
} }
if (flag)
{
lineHistory.RemoveAt(i);
}
}
//擦除矩形
for (int i = rectHistory.Count - ; i >= ; i--)
{
HRectangle rect = rectHistory[i]; if (p0.X > rect.Start.X && p0.X < rect.End.X && p0.Y > rect.Start.Y && p0.Y < rect.End.Y)
{ rectHistory.RemoveAt(i);
}
}
} /// <summary>
/// 获取两点之间的距离
/// </summary>
/// <param name="p0"></param>
/// <param name="p1"></param>
/// <returns></returns>
private double GetDistance(Point p0, Point p1)
{
return Math.Sqrt(Math.Pow((p0.X - p1.X), ) + Math.Pow((p0.Y - p1.Y), ));
} #endregion #region 鼠标事件响应 /// <summary>
/// 鼠标移动时设置点
/// </summary>
/// <param name="p"></param>
public void SetPointAndRefresh(Point p)
{
if (this.drawTypes == DrawType.Line)
{
this.curLine.PointList.Add(p);
}
if (this.drawTypes == DrawType.Rect)
{
this.curRect.End = p;
}
this.Refresh(); } public void OnMouseDown(Point p)
{
if (this.DrawTypes == DrawType.Line)
{
this.CurLine.PointList.Clear();
this.CurLine.PointList.Add(p);
}
if (this.DrawTypes == DrawType.Rect)
{
this.CurRect.Start = p;
}
} public void OnMouseUp(Point p)
{
if (this.DrawTypes == DrawType.Line)
{
//右键起来时,停止绘图,并写入历史记录
Point[] pCopy = this.CurLine.PointList.ToArray();
List<Point> lstPoint = new List<Point>();
lstPoint.AddRange(pCopy);
this.LineHistory.Add(new HLine() { LineColor = this.CurLine.LineColor, LineWidth = this.CurLine.LineWidth, PointList = lstPoint });
this.CurLine.PointList.Clear();
}
if (this.DrawTypes == DrawType.Rect)
{
this.RectHistory.Add(new HRectangle() { LineColor = this.CurRect.LineColor, LineWidth = this.CurRect.LineWidth, Start = this.CurRect.Start, End = this.CurRect.End });
this.CurRect.Start = new Point(, );
this.CurRect.End = new Point(, );
}
if (this.DrawTypes == DrawType.Earser)
{
//如果是橡皮擦功能
this.Earser(p);
this.Refresh();
}
} #endregion #region 初始设置 public void SetPen(Color c)
{
this.DrawTypes = DrawType.Line;
this.CurLine.LineWidth = ;
this.CurLine.LineColor = c;
//通过图片的句柄获取指针
this.Cursor = new Cursor(global::ScreenShot.Properties.Resources.pen.GetHicon());
this.StartDraw = true;
} public void SetLightPen()
{
this.StartDraw = true;
this.CurLine.LineWidth = ;
this.DrawTypes = DrawType.Line;
this.Cursor = new Cursor(global::ScreenShot.Properties.Resources.lightpen.GetHicon());
this.CurLine.LineColor = Color.FromArgb(, Color.Yellow);
} public void SetRectangle()
{
this.StartDraw = true;
this.CurRect.LineWidth = ;
this.DrawTypes = DrawType.Rect;
this.CurRect.LineColor = Color.Red;
this.Cursor = Cursors.Cross;
} public void SetEarser()
{
this.DrawTypes = DrawType.Earser;//橡皮檫
this.Cursor = new Cursor(global::ScreenShot.Properties.Resources.easer1.GetHicon());
} public void SetDefault()
{
this.Cursor = Cursors.Default;
this.StartDraw = false;
} #endregion
}

实现效果

作者:Jeremy.Wu
  出处:https://www.cnblogs.com/jeremywucnblog/

  本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

C# - VS2019通过重写pictureBox实现简单的桌面截图功能的更多相关文章

  1. VC++ 实现简单的桌面截图

    使用了EasyX图像库,使用方法请参考:VC++ 制作一个简易的控制台时钟应用 简单的桌面截图代码: ///////////////////////////////////////////////// ...

  2. CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能

    CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能 效果图 这是红宝书里的例子,在这个例子中,下述功能全部登场,因此这个例子可作为使用Compute Shader的典型 ...

  3. 完成一段简单的Python程序,用于实现一个简单的加减乘除计算器功能

    #!/bin/usr/env python#coding=utf-8'''完成一段简单的Python程序,用于实现一个简单的加减乘除计算器功能'''try: a=int(raw_input(" ...

  4. Selenium + PhantomJS + python 简单实现爬虫的功能

    Selenium 一.简介 selenium是一个用于Web应用自动化程序测试的工具,测试直接运行在浏览器中,就像真正的用户在操作一样 selenium2支持通过驱动真实浏览器(FirfoxDrive ...

  5. iOS开发——使用技术OC篇&简单九宫格锁屏功能的实现与封装

    简单九宫格锁屏功能的实现与封装 首先来看看最后的实现界面. 在这开始看下面的内容之前希望你能先大概思考活着回顾一下如果 你会怎么做,只要知道大概的思路就可以. 由于iphone5指纹解锁的实现是的这个 ...

  6. 简单 TCP/IP 服务功能

    本主题使用每台 Windows 计算机上提供的 Echo 和 Quote of the Day 服务.在所有 Windows 版本中都提供了简单 TCP/IP 服务功能.该功能会提供了以下服务:Cha ...

  7. Python django实现简单的邮件系统发送邮件功能

    Python django实现简单的邮件系统发送邮件功能 本文实例讲述了Python django实现简单的邮件系统发送邮件功能. django邮件系统 Django发送邮件官方中文文档 总结如下: ...

  8. Netty学习笔记(四) 简单的聊天室功能之服务端开发

    前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...

  9. 基于PHP实现一个简单的在线聊天功能(轮询ajax )

    基于PHP实现一个简单的在线聊天功能(轮询ajax ) 一.总结 1.用的轮询ajax 二.基于PHP实现一个简单的在线聊天功能 一直很想试着做一做这个有意思的功能,感觉复杂的不是数据交互和表结构,麻 ...

随机推荐

  1. css多余文本使用....代替

    1. 只显示单行文本,多余文本使用...代替 white-space: nowrap; overflow: hidden; text-overflow: ellipsis; 2. 显示多行文本,多余文 ...

  2. GitLab CI/CD持续集成设置

    GitLab CI/CD持续设置 官方文档地址(https://docs.gitlab.com/ee/ci/README.html) GitLab CI.CD功能非常完善,只需要简单几步,就可以完成项 ...

  3. Centos 7 下安装 Jenkins

    Jenkins介绍 Jenkins是一个开源的支持自动化构建.部署等任务的平台.基本上可以说是持续集成(CI).持续发布(CD)不可或缺的工具. 安装Java环境 CentOS 7 安装 JAVA环境 ...

  4. 平时代码中用不到设计模式?Are you kidding me?

    引子 平时我是个反应非常慢的人.有多慢呢?大概是两年前有次团队内部开会时,我听到同学说平时代码中用不到设计模式,我当时没有回答.两年后我终于反应过来了:“Are you kidding me?我每天都 ...

  5. JS基础语法---预解析

    预解析:就是在解析代码之前   1. 预解析做什么事? 把变量的声明提前了----提前到当前所在的作用域的最上面 函数的声明也会被提前---提前到当前所在的作用域的最上面   举例: function ...

  6. SSM框架中mapper和mapping.xml文件在同一个包下需要的配置

    前言 当我们在开发过程中,由于maven项目本身的限制,我们不能直接把我们的mapper.xml文件和对应mapper.java接口文件放到一起,也就是不能直接放在java包中,如图:  因为mave ...

  7. MySQL基础之常用函数

    数学函数的使用 常用数学函数 函数 作用 函数 作用 ceil() 进一取整 abs() 取绝对值 floor() 舍掉小数部分 power() 幂运算 round() 四舍五入 pi() 圆周率 t ...

  8. ORACLE等待事件:read by other session

    read by other session简介 官方关于read by other session的介绍如下: When information is requested from the datab ...

  9. Php—使用phpMyAdmin报错

    1.Warning in ./libraries/config/FormDisplay.php#661  "continue" targeting switch is equiva ...

  10. 【转载】C++编译过程

    C++编译过程 C++ 编译过程在介绍编译器之前,先简单地说一下 C++ 的编译过程,以便理解编译器的工作.编译(compiling)并不意味着只创建仅仅一个可执行文件.创建一个可执行文件是一个多级过 ...