利用.NET绘图技术制作水晶按钮控件
2015-06-10 09:42
681 查看
利用.NET绘图技术制作水晶按钮控件
UI(User Interface)编程在整个项目开发过程中是个颇为重要的环节,任何好的解决方案若没有良好的用户界面呈现给最终用户,那么就算包含了最先进的技术也不能算是好程序。UI编程体现在两个方面,一是设计精美的用户界面,再有就是符合大多数用户习惯和易于使用的操作流程,而制作出精美的、绚丽多彩的用户界面是博得最终用户喜爱的第一步。我们就以制作一个水晶样式的三维按钮为例来丰富.Net界面素材库,为Windows 窗体程序增加亮点。
一、 技术要点
不可否认的是,Windows编程已经进入.Net时代,虽然现在的编程平台仍然是多家并存,但是微软的.Net框架类库已经全面占据了主流地位。.Net框架为我们提供了非常丰富的类、函数和方法,从桌面到Web它可以触及到编程的任何领域,以至于可以完全放弃Win32
API 的手工调用,因为.Net框架已经为我们准备好了一切。尤其是GDI+的发布,Win32程序员都应该非常清楚,在VC6和Delphi5、6、7下要想绘制不规则图形、设计独特样式的窗口控件是件多么不轻松的事情,我们需要返回当前设备指针,然后坐标映射,再调用标准的Win32 GDI函数来进行绘制操作,最后还得记着释放设备指针等一系列内存清理操作,现在有了.Net类库,我们只需在控件的OnPaint事件中通过e.Graphics返回Graphics对象,然后创建一个自定义的刷子对象Brush来填充Graphics表面,再创建一个Region对象设计好我们需要的控件轮廓,并将其赋给控件的Region属性,在这个过程中可以使用GDI+为我们提供的丰富的类和方法来设计美轮美奂的控件外观,这样一个全新的控件就创建完成了。
我们的示例控件是一个水晶样式的三维按钮,设计这样一个按钮控件其实并不复杂,我们只需要捕获OnPaint事件,并在事件中按照不同的按钮状态譬如:鼠标进入、鼠标悬停、鼠标单击以及鼠标离开等重新绘制按钮的外观。按钮的三维样式实际上就是三个矩形区域的叠加,即阴影位于最底层、按钮本身以及最顶层的按钮头部白色泡泡部分,这三部分有效的叠加就制作成了一个惟妙惟肖的水晶样式的按钮了,如下图所示:
|
//创建按钮本身的图形 Rectangle rc = new Rectangle(btnOffset, btnOffset, this.ClientSize.Width - 8 - btnOffset, this.ClientSize.Height - 8 - btnOffset); GraphicsPath path1 = this.GetGraphicsPath(rc, 20); LinearGradientBrush br1 = new LinearGradientBrush(new Point(0, 0), new Point(0, rc.Height + 6), Color.Blue, Color.White); //创建按钮顶部的白色渐变 Rectangle rc3 = rc; rc3.Inflate(-5, -5); // rc3.Height = 15; GraphicsPath path3 = GetGraphicsPath(rc3, 20); LinearGradientBrush br3 = new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical) |
Rectangle rc2 = rc; rc2.Offset(shadowOffset, shadowOffset); GraphicsPath path2 = this.GetGraphicsPath(rc2, 20); PathGradientBrush br2 = new PathGradientBrush(path2); br2.CenterColor = Color.Black; br2.SurroundColors = new Color[] {SystemColors.ButtonFace}; //为了更逼真,我们将渐变结束颜色设定为窗体前景颜色,可以根据窗口的前景颜色适当调整 |
二、 实现
我们利用C# 来制作水晶按钮控件。
首先启动Visual Studio 2005,新建空白解决方案,我们取名为:TestCrystalButton,然后在项目导航栏上右击鼠标添加新项目,为此解决方案添加新的C# Windows 控件库,取名为MyControls。IDE会创建一个继承于UserControl名为UserControl1的类,修改代码使其继承自Button,并将原文件中所有引用UserControl1名称的地方都更改为CrystalButton,在项目导航栏中把UserControl1.cs更名为CrystalButton.cs,如下面一段代码:
namespace MyControls { public partial class CrystalButton: Button { public CrystalButton () { InitializeComponent(); } } } |
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
语句注释掉,因为从Button控件不可能有自动缩放功能,它必须依赖于其父控件。在源文件头部添加对System.Drawing.Imaging和System.Drawing.Drawing2D程序集的引用。首先需要创建一个枚举类型MouseActionType,当按钮需要绘制时会根据当前鼠标的位置进行不同状态的绘制,如下面一段代码:
...... private enum MouseActionType { None, Hover, Click } private MouseActionType mouseAction; |
控件的OnPaint事件是整个项目中最重要的代码段,它按照按钮组成的三部分分别进行绘制,最后将按钮的文本也同样绘制到按钮表面,所有操作都使用了二级缓存绘图技术,代码如下:
protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.Clear(SystemColors.ButtonFace ); Color clr = this.BackColor; int shadowOffset = 8; int btnOffset = 0; switch (mouseAction) { case MouseActionType.Click: shadowOffset = 4; clr = Color.LightGray; btnOffset = 2; break; case MouseActionType.Hover: clr = Color.LightGray; break; } g.SmoothingMode = SmoothingMode.AntiAlias; // 创建按钮本身的图形 Rectangle rc = new Rectangle(btnOffset, btnOffset, this.ClientSize.Width - 8 - btnOffset, this.ClientSize.Height - 8 - btnOffset); GraphicsPath path1 = this.GetGraphicsPath(rc, 20); LinearGradientBrush br1 = new LinearGradientBrush(new Point(0, 0), new Point(0, rc.Height + 6), clr, Color.White); // 创建按钮阴影 Rectangle rc2 = rc; rc2.Offset(shadowOffset, shadowOffset); GraphicsPath path2 = this.GetGraphicsPath(rc2, 20); PathGradientBrush br2 = new PathGradientBrush(path2); br2.CenterColor = Color.Black; br2.SurroundColors = new Color[] {SystemColors.ButtonFace}; //为了更逼真,我们将渐变结束颜色设定为窗体前景颜色,可以根据窗口的前景颜色适当调整 //创建按钮顶部白色渐变 Rectangle rc3 = rc; rc3.Inflate(-5, -5); rc3.Height = 15; GraphicsPath path3 = GetGraphicsPath(rc3, 20); LinearGradientBrush br3 = new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical); // 绘制图形 g.FillPath(br2, path2); //绘制阴影 g.FillPath(br1, path1); //绘制按钮 g.FillPath(br3, path3); //绘制顶部白色泡泡 //设定内存位图对象,进行二级缓存绘图操作 buttonBitmapRectangle = new Rectangle(rc.Location, rc.Size); buttonBitmap = new Bitmap(buttonBitmapRectangle.Width, buttonBitmapRectangle.Height); Graphics g_bmp = Graphics.FromImage(buttonBitmap); g_bmp.SmoothingMode = SmoothingMode.AntiAlias; g_bmp.FillPath(br1, path1); g_bmp.FillPath(br3, path3); //将region赋值给button Region rgn = new Region(path1); rgn.Union(path2); this.Region = rgn; // 绘制按钮的文本 GraphicsPath path4 = new GraphicsPath(); RectangleF path1bounds = path1.GetBounds(); Rectangle rcText = new Rectangle((int)path1bounds.X + btnOffset, (int)path1bounds.Y + btnOffset, (int)path1bounds.Width, (int)path1bounds.Height); StringFormat strformat = new StringFormat(); strformat.Alignment = StringAlignment.Center; strformat.LineAlignment = StringAlignment.Center; path4.AddString(this.Text, this.Font.FontFamily, (int)this.Font.Style, this.Font.Size, rcText, strformat); Pen txtPen = new Pen(this.ForeColor , 1); g.DrawPath(txtPen, path4); g_bmp.DrawPath(txtPen, path4); } |
private ImageAttributes imgAttr = new ImageAttributes();
Rectangle buttonBitmapRectangle;
Bitmap buttonBitmap;
private GraphicsPath GetGraphicsPath(Rectangle rc,int r)
{
int x = rc.X, y = rc.Y, w = rc.Width, h = rc.Height;
GraphicsPath gpath = new GraphicsPath();
gpath.AddArc(x, y, r, r, 180, 90);//左上角圆弧
gpath.AddArc(x + w - r, y, r, r, 270, 90);
gpath.AddArc(x + w - r, y + h - r, r, r, 0, 90);
gpath.AddArc(x, y + h - r, r, r, 90, 90);
gpath.CloseFigure();
return gpath;
}
protected override void OnMouseDown(MouseEventArgs mevent)
{
if (mevent.Button ==MouseButtons.Left )
{
this.mouseActionType = MouseActionType.Click;
//使整个画面无效并导致重绘控件
this.Invalidate();
}
base.OnMouseDown(mevent);
}
protected override void OnMouseUp(MouseEventArgs mevent)
{
this.mouseActionType = MouseActionType.Hover;
this.Invalidate();
base.OnMouseUp(mevent);
}
protected override void OnMouseHover(EventArgs e)
{
this.mouseActionType = MouseActionType.Hover;
this.Invalidate();
base.OnMouseHover(e);
}
protected override void OnMouseLeave(EventArgs e)
{
this.mouseActionType = MouseActionType.None;
this.Invalidate();
base.OnMouseLeave(e);
}
}
控件制作完毕,编译该解决方案及控件项目生成CrystalButton.dll,您可以在当前解决方案中添加使用该控件的Windows窗体程序项目,也可以在任意解决方案中添加对该控件的引用,简单到只需从工具箱中把CrystalButton拖拽到窗体上。
三、 总结
.Net 框架的GDI+增强型的图形图像绘制技术为我们提供了强大的图形图像绘制能力,它所包含的丰富的类和方法为我们实现完全自定义控件外观提供了有力保证,不但简化了程序代码还大大节省了编程时间。
该示例控件和程序在Visual Studio 2005 Team Suite、Windows XP SP2下编译运行通过。
相关文章推荐
- Flash/ActionScript 解决跨域问题的策略文件crossdomain.xml的写法
- ndk-r10 Eclipse配置
- PHP滚动日志的代码实现
- shell中的if语句
- struts2继承json-default与bean中的boolean的小问题
- windows新建或者重命名文件及文件夹必须手动刷新才能显示出来问题解决方法
- 有关文档碎片(document fragment)的用法
- 如何安装openjdk1.7
- 批量读取properties
- DirectX9.0 开发学习(一):向量几何基础知识
- 【Mybatis】Insert批量操作
- PHP array_diff_key()
- Interview
- [每天读书半小时] 2015-6-10 《内向者优势》
- Activity重识
- Linux 命令符 学习摘要,免得忘了
- 根据ip获取城市信息
- 中国青少年上网行为研究报告
- android adb无线调试
- MySQL数据库学习一 数据库概述