适用于:
Microsoft® .NET Framework 精简版
Microsoft® Visual Studio® .NET 2003
摘要:学习如何创建基于 .NET Framework 精简版的图像按钮。
下载 ImageButton.msi(英文)。(请注意,在示例文件中,程序员的注释使用的是英文,本文中将其译为中文是为了便于读者理解。)
简介
.NET Framework 精简版提供了一套丰富的控件,用于设计应用程序的用户界面。但是,作为一名 .NET Framework 开发人员,首先要认识到 .NET Framework 精简版的 1.0 版中并未包含所有 .NET Framework Windows 窗体程序包的功能。在 Microsoft® Windows® CE 平台上,内存、CPU 和其他资源更加珍贵。这意味着您将看到 .NET Framework 完整版和 .NET Framework 精简版之间有很大的区别。例如,大部分标准控件(例如 Button、ListBox 或 Label)都不允许覆盖 OnPaint 事件以及向其中添加自定义图形。本白皮书的主要示例是一个简单的 ImageButton 控件。该控件用于演示创建自行绘制的自定义控件的主要技术,也是在基于 .NET Framework 精简版的应用程序中处理图像、文本或线条图时获得最佳图像性能的最实用原则。
提供的功能
由于资源限制,在 .NET Framework 精简版中没有完全的 GDI+ 支持。您可能已经知道,GDI+ 服务分为以下三大类:
- 二维矢量图形
- 图像处理
- 版式
在 .NET Framework 精简版的“二维矢量图形”中,Graphics 对象仅支持核心图形图元,例如,Ellipse、Line、Image、Polygon、Rectangle、String、Fill Ellipse、Fill Polygon、Fill Rectangle 和 Fill Region。
在“图像处理”类别中,Bitmap 类不支持位级别的图像处理,也不支持将位图保存到文件。此外,.NET Framework 通过 ControlStyles 支持的双缓冲也不能使用。
“版式”类别主要与文本显示有关,例如字体、字号和样式等等。.NET Framework 精简版中的 GDI 提供了对此任务的支持,但是不能使用任何子像素反走样。
但不用担心!GDI 功能提供的子集仍然允许我们创建一个图形处理功能强大的应用程序。让我们看一下 .NET Framework 精简版附带的 System.Windows.Forms.DataGrid 控件。该控件是一个完全受控的、自行绘制的控件,通过呈现多个数据行和单元格来提供良好的图形性能。要获得这种性能,我们只需要按照平台为我们设置的规则进行操作。
创建图形的最佳方法
- 在创建自行绘制的控件时,请从 System.Windows.Forms.Control 中派生,并覆盖 OnPaint 和 OnPaintBackground 事件。
using System; using System.Drawing; using System.Windows.Forms; public class MyButton : Control { protected override void OnPaint(PaintEventArgs e ) { //一些绘图逻辑 Graphics gr = e.Graphics; gr.DrawImage(image, 0, 0); Graphics gr = e.Graphics; gr.DrawImage(image, 0, 0); gr.DrawRectangle(pen, this.ClientRectangle); } protected override void OnPaintBackground(PaintEventArgs e ) { //不执行任何操作 } }
- 在 OnPaint 事件中使用 Pen、Bitmap 和 Brush 对象之前,预先对其进行缓存。OnPaint 事件的特性是它可以根据操作系统的要求无限次调用。在实例化和销毁这些对象上浪费时间将会影响绘图性能。
- 使用代码中的双缓冲来减少刷新屏幕上的图形时可能出现的闪烁现象。通常,双缓存逻辑如下所示:
protected override void OnPaint(PaintEventArgs e ) { Graphics gxOff; //屏幕外的图像 if (m_bmpOffscreen == null) //要双缓冲的位图 { m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height); } gxOff = Graphics.FromImage(m_bmpOffscreen); gxOff.Clear(this.BackColor); //绘制一些位图 gxOff.DrawImage(bmpParent, 0, 0, bmpRect, GraphicsUnit.Pixel); //边界矩形 Rectangle rc = this.ClientRectangle; rc.Width--; rc.Height--; //绘制边界 gxOff.DrawRectangle(new Pen(Color.Black), rc); //从内存位图绘制 e.Graphics.DrawImage(m_bmpOffscreen, 0, 0); base.OnPaint(e); }
在上面的代码中,我们通过调用 Graphics 类的静态 FromImage 方法在与我们的控件大小相同的空位图中创建了一个 Graphics 对象。我们在内存中的 Graphics 对象上进行所有的绘图,完成后,将整个准备好的位图覆盖到控件的图形上即可。
.NET Framework 精简版中也具备使用 ImageAttributes 参数透明绘制位图的功能,但是需要执行的操作比在桌面中多。
ImageAttributes imageAttr = new ImageAttributes(); // 设置透明键值 imageAttr.SetColorKey(Color.White, Color.White); //绘制时使用该键值 gxOff.DrawImage(m_bmp, imgRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imageAttr);
请记住,SetColorKey 方法中的低颜色键值和高颜色键值应该相同,这主要是因为 .NET Framework 精简版不支持通过其他任何方式设置透明颜色。
应用规则
为了形象地演示对这些最佳方法的使用,我们准备创建一个自行绘制的 ImageButton 控件。要求创建一个在其上显示的“下压按钮”样式的控件,并显示可视确认使用户知道按钮被按下了。
开始时,我们在 Visual Studio .NET 中创建一个新的 Smart Device Application(智能设备应用程序)项目,并选择 Windows Application(Windows 应用程序)作为项目类型。将新的 ImageButton 类添加到项目中:
using System; using System.Drawing; using System.Windows.Forms; public class ImageButton : Control { //私有成员 private Image image; //表示按下状态的标记 private bool bPushed; private Bitmap m_bmpOffscreen; public ImageButton() { bPushed = false; //默认最小的大小 this.Size = new Size(21, 21); } protected override void OnPaint(PaintEventArgs e ) { //一些绘图逻辑 } protected override void OnPaintBackground(PaintEventArgs e ) { //不执行任何操作 } }
在上面的代码中,我们按照前面的说明从 Control 中派生出 ImageButton 类,并覆盖了 OnPaint 和 OnPaintBackground 事件。 ImageButton 将需要一个用于显示的图像,因此我们添加 Image 属性:
public Image Image { get { return image; } set { image = value; } }
当然,所有自行绘制的控件的主体是 OnPaint 事件中的绘图代码:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e ) { Graphics gxOff; //屏幕外的图像 Rectangle imgRect; //图像矩形 Brush backBrush; //填充背景色的画笔 if (m_bmpOffscreen == null) //要双缓冲的位图 { m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height); } gxOff = Graphics.FromImage(m_bmpOffscreen); gxOff.Clear(this.BackColor); if (!bPushed) backBrush = new SolidBrush(Parent.BackColor); else //处于按下状态时更改背景 backBrush = new SolidBrush(Color.LightGray); gxOff.FillRectangle(backBrush, this.ClientRectangle); if (image != null) { //将图像相对于控件居中 int imageLeft = (this.Width - image.Width) / 2; int imageTop = (this.Height - image.Height) / 2; if (!bPushed) { imgRect = new Rectangle(imageLeft, imageTop, image.Width, image.Height); } else //按钮已按下 { //将图像偏移一个像素 imgRect = new Rectangle(imageLeft + 1, imageTop + 1, image.Width, image.Height); } //设置透明键值 ImageAttributes imageAttr = new ImageAttributes(); imageAttr.SetColorKey(BackgroundImageColor(image), BackgroundImageColor(image)); //绘制图像 gxOff.DrawImage(image, imgRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttr); } if (bPushed) //按钮已按下 { //准备矩形 Rectangle rc = this.ClientRectangle; rc.Width--; rc.Height--; //绘制矩形 gxOff.DrawRectangle(new Pen(Color.Black), rc); } //从内存位图绘制 e.Graphics.DrawImage(m_bmpOffscreen, 0, 0); base.OnPaint(e); }
在创建这些代码时,我遵循了前一部分中列出的有关在 .NET Framework 精简版中成功绘图的原则。我尽可能预先缓存了绘图对象,并使用双缓冲来减少闪烁现象。为了使图像透明,我们使用以下辅助函数来识别其背景色:
private Color BackgroundImageColor(Image image) { Bitmap bmp = new Bitmap(image); return bmp.GetPixel(0, 0); }
此函数的任务是检索位图左上角的像素颜色。绘制按钮时,我们需要检查用户按下此按钮时所需的 bPushed 标志。通过覆盖 OnMouseDown 和 OnMouseUp 事件我们很容易达到完成这一任务:
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e ) { bPushed = true; this.Invalidate(); } protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e) { bPushed = false; this.Invalidate(); }
使用方法
新创建的 ImageButton 的用法应该很简单。只需在窗体构造函数中添加以下几行代码即可:
public Form1() { InitializeComponent(); imageButton1 = new ImageButton(); imageButton1.Image = new Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream("ImageButtonProject.doorin2.gif")); imageButton1.Location = new Point(30, 50); imageButton1.Size = new Size(44, 34); //连接到 click 事件 imageButton1.Click+=new EventHandler(imageButton1_Click); this.Controls.Add(imageButton1); }
我选择添加图像文件 doorin2.gif,将其作为内嵌的资源添加到项目中。很容易通过当前程序集的 GetManifestResourceStream 方法来检索该图像。
图 1:一个窗体上有三个 ImageButton 控件
图 2:第一个 ImageButton 处于按下状态
С
.NET Framework 精简版所提供的图形和绘图功能不如 .NET Framework 完整版中提供的多。这是由于平台资源的限制造成的。但是,如果了解一些自定义绘图原则,仍然可以在您的应用程序中创建丰富多彩的图形。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10294527/viewspace-126753/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/10294527/viewspace-126753/