关于这个的例子其实网上已经有这方面的资料了,但是为了文章的完整性,还是觉得有必要讲解.
我们先来看一下效果:
  

 

( 图2 )

接下来看看这是如何做到的. 
思路:聊天窗体上有一个截图按钮,点击按钮后,程序将整个屏幕画在一个新的全屏窗体上,然后显示这个窗体.因为是全屏的窗体,并且隐藏了菜单栏、工具栏等,所以在我们看来就好像是一个桌面的截图,然后在这个新窗体上画矩形,最后保存矩形中的内容并显示在原来的聊天窗体中.
步骤:
A.新建一个窗体.命名为Catch.然后设置这个窗体的FormBorderStyle为None,WindowState为Maximized.
B.我们对代码进行编辑:

复制代码代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Client
{
    public partial class Catch : Form
    {
        public Catch()
        {
            InitializeComponent();
        }
        用户变量#region 用户变量
        private Point DownPoint = Point.Empty;//记录鼠标按下坐标,用来确定绘图起点
        private bool CatchFinished = false;//用来表示是否截图完成
        private bool CatchStart = false;//表示截图开始
        private Bitmap originBmp;//用来保存原始图像
        private Rectangle CatchRect;//用来保存截图的矩形
        #endregion
        //窗体初始化操作
        private void Catch_Load(object sender, EventArgs e)
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            this.UpdateStyles();
            //以上两句是为了设置控件样式为双缓冲,这可以有效减少图片闪烁的问题,关于这个大家可以自己去搜索下
            originBmp = new Bitmap(this.BackgroundImage);//BackgroundImage为全屏图片,我们另用变量来保存全屏图片
        }
        //鼠标右键点击结束截图
        private void Catch_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
        }
        //鼠标左键按下时动作
        private void Catch_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (!CatchStart)
                {//如果捕捉没有开始
                    CatchStart = true;
                    DownPoint = new Point(e.X, e.Y);//保存鼠标按下坐标
                }
            }
        }
        private void Catch_MouseMove(object sender, MouseEventArgs e)
        {
            if (CatchStart)
            {//如果捕捉开始
                Bitmap destBmp = (Bitmap)originBmp.Clone();//新建一个图片对象,并让它与原始图片相同
                Point newPoint = new Point(DownPoint.X, DownPoint.Y);//获取鼠标的坐标
                Graphics g = Graphics.FromImage(destBmp);//在刚才新建的图片上新建一个画板
                Pen p = new Pen(Color.Blue,1);
                int width = Math.Abs(e.X - DownPoint.X), height = Math.Abs(e.Y - DownPoint.Y);//获取矩形的长和宽
                if (e.X < DownPoint.X)
                {
                    newPoint.X = e.X;
                }
                if (e.Y < DownPoint.Y)
                {
                    newPoint.Y = e.Y;
                }
                CatchRect = new Rectangle(newPoint,new Size(width,height));//保存矩形
                g.DrawRectangle(p,CatchRect);//将矩形画在这个画板上
                g.Dispose();//释放目前的这个画板
                p.Dispose();
                Graphics g1 = this.CreateGraphics();//重新新建一个Graphics类
                //如果之前那个画板不释放,而直接g=this.CreateGraphics()这样的话无法释放掉第一次创建的g,因为只是把地址转到新的g了.如同string一样
                g1 = this.CreateGraphics();//在整个全屏窗体上新建画板
                g1.DrawImage(destBmp,new Point(0,0));//将刚才所画的图片画到这个窗体上
                //这个也可以属于二次缓冲技术,如果直接将矩形画在窗体上,会造成图片抖动并且会有无数个矩形.
                g1.Dispose();
                destBmp.Dispose();//要及时释放,不然内存将会被大量消耗

}
        }
        private void Catch_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (CatchStart)
                {
                    CatchStart = false;
                    CatchFinished = true;

}
            }
        }
        //鼠标双击事件,如果鼠标位于矩形内,则将矩形内的图片保存到剪贴板中
        private void Catch_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left&&CatchFinished)
            {
                if (CatchRect.Contains(new Point(e.X, e.Y)))
                {
                    Bitmap CatchedBmp = new Bitmap(CatchRect.Width, CatchRect.Height);//新建一个于矩形等大的空白图片
                    Graphics g = Graphics.FromImage(CatchedBmp);
                    g.DrawImage(originBmp, new Rectangle(0, 0, CatchRect.Width, CatchRect.Height), CatchRect, GraphicsUnit.Pixel);
                    //把orginBmp中的指定部分按照指定大小画在画板上
                    Clipboard.SetImage(CatchedBmp);//将图片保存到剪贴板
                    g.Dispose();
                    CatchFinished = false;
                    this.BackgroundImage = originBmp;
                    CatchedBmp.Dispose();
                    this.DialogResult = DialogResult.OK;
                    this.Close();
                }
            }
        }
    }
}

