c#创建画布_c# GDI+简单绘图(四) 简易画板功能
前几篇我已经向大家介绍了如何使用GDI+来绘图,并做了一个截图的实例,这篇我向大家介绍下如何来做一个类似windows画图的工具.
个人认为如果想做一个功能强大的绘图工具,那么单纯掌握GDI还远远不够,我的目前也只能做一个比较简单的绘图工具了.不足之处,欢迎大家讨论!
先来看一下最终效果吧:
主要实现功能:画直线,矩形,橡皮,圆形,切换颜色,打开图片,保存图片,清除图片,手动调节画布大小;软件刚启动时,为一张空白画布,我们可以直接在画布上绘画,也可以通过菜单中的“打开”,导入一张图片,然后我们就可以在这张图片上进行绘制。
平台:VS2005 WINFORM
由于代码过多,在这里只简要介绍下制作步骤,提供大家工程下载.
1.对整个界面进行布局.
2.实现绘图工具的功能
3.实现颜色拾取的功能,这里我们直接拿上次写的自定义控件来用.
4.实现菜单功能
5.实现手动调节画布大小的功能
6.测试
实现绘图工具的功能
为了让代码藕合度小点,稍许用了些设计模式,因为不是很会,所以代码还是有点乱乱的,嘿嘿!关于绘图工具的这些功能块全部写在了DrawTools这个类里.那么在主窗体中,只需要调用这个类来完成绘制就行了,而不需要过多的涉及到具体的绘图代码。绘图工具这个类提供的主要工具就是:铅笔、橡皮、直线、矩形、圆形、实心矩形、实心圆形。关于这些功能块的代码,并不难,只要大家对认真看过前几篇内容,那应该都看得懂。
这里要注意以下几点:
1.如何防止记录不必要的绘图过程中的痕迹?
这个问题在第三篇中有提到过,大家不妨先去看看那一篇。为了让代码看起来可读性高点,我设置了两个Image变量,finishingImg用来保存绘图过程中的痕迹,orginalImg用来保存已完成的绘图过程和初始时的背景图片。
2.这个类如何与主窗体进行通信?
当然如果直接将这些功能块写在主窗体中自然没有这个问题。但是那样代码会显得很混杂,如果只是工具代码出现问题就需要改整个项目。我在这里通过定义方法和属性,让主窗体通过给属性赋值将画板画布以及颜色什么的信息传给这个工具类,然后通过调用相应的工具方法来使用这些工具。
3.关键属性
要想让这些工具能正常使用,必须传递给他以下几样东西:目标画板(也就是picturebox),绘图颜色,原始画布。
实现菜单功能
这里就需要我们对文件的操作有一点了解,大家可以去查一下相关资料。
难点主要就是“打开”这个菜单项的实现
我们要实现将打开后的图片在修改后重新保存就必须让文件在打开后就能关闭,否则就会因为文件打开而无法覆盖原文件。就会导致编译时弹出“GDI 一般性错误”。所以根据网上其它朋友的做法就是先将打开的图片通过GDI+将图片画到另一个画布上,然后及时关闭打开的图片和用来绘制该图片的画板。
privatevoidopenPic_Click(objectsender, EventArgs e)
{
OpenFileDialog ofd=newOpenFileDialog();//实例化文件打开对话框ofd.Filter="JPG|*.jpg|Bmp|*.bmp|所有文件|*.*";//设置对话框打开文件的括展名if(ofd.ShowDialog()==DialogResult.OK)
{
Bitmap bmpformfile=newBitmap(ofd.FileName);//获取打开的文件panel2.AutoScrollPosition=newPoint(0,0);//将滚动条复位pbImg.Size=bmpformfile.Size;//调整绘图区大小为图片大小 reSize.Location=newPoint(bmpformfile.Width, bmpformfile.Height);//reSize为我用来实现手动调节画布大小用的
//因为我们初始时的空白画布大小有限,"打开"操作可能引起画板大小改变,所以要将画板重新传入工具类dt.DrawTools_Graphics=pbImg.CreateGraphics();
Bitmap bmp=newBitmap(pbImg.Width, pbImg.Height);
Graphics g=Graphics.FromImage(bmp);
g.FillRectangle(newSolidBrush(pbImg.BackColor),newRectangle(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控件
privateboolbReSize=false;//是否改变画布大小privatevoidreSize_MouseDown(objectsender, MouseEventArgs e)
{
bReSize=true;//当鼠标按下时,说明要开始调节大小}
privatevoidreSize_MouseMove(objectsender, MouseEventArgs e)
{
if(bReSize)
{
reSize.Location=newPoint(reSize.Location.X+e.X, reSize.Location.Y+e.Y);
} }
privatevoidreSize_MouseUp(objectsender, MouseEventArgs e)
{
bReSize=false;//大小改变结束
//调节大小可能造成画板大小超过屏幕区域,所以事先要设置autoScroll为true.
//但是滚动条的出现反而增加了我们的难度,因为滚动条上下移动并不会自动帮我们调整图片的坐标。
//这是因为GDI绘图的坐标系不只一个,好像有三个,没有仔细了解,一个是屏幕坐标,一个是客户区坐标,还个是文档坐标。
//滚动条的上下移动改变的是文档的坐标,但是客户区坐标不变,而location属性就属于客户区坐标,所以我们直接计算会出现错误
//这时我们就需要知道文档坐标与客户区坐标的偏移量,这就是AutoScrollPostion可以提供的 pbImg.Size=newSize(reSize.Location.X-(this.panel2.AutoScrollPosition.X), reSize.Location.Y-(this.panel2.AutoScrollPosition.Y));
dt.DrawTools_Graphics=pbImg.CreateGraphics();//因为画板的大小被改变所以必须重新赋值
//另外画布也被改变所以也要重新赋值Bitmap bmp=newBitmap(pbImg.Width, pbImg.Height);
Graphics g=Graphics.FromImage(bmp);
g.FillRectangle(newSolidBrush(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();
}
效果如下图(仔细看白色区域的右下角):
此时就可以通过拖动那个小方块来调节图片大小了。
这样,主要的问题差不多已经解决了,但还是有不足这处,欢迎大家提出宝贵的意见。
作者:stg609
c#创建画布_c# GDI+简单绘图(四) 简易画板功能相关推荐
- c#创建画布_C#GDI+编程基础(一:Graphics画布类)
GDI+存在的意义:将变成与具体硬件实现细节分开. GDI+步骤:获取画布,绘制图像.处理图像 命名空间: using System.Drawing;//提供对GDI+基本图形功能的访问 using ...
- c#创建画布_C#中的绘图
? LinearGradientBrush:使用沿渐变混合的两种颜色进行绘制 ? PathGradientBrush :基于编程者定义的唯一路径,使用复杂的混合色渐变进行绘制 我们这里只是简单介绍使用 ...
- c# GDI+简单绘图(一)
最近对GDI+这个东西接触的比较多,也做了些简单的实例,比如绘图板,仿QQ截图等. 最早接触这个类,是因为想做仿QQ截图的效果.巧的很,学会了如何做截图后,.NET课堂上老师也正巧要讲关于c#绘图方面 ...
- C#GDI+简单绘图
原文地址:http://www.cnblogs.com/stg609/archive/2008/03/16/1108333.html (一)GDI+ 基础知识 最近对GDI+这个东西接触的比较多,也做 ...
- [收藏转载]C# GDI+ 简单绘图(一)
最近对GDI+这个东西接触的比较多,也做了些简单的实例,比如绘图板,仿QQ截图等. 废话不多说了,我们先来认识一下这个GDI+,看看它到底长什么样. GDI+:Graphics Device Inte ...
- C# GDI+ 简单绘图 (三)
感谢大家的支持,这几天从早忙到晚,一个字累呀!!!现在挺困的,但是又不习惯这么早睡觉,哎~~还是利用这个时间继续来写第三篇吧. 前两篇已经基本向大家介绍了绘图的基本知识.那么,我就用我们上两篇所学的, ...
- C# GDI+ 简单绘图 (三) 仿浏览器截屏效果
感谢大家的支持,这几天从早忙到晚,一个字累呀!!!现在挺困的,但是又不习惯这么早睡觉,哎~~还是利用这个时间继续来写第三篇吧. 前两篇已经基本向大家介绍了绘图的基本知识.那么,我就用我们上两篇所学的, ...
- c# GDI+简单绘图(二)
在上一片里已经向大家介绍了如何使用GDI+绘制简单的图像,这一片继续向大家介绍其它一些绘图知识. 1.首先我们来看下上一片中我们使用过的Pen. Pen的属性主要有:Color(颜色),DashCap ...
- [导入]c# GDI+简单绘图(一)
摘要: 最近对GDI+这个东西接触的比较多,也做了些简单的实例,比如绘图板,仿QQ截图等. 最早接触这个类,是因为想做仿QQ截图的效果.巧的很,学会了如何做截图后,.NET课堂上老师也正巧要讲关于c# ...
最新文章
- 视频+课件| 室内动态变化场景中的相机重定位(CVPR2021)
- 你为什么薪水那么低(二)之 生产力
- 6.0 《数据库系统概论》之关系数据库的规范化理论(数据依赖对表的影响[插入-删除-修改-冗余]、1NF-2NF-3NF-BCNF-4NF、函数依赖与多值依赖)
- [BZOJ 4563]放棋子
- classpath*: 和classpath:有什么区别_我们可以从Java“HelloWorld”中学到什么?
- 强化学习-动态规划_强化学习-第5部分
- java入门5-asp.net关注
- SQL解析之硬解析和软解析
- linux命令 正则表达式,详解Linux命令中的正则表达式
- object-c 入门基础篇
- Python中np.sum()对axis的个人理解,超详细
- sql数值计算函数ceil(x)、sign(X)、sqrt(X)、truncate(X,D)、floor(x)、pi()、mod(x,y)
- 推荐系统(原理介绍)
- [XCTF-Reverse] 13-18
- 光线cms,如何增加像百度一样的智能提示
- 【Python百日进阶-Web开发-Feffery】Day378 - fac数据展示17:AntdTable 表格 (5)示例:表格校验、监听
- 大学毕业生参考信函提示
- 华为怎么显示返回按键_华为怎么把返回那三个键调出来
- c语言实现顺序存储程序,线性表的顺序存储结构动态态分配C语言实现
- cf1月24日服务器维护更新公告,CF官网公告 1月24日停机维护公告
热门文章
- 函数传址,但无法改变xy数据问题
- 趋势的郁闷--今天感觉到了防毒墙和防火墙的区别?
- 华为手机_text是什么文件_AS读取华为手机内置SD卡文件时,找不到文件问题
- 云深互联:跨越界限的集成者
- 熊掌号 php提交,网站接入熊掌号,网页配置并提交
- (Python)从零开始,简单快速学机器仿人视觉Opencv---第十九节:关于轮廓的函数
- html的div修改字体,div字体大小_div内文字大小改变css代码
- 玩转可视化图表之矩形树图
- Win10电脑总是自动安装乱七八糟的软件怎么回事?
- 软件生命周期中的测试概念,IT软件生命周期中的重要概念