C#实现截图工具小项目

作者:*八步赶蝉* 时间:2023-10-02 08:20:03 

本文实例为大家分享了C#实现截图工具小项目的具体代码,供大家参考,具体内容如下

1.起因

一直用的截图是qq的截图,所以想要实现一个简单点的截图,为了方便。

2.思路

讲一下实现流程。

1、主窗体,上有截图按钮,点击进入截图窗体
2、在截图窗体中,背景设置为全屏幕的截图图片,无边框,窗体最大化,这时你看到的就是一张屏幕图,其实是一个窗体,然后我们将在这个窗体中截取图片,其实主要就是画板Graphics的使用,截取完之后图片将保存到剪切板。

3.代码

热键注册类   HotKey.cs


using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace test {
   /// <summary>
   /// 热键类
   /// </summary>
   public class HotKey {
       /// <summary>
       /// 如果函数执行成功,返回值不为0,如果执行失败,返回值为0
       /// </summary>
       /// <returns></returns>
       [DllImport("user32.dll", SetLastError = true)]
       public static extern bool RegisterHotKey(
           IntPtr hWnd,           // 窗口的句柄, 当热键按下时,会产生WM_HOTKEY信息,该信息该会发送该窗口句柄
           int id,                      // 定义热键ID,属于唯一标识热键的作用
           uint fsModifiers,            // 热键只有在按下Alt、 Ctrl、Shift、Windows等键时才会生效,即才会产生WM_HOTKEY信息
           Keys vk                   // 虚拟键,即按了Alt+Ctrl+ X ,X就是代表虚拟键
           );

[DllImport("user32.dll", SetLastError = true)]
       public static extern bool UnregisterHotKey(
           IntPtr hWnd,                   // 窗口句柄
           int id                         // 要取消热键的ID
           );
   }
}

主窗体  Form1.cs


using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Timers;
using System.Windows.Forms;

namespace test {
   public partial class Form1 : Form {

[Flags]
       public enum KeyModifiers { //定义热键值字符串(热键值是系统规定的,不能改变)
           None = 0,
           Alt = 1,
           Ctrl = 2,
           Shift = 4,
           WindowsKey = 8
       }

public Form1() {
           InitializeComponent();
       }

//窗体加载时-注册快捷键
       private void Form1_Load(object sender, EventArgs e) {
           uint ctrlHotKey = (uint)(KeyModifiers.Alt | KeyModifiers.Ctrl);
           // 注册热键为Alt+Ctrl+A, "100"为唯一标识热键
           HotKey.RegisterHotKey(Handle,100,ctrlHotKey,Keys.A);
       }

//截图按钮
       private void button1_Click(object sender, EventArgs e) {
           if (this.WindowState != FormWindowState.Minimized) {
               this.WindowState = FormWindowState.Minimized;
               Thread.Sleep(200);
           }
           int swidth = Screen.PrimaryScreen.Bounds.Width;
           int sheight = Screen.PrimaryScreen.Bounds.Height;
           Bitmap btm = new Bitmap(swidth,sheight); //空图与屏幕同大小
           Graphics g = Graphics.FromImage(btm); //空图的画板
           g.CopyFromScreen(new Point(0,0),new Point(0,0),new Size(swidth,sheight)); //将屏幕内容复制到空图
           Cutter cutter = new Cutter(btm); //传送截图
           cutter.FormBorderStyle = FormBorderStyle.None; //截图全屏,无边框
           cutter.BackgroundImage = btm; //新的窗体截图做背景
           cutter.Show();
       }
       private void tiaoZ(object sender, ElapsedEventArgs e) {
       }

//窗体关闭-取消热键
       private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
           HotKey.UnregisterHotKey(Handle,100);
       }

//快捷键按下执行的事件
       private void GlobalKeyProcess() {
           this.WindowState = FormWindowState.Minimized;
           Thread.Sleep(200);
           button1.PerformClick();
       }

//重写。监视系统消息,调用对应方法
       protected override void WndProc(ref Message m) {
           const int WM_HOTKEY = 0x0312;
           //如果m.Msg的值为0x0312(我也不知道为什么是0x0312)那么表示用户按下了热键
           switch (m.Msg) {
               case WM_HOTKEY:
                   if (m.WParam.ToString().Equals("100")) {
                       GlobalKeyProcess();
                   }
                   //todo  其它热键
                   break;
           }
           // 将系统消息传递自父类的WndProc
           base.WndProc(ref m);
       }
   }
}

