网站开发语言有什么,装修设计软件哪个好用,wordpress 小说主题,公众号运营外包价格最近对GDI这个东西接触的比较多#xff0c;也做了些简单的实例#xff0c;比如绘图板#xff0c;仿QQ截图等#xff0e; 废话不多说了#xff0c;我们先来认识一下这个GDI#xff0c;看看它到底长什么样. GDI#xff1a;Graphics Device Interface Plus也就是图形设备接…最近对GDI这个东西接触的比较多也做了些简单的实例比如绘图板仿QQ截图等 废话不多说了我们先来认识一下这个GDI看看它到底长什么样. GDIGraphics Device Interface Plus也就是图形设备接口,提供了各种丰富的图形图像处理功能;在C#.NET中使用GDI处理二维2D的图形和图像使用DirectX处理三维3D的图形图像,图形图像处理用到的主要命名空间是System . Drawing提供了对GDI基本图形功能的访问主要有Graphics类、Bitmap类、从Brush类继承的类、Font类、Icon类、Image类、Pen类、Color类等. 大概了解了什么是GDI后,我们来看一下绘图要用到的主要工具,要画图,肯定要画板吧,在C#中画板可以通过Graphics这个类来创建,有了画板,总得弄个笔什么之类的吧,不然怎么画呀,难不成我们用手指画.笔又可以分好多种类,比如铅笔,画刷等.它们的区别主要是铅笔可以用来画线条,而画刷呢,嘿嘿,自己考虑下.在c#中我们可以用Pen,Brush类来实现类似功能.颜料则自然是用Color类了. 有了工具,我们就可以开始动手了!(所需命名空间using System.Drawing;) 实现效果:在空白窗体中画基本图形 准备一个画板: 创建一个画板主要有3种方式: A: 在窗体或控件的Paint事件中直接引用Graphics对象 B: 利用窗体或某个控件的CreateGraphics方法 C: 从继承自图像的任何对象创建Graphics对象 这次我们就先以A为例: private void Form1_Paint(object sender, PaintEventArgs e) { Graphics g e.Graphics; //创建画板,这里的画板是由Form提供的. } 然后,我们要只笔: private void Form1_Paint(object sender, PaintEventArgs e) { Graphics g e.Graphics; //创建画板,这里的画板是由Form提供的. Pen p new Pen(Color.Blue, 2);//定义了一个蓝色,宽度为的画笔 } 接下来我们就可以来画画了. private void Form1_Paint(object sender, PaintEventArgs e) { Graphics g e.Graphics; //创建画板,这里的画板是由Form提供的. Pen p new Pen(Color.Blue, 2);//定义了一个蓝色,宽度为的画笔 g.DrawLine(p, 10, 10, 100, 100);//在画板上画直线,起始坐标为(10,10),终点坐标为(100,100) g.DrawRectangle(p, 10, 10, 100, 100);//在画板上画矩形,起始坐标为(10,10),宽为,高为 g.DrawEllipse(p, 10, 10, 100, 100);//在画板上画椭圆,起始坐标为(10,10),外接矩形的宽为,高为 } 效果图如下: 在上一片里已经向大家介绍了如何使用GDI绘制简单的图像,这一片继续向大家介绍其它一些绘图知识. 1.首先我们来看下上一片中我们使用过的Pen. Pen的属性主要有: Color(颜色),DashCap(短划线终点形状),DashStyle(虚线样式),EndCap(线尾形状), StartCap(线头形状),Width(粗细)等.我们可以用Pen 来画虚线,带箭头的直线等 Pen p new Pen(Color.Blue, 5);//设置笔的粗细为,颜色为蓝色Graphics g this.CreateGraphics();//画虚线p.DashStyle DashStyle.Dot;//定义虚线的样式为点g.DrawLine(p, 10, 10, 200, 10);//自定义虚线p.DashPattern new float[] { 2, 1 };//设置短划线和空白部分的数组g.DrawLine(p, 10, 20, 200, 20);//画箭头,只对不封闭曲线有用p.DashStyle DashStyle.Solid;//实线p.EndCap LineCap.ArrowAnchor;//定义线尾的样式为箭头g.DrawLine(p, 10, 30, 200, 30);g.Dispose();p.Dispose(); 以上代码运行结果: 2.接下来我们来看下Brush的使用 作用:我们可以用画刷填充各种图形形状如矩形、椭圆、扇形、多边形和封闭路径等,主要有几种不同类型的画刷: ? SolidBrush画刷最简单的形式用纯色进行绘制 ? HatchBrush类似于 SolidBrush但是可以利用该类从大量预设的图案中选择绘制时要使用的图案而不是纯色 ? TextureBrush使用纹理如图像进行绘制 ? LinearGradientBrush使用沿渐变混合的两种颜色进行绘制 ? PathGradientBrush 基于编程者定义的唯一路径使用复杂的混合色渐变进行绘制 我们这里只是简单介绍使用其中的几种: Graphics g this.CreateGraphics();Rectangle rect new Rectangle(10, 10, 50, 50);//定义矩形,参数为起点横纵坐标以及其长和宽//单色填充SolidBrush b1 new SolidBrush(Color.Blue);//定义单色画刷 g.FillRectangle(b1, rect);//填充这个矩形//字符串g.DrawString(字符串, new Font(宋体, 10), b1, new PointF(90, 10));//用图片填充TextureBrush b2 new TextureBrush(Image.FromFile(e:picture1.jpg));rect.Location new Point(10, 70);//更改这个矩形的起点坐标rect.Width 200;//更改这个矩形的宽来rect.Height 200;//更改这个矩形的高g.FillRectangle(b2, rect);//用渐变色填充rect.Location new Point(10, 290);LinearGradientBrush b3 new LinearGradientBrush(rect, Color.Yellow , Color.Black , LinearGradientMode.Horizontal);g.FillRectangle(b3, rect); 运行效果图: 3.坐标轴变换 在winform中的坐标轴和我们平时接触的平面直角坐标轴不同,winform中的坐标轴方向完全相反:窗体的左上角为原点(0,0),水平向左则X增大,垂直下向则Y增大 接下来,我们来实际操作下,通过旋转坐标轴的方向来画出不同角度的图案,或通过更改坐标原点的位置来平衡坐标轴的位置. Graphics g this.CreateGraphics();//单色填充//SolidBrush b1 new SolidBrush(Color.Blue);//定义单色画刷 Pen p new Pen(Color.Blue,1);//转变坐标轴角度for (int i 0; i 90; i){ g.RotateTransform(i);//每旋转一度就画一条线 g.DrawLine(p, 0, 0, 100, 0); g.ResetTransform();//恢复坐标轴坐标}//平移坐标轴g.TranslateTransform(100, 100);g.DrawLine(p, 0, 0, 100, 0);g.ResetTransform();//先平移到指定坐标,然后进行度旋转g.TranslateTransform(100,200);for (int i 0; i 8; i){g.RotateTransform(45);g.DrawLine(p, 0, 0, 100, 0);}g.Dispose(); 运行效果图: 4.最后我们来看下Graphics这个画板上我们还可以画什么 其实我们上面用到的都是在画一些简单的图形,直线,矩形,扇形,圆孤等,我们还可以用它来绘制图片,这可以用它的DrawImage方法.这里我不详细讲解,大家有兴趣可以自己去MSDN了解下.我们后面会讲到的截图就会用到这个方法. 感谢大家的支持,这几天从早忙到晚,一个字累呀!!!现在挺困的,但是又不习惯这么早睡觉,哎~~还是利用这个时间继续来写第三篇吧. 前两篇已经基本向大家介绍了绘图的基本知识.那么,我就用我们上两篇所学的,做几个例子 我们先来做一个简单的----仿QQ截图关于这个的例子其实网上已经有这方面的资料了,但是为了文章的完整性,还是觉得有必要讲解 我们先来看一下效果 图1 (图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类 //如果之前那个画板不释放而直接gthis.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.LeftCatchFinished) { 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相同的图片进行绘制那么上一次的图形就不会被保留下来问题也就解决了 下一次向大家介绍如何做一个仿windows画板的程序 前几篇我已经向大家介绍了如何使用GDI来绘图并做了一个截图的实例这篇我向大家介绍下如何来做一个类似windows画图的工具. 个人认为如果想做一个功能强大的绘图工具那么单纯掌握GDI还远远不够我的目前也只能做一个比较简单的绘图工具了不足之处欢迎大家讨论 先来看一下最终效果吧 主要实现功能画直线矩形橡皮圆形切换颜色打开图片保存图片清除图片手动调节画布大小;软件刚启动时为一张空白画布我们可以直接在画布上绘图也可以通过菜单中的“打开”导入一张图片然后我们就可以在这张图片上进行绘制。 平台VS2005 WINFORM 由于代码过多在这里只简要介绍下制作步骤提供大家工程下载 1.对整个界面进行布局 2.实现绘图工具的功能 3.实现颜色拾取的功能这里我们直接拿上次写的自定义控件来用 4.实现菜单功能 5.实现手动调节画布大小的功能 6.测试 实现绘图工具的功能 为了让代码藕合度小点稍许用了些设计模式因为不是很会所以代码还是有点乱乱的绘图工具的这些功能块全部写在了DrawTools这个类里那么在主窗体中只需要调用这个类来完成绘制就行了而不需要过多的涉及到具体的绘图代码。绘图工具这个类提供的主要工具就是铅笔、橡皮、直线、矩形、圆形、实心矩形、实心圆形。关于这些功能块的代码并不难只要大家对认真看过前几篇内容那应该都看得懂。 这里有几点要注意 .如何防止记录不必要的绘图过程中的痕迹 这个问题在第三篇中有提到过大家不妨先去看看那一篇。为了让代码看起来可读性高点我设置了两个Image变量finishingImg用来保存绘图过程中的痕迹orginalImg用来保存已完成的绘图过程和初始时的背景图片。 2.这个类如何与主窗体进行通信 当然如果直接将这些功能块写在主窗体中自然没有这个问题。但是那样代码会显得很混杂如果只是工具代码出现问题就需要改整个项目。我在这里通过定义方法和属性让主窗体通过给属性赋值将画板画布以及颜色什么的信息传给这个工具类然后通过调用相应的工具方法来使用这些工具。 3.关键属性 要想让这些工具能正常使用必须传递给他以下几样东西目标画板也就是picturebox绘图颜色原始画布。 实现菜单功能 这里就需要我们对文件的操作有一点了解大家可以去查一下相关资料。 难点主要就是“打开”这个菜单项的实现 我们要实现将打开后的图片在修改后重新保存就必须让文件在打开后就能关闭否则就会因为文件打开而无法覆盖原文件。就会导致编译时弹出“GDI 一般性错误”。所以根据网上其它朋友的做法就是先将打开的图片通过GDI将图片画到另一个画布上然后及时关闭打开的图片和用来绘制该图片的画板。详见http://www.wanxin.org/redirect.php?tid3gotolastpost private void openPic_Click(object sender, EventArgs e) { OpenFileDialog ofd new OpenFileDialog();//实例化文件打开对话框 ofd.Filter JPG|*.jpg|Bmp|*.bmp|所有文件|*.*;//设置对话框打开文件的括展名 if (ofd.ShowDialog() DialogResult.OK) { Bitmap bmpformfile new Bitmap(ofd.FileName);//获取打开的文件 panel2.AutoScrollPosition new Point(0,0);//将滚动条复位 pbImg.Size bmpformfile.Size;//调整绘图区大小为图片大小 reSize.Location new Point(bmpformfile.Width, bmpformfile.Height);//reSize为我用来实现手动调节画布大小用的 //因为我们初始时的空白画布大小有限打开操作可能引起画板大小改变所以要将画板重新传入工具类 dt.DrawTools_Graphics pbImg.CreateGraphics(); Bitmap bmp new Bitmap(pbImg.Width, pbImg.Height); Graphics g Graphics.FromImage(bmp); g.FillRectangle(new SolidBrush(pbImg.BackColor), new Rectangle(0, 0, pbImg.Width, pbImg.Height));//不使用这句话那么这个bmp的背景就是透明的 g.DrawImage(bmpformfile, 0, 0,bmpformfile.Width,bmpformfile.Height);//将图片画到画板上 g.Dispose();//释放画板所占资源 //不直接使用pbImg.Image Image.FormFile(ofd.FileName)是因为这样会让图片一直处于打开状态也就无法保存修改后的图片 bmpformfile.Dispose();//释放图片所占资源 g pbImg.CreateGraphics(); g.DrawImage(bmp, 0, 0); g.Dispose(); dt.OrginalImg bmp; bmp.Dispose(); sFileName ofd.FileName;//储存打开的图片文件的详细路径用来稍后能覆盖这个文件 ofd.Dispose(); } } 清除图像其实就是用白色填充整个画布其它的都比较简单这就不具体讲了。 实现手动调节画布大小 网上有人说使用API但是个人觉得还是使用其它控件帮忙比较简单至少我们还看得懂。 思路放置一个picturebox1(尺寸为5*5)将它固定在主画板的右下角然后改变鼠标进入时的Cursor为箭头形状设置鼠标按下移动时的事件让该picturebox1 跟随鼠标移动。当鼠标松开时将主画板的右下角坐标调整为picturebox1的坐标。 下面来看下代码 其中的reSize就是我们用来帮忙的picturebox控件 private bool bReSize false;//是否改变画布大小 private void reSize_MouseDown(object sender, MouseEventArgs e) { bReSize true;//当鼠标按下时说明要开始调节大小 } private void reSize_MouseMove(object sender, MouseEventArgs e) { if (bReSize) { reSize.Location new Point(reSize.Location.X e.X, reSize.Location.Y e.Y); } } private void reSize_MouseUp(object sender, MouseEventArgs e) { bReSize false;//大小改变结束 //调节大小可能造成画板大小超过屏幕区域所以事先要设置autoScroll为true. //但是滚动条的出现反而增加了我们的难度因为滚动条上下移动并不会自动帮我们调整图片的坐标。 //这是因为GDI绘图的坐标系不只一个好像有三个没有仔细了解一个是屏幕坐标一个是客户区坐标还个是文档坐标。 //滚动条的上下移动改变的是文档的坐标但是客户区坐标不变而location属性就属于客户区坐标所以我们直接计算会出现错误 //这时我们就需要知道文档坐标与客户区坐标的偏移量这就是AutoScrollPostion可以提供的 pbImg.Size new Size(reSize.Location.X - (this.panel2.AutoScrollPosition.X), reSize.Location.Y - (this.panel2.AutoScrollPosition.Y)); dt.DrawTools_Graphics pbImg.CreateGraphics();//因为画板的大小被改变所以必须重新赋值 //另外画布也被改变所以也要重新赋值 Bitmap bmp new Bitmap(pbImg.Width, pbImg.Height); Graphics g Graphics.FromImage(bmp); g.FillRectangle(new SolidBrush(Color.White), 0, 0, pbImg.Width, pbImg.Height); g.DrawImage(dt.OrginalImg, 0, 0); g.Dispose(); g pbImg.CreateGraphics(); g.DrawImage(bmp, 0, 0); g.Dispose(); dt.OrginalImg bmp; bmp.Dispose(); } 效果如下图仔细看白色区域的右下角 此时就可以通过拖动那个小方块来调节图片大小了。 这样主要的问题差不多已经解决了但还是有不足这处欢迎大家提出宝贵的意见。 转载于:https://www.cnblogs.com/zhili/archive/2013/05/24/3096101.html