C.创建了Catch窗体后,我们在截图按钮(位于聊天窗体上)上加入以下事件:

复制代码代码如下:
 private void bCatch_Click(object sender, EventArgs e)
        {
            if (bCatch_HideCurrent.Checked)
            {
                this.Hide();//隐藏当前窗体
                Thread.Sleep(50);//让线程睡眠一段时间,窗体消失需要一点时间
                Catch CatchForm = new Catch();
                Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);//新建一个和屏幕大小相同的图片         
                Graphics g = Graphics.FromImage(CatchBmp);
                g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));//保存全屏图片
                CatchForm.BackgroundImage = CatchBmp;//将Catch窗体的背景设为全屏时的图片
                if (CatchForm.ShowDialog() == DialogResult.OK)
                {//如果Catch窗体结束,就将剪贴板中的图片放到信息发送框中
                    IDataObject iData = Clipboard.GetDataObject();
                    DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap);
                    if (iData.GetDataPresent(DataFormats.Bitmap))
                    {
                        richtextbox1.Paste(myFormat);
                        Clipboard.Clear();//清除剪贴板中的对象
                    }
                    this.Show();//重新显示窗体
                }
            }
        }

这样我们的截图功能便完成了.
我想对于初学者来说如何消去第一次绘制的图片是个比较困难的问题.如果没有采取措施,你会发现只要你鼠标移动,就会画一个矩形,这样便会出现N多的矩形,而我们只是要最后的那一个.
一般解决这种问题的方法有两种:
1.就是在绘制第二个图形时,我们先用与底色相同的颜色将上次绘制的图形重新绘制一下.但这往往需要底色为纯色时使用.
2.我们并不直接将图形画在画板上,我们用一个图片A来保存原画板上的图片.然后再新建一个与图片A相同的图片B,将我们要绘制的图形画在该图片B上,然后再将该图片B画在画板上.这样图片A并没有被改变.于是第二次画的时候我们还是同样新建一个与图片A相同的图片进行绘制.那么上一次的图形就不会被保留下来.问题也就解决了.

GDI+3的更多相关文章

  1. 超全面的.NET GDI+图形图像编程教程

    本篇主题内容是.NET GDI+图形图像编程系列的教程,不要被这个滚动条吓到,为了查找方便,我没有分开写,上面加了目录了,而且很多都是源码和图片~ (*^_^*) 本人也为了学习深刻,另一方面也是为了 ...

  2. (转载)GDI+双缓冲

    双缓冲在GDI+里可以有效的提高描画效率.改善显示的质量. 下面的代码是一个最简单的双缓冲的模板.可以根据需要,做简单的修改即可. Bitmap CacheImage( [Width], [Heigh ...

  3. (转载)解决GDI闪烁

    一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁. 先来谈谈闪烁产生的原因 原因一:如果熟悉显卡原理的话,调用GDI函数向屏幕输出的 ...

  4. 通过GDI+绘制 验证码

    只为了记录下自己的学习历程,方便日后查看 现在开始言归正传,以下为其完整代码附上 using System; using System.Collections.Generic; using Syste ...

  5. 【VC++技术杂谈007】使用GDI+进行图片格式转换

    本文主要介绍如何使用GDI+对图片进行格式转换,可以转换的图片格式为bmp.jpg.png. 1.加载GDI+库 GDI+是GDI图形库的一个增强版本,提供了一系列Visual C++ API.为了使 ...

  6. C# GDI绘制矩形框,鼠标左键拖动可移动矩形框,滚轮放大缩小矩形框

    最近工作需要,要做一个矩形框,并且 用鼠标左键拖动矩形框移动其位置.网上查了一些感觉他们做的挺复杂的.我自己研究一天,做了一个比较简单的,发表出来供大家参考一下.如觉得简单,可路过,谢谢.哈哈. 先大 ...

  7. 【Windows编程】系列第五篇:GDI图形绘制

    上两篇我们学习了文本字符输出以及Unicode编写程序,知道如何用常见Win32输出文本字符串,这一篇我们来学习Windows编程中另一个非常重要的部分GDI图形绘图.Windows的GDI函数包含数 ...

  8. GDI+ 笔记

    1.GDI+模板 #include<windows.h> #include<GdiPlus.h> #include <time.h> #include <ma ...

  9. C# GDI+发生一般性错误(A generic error occurred in GDI+))

    解决思路: 1. 因为 .net GDI+ 是对底层 的封装. 所以可以尝试用 Marshal.GetLastWin32Error();函数获得底层错误代码. try{ image.Save(file ...

  10. GDI与GDI+ 贴图性能对比

    在做绘图相关工作,由于对显示绘制结果实时性有要求,筛选了GDI , 与GDI+ 贴图性能. 这里假设在内存中已绘制完成一张图片,现需求显示在控件上,同时,总是更新全部区域. GDI+ 实现 priva ...

随机推荐

  1. 新建Django 项目完整流程

    1) 在桌面或者其他文件 新建项目名称 (mkdir 新建文件夹) 2)进入文件夹  pipenv --python3(用命令提示粘贴复制, 自己这样写经常有问题) 3) 启动虚拟环境  pipenv ...

  2. 网络协议-webService协议

    webservice 协议 Web Service使用的是 SOAP (Simple Object Access Protocol)协议soap协议只是用来封装消息用的.封装后的消息你可以通过各种已有 ...

  3. hdu 1086 You can Solve a Geometry Problem too 求n条直线交点的个数

    You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3 ...

  4. 代理实现aop以及代理工厂实现增强

    一.静态代理实现 1.接口(抽象主题) 2.接口的实现类(真实主题) 3.代理类(代理主题) 4.测试类: ApplicationContext context=new ClassPathXmlApp ...

  5. ROS学习笔记11-写一个简单的服务和客户端(C++版本)

    本文主要来源于:http://wiki.ros.org/ROS/Tutorials/WritingServiceClient%28c%2B%2B%29 写一个服务节点.在创建消息和服务中,我们创建了一 ...

  6. logj4.xml

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration PU ...

  7. 联想电脑硬盘保护系统EDU8.0.1iso安装

    管理306机房4年了,15年我带领的第一批学生参加吉林省职业院校技能大赛的时候,领导把这个机房交给我负责.那个时候这个机房的机器是全校的顶配,30台DELL16G内存,2T硬盘,I7处理器,后面是6组 ...

  8. 一个自己实现的Vector(只能处理基本类型数据)

    一个自己实现的Vector(只能处理基本类型数据) string 类型不行 bool char* int double float long long 等基本s类型可用 使用模板类实现.底层为数组实现 ...

  9. python进阶强化学习

    最近学习了慕课的python进阶强化训练,将学习的内容记录到这里,同时也增加了很多相关知识. 主要分为以下九个模块: 基本使用 迭代器和生成器 字符串 文件IO操作 自定义类和类的继承 函数装饰器和类 ...

  10. java有参

    一.带参数的方法 语法: 访问修饰符  方法返回值类型   方法名称 (参数列表){ // 方法体 注意:每个参数之间用","分割 二.形参和实参 形参:在方法定义时指定的参数 实 ...