截图窗体-核心 Cutter.cs


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace test {
   public partial class Cutter : Form {
       Bitmap screenBtmp = null; //电脑屏幕的截图

public Cutter(Bitmap btm) {
           InitializeComponent();
           screenBtmp = btm;
       }

//鼠标右键退出
       private void Cutter_MouseClick(object sender, MouseEventArgs e) {
           if (e.Button == MouseButtons.Right) {
               this.DialogResult = DialogResult.OK;
               this.Close();
           }
       }

bool CatchStart = false; //自由截图开始
       Point downPoint; //初始点
       //鼠标左键按下-开始自由截图
       private void Cutter_MouseDown(object sender, MouseEventArgs e) {
           if (e.Button == MouseButtons.Left) {
               if (!CatchStart) {
                   CatchStart = true;
                   downPoint = new Point(e.X,e.Y); //初始点
               }
           }
       }

Rectangle catchRec;//存放截取范围
       //鼠标移动-绘制自由截图路径
       private void Cutter_MouseMove(object sender, MouseEventArgs e) { //路径绘制,核心
           if (CatchStart) {
               //
               //二次缓冲
               //不是直接在控件的背景画板上进行绘制鼠标移动路径,那样会造成绘制很多路径,因为前面绘制的路径还在
               //而是在内存中每移动一次鼠标就创建一张和屏幕截图一样的新BImtap,在这个Bitmap中绘制鼠标移动路径
               //然后在窗体背景画板上,绘制这个新的Bitmap,这样就不会造成绘制很多路径,因为每次都绘制了全新的Bitmao
               //但是这样做的话,因为鼠标移动的次数是大量的,所以在内存中会创建大量的Bitmap会造成内存消耗严重,所以每次移动绘制完后,
               //需要释放Dispose() 画板,画笔,Bitmap资源。
               //
               Bitmap copyBtmp = (Bitmap)screenBtmp.Clone(); //创建新的,在其上绘制路径
               //左上角
               Point firstP = new Point(downPoint.X,downPoint.Y);
               //新建画板,画笔
               Graphics g = Graphics.FromImage(copyBtmp);
               Pen p = new Pen(Color.Red,1);
               //计算路径范围
               int width = Math.Abs(e.X - downPoint.X);
               int height = Math.Abs(e.Y - downPoint.Y);
               if (e.X < downPoint.X) {
                   firstP.X = e.X;
               }
               if (e.Y < downPoint.Y) {
                   firstP.Y = e.Y;
               }
               //绘制路径
               catchRec = new Rectangle(firstP,new Size(width,height));
               //将路径绘制在新的BItmap上,之后要释放
               g.DrawRectangle(p, catchRec);
               g.Dispose();
               p.Dispose();

//窗体背景画板
               Graphics gf = this.CreateGraphics();
               //将新图绘制在窗体的画板上   --   自由截图-路径绘制处,其实还是一张和屏幕同样大小的图片,只不过上面有红色的选择路径
               gf.DrawImage(copyBtmp,new Point(0,0));
               gf.Dispose();
               //释放内存Bimtap
               copyBtmp.Dispose();

}
       }

bool catchFinished = false; //自由截图结束标志
       //鼠标左键弹起-结束自由截图
       private void Cutter_MouseUp(object sender, MouseEventArgs e) {
           if (e.Button == MouseButtons.Left) {
               if (CatchStart) {
                   CatchStart = false;
                   catchFinished = true;
               }
           }
       }

//鼠标左键双击,保存自由截取的图片
       private void Cutter_MouseDoubleClick(object sender, MouseEventArgs e) {
           if((e.Button == MouseButtons.Left) && catchFinished){
               //创建用户截取的范围大小的空图
               Bitmap catchBtmp = new Bitmap(catchRec.Width,catchRec.Height);
               Graphics g = Graphics.FromImage(catchBtmp);
               //在原始的屏幕截图ScreenBitmap上 截取 用户选择范围大小的区域   绘制到上面的空图
               //绘制完后,这个空图就是我们想要的截取的图片
               //参数1  原图
               //参数2  在空图上绘制的范围区域
               //参数3  原图的截取范围
               //参数4  度量单位
               g.DrawImage(screenBtmp,new Rectangle(0,0,catchRec.Width,catchRec.Height),catchRec,GraphicsUnit.Pixel);

//将自由截取的图片保存到剪切板中
               Clipboard.Clear();
               Clipboard.SetImage(catchBtmp);
               g.Dispose();
               catchFinished = false;
               this.BackgroundImage = screenBtmp;
               catchBtmp.Dispose();
               this.DialogResult = DialogResult.OK;
               this.Close();
           }
       }
   }
}

来源:https://blog.csdn.net/qq_38261174/article/details/85274325

标签:C#,截图
0
投稿

猜你喜欢

  • redis统计APP在线人数的实例

    2023-11-24 23:56:54
  • C#利用File方法对文件的操作总结(字节写入和读取)

    2022-07-20 09:30:55
  • 详解如何在Flutter中获取设备标识符

    2022-12-18 12:41:26
  • Java集合系列之ArrayList源码分析

    2023-01-31 03:02:36
  • 一篇文章带你了解C语言二分查找

    2023-10-16 19:51:57
  • 详解EventBus 3.x 的快速使用

    2021-09-04 21:00:29
  • SpringBoot一个非常蛋疼的无法启动的问题解决

    2023-12-12 15:24:36
  • Java如何获取对象属性及对应值

    2022-03-30 07:03:05
  • Gradle快速安装及入门

    2021-11-25 09:33:28
  • Java jpa外连接查询join案例详解

    2022-12-17 18:31:15
  • Java发送邮件遇到的常见需求汇总

    2021-10-07 14:51:02
  • Java 栈与队列超详细分析讲解

    2023-08-15 01:09:07
  • C#事件实例详解

    2022-04-23 22:24:47
  • C#使用Chart绘制曲线

    2023-03-12 19:08:56
  • Java HashMap的工作原理

    2022-12-25 14:39:02
  • Android 通过SQLite数据库实现数据存储管理

    2023-09-28 11:31:59
  • 兼容Spring Boot 1.x和2.x配置类参数绑定的工具类SpringBootBindUtil

    2023-11-03 05:35:06
  • Android日期选择器实现年月日三级联动

    2022-12-13 03:35:59
  • C#实现线程安全的简易日志记录方法

    2023-12-20 22:45:17
  • Springboot实现多服务器session共享

    2022-09-06 13:58:34
  • asp之家 软件编程 m.aspxhome.com