创建ImageButton自定义控件
*本文大部分都参考了MSDN的文章,非原创
在创建自行绘制的控件时,应从 System.Windows.Forms.Control 中派生,并覆盖 OnPaint 和 OnPaintBackground 事件。 下面是一个最简单的例子:
当然,现在这个ImageButton除了能显示一张图片以外什么也不能做,我将在后面一步一步完善它。
OnPaint 事件的特性是它可以根据操作系统的要求无限次调用。在实例化和销毁这些对象上浪费时间将会影响绘图性能。 出现所谓的“闪烁”现象,通常采用“双缓冲”来减小这一因素的影响:
然而,陈现在控件上的一张图片,我们如何让其显示透明图像,为了使图像透明,我们使用下面这个函数来获取图片的背景颜色:
这只是一个示例,还有很多不足之处,读者可以自己对其进行扩展,如加入Attributes的支持、为图片在控件中的陈现提供不同的方式(如当图片大于控件的尺寸时,是否对图片进行缩放)等。
在创建自行绘制的控件时,应从 System.Windows.Forms.Control 中派生,并覆盖 OnPaint 和 OnPaintBackground 事件。 下面是一个最简单的例子:
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8
9namespace Animation
10{
11 public partial class ImageButton : Control
12 {
13 private Image image;
14
15 public ImageButton()
16 {
17 InitializeComponent();
18 }
19
20 public Image Image
21 {
22 get { return this.image; }
23 set { this.image = value; }
24 }
25
26 protected override void OnPaint(PaintEventArgs pe)
27 {
28 if (image != null)
29 {
30 Graphics g = pe.Graphics;
31 g.DrawImage(image, this.ClientRectangle);
32 }
33
34 // 调用基类 OnPaint
35 base.OnPaint(pe);
36 }
37
38 protected override void OnPaintBackground(PaintEventArgs pevent)
39 {
40 base.OnPaintBackground(pevent);
41 }
42 }
43}
44
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8
9namespace Animation
10{
11 public partial class ImageButton : Control
12 {
13 private Image image;
14
15 public ImageButton()
16 {
17 InitializeComponent();
18 }
19
20 public Image Image
21 {
22 get { return this.image; }
23 set { this.image = value; }
24 }
25
26 protected override void OnPaint(PaintEventArgs pe)
27 {
28 if (image != null)
29 {
30 Graphics g = pe.Graphics;
31 g.DrawImage(image, this.ClientRectangle);
32 }
33
34 // 调用基类 OnPaint
35 base.OnPaint(pe);
36 }
37
38 protected override void OnPaintBackground(PaintEventArgs pevent)
39 {
40 base.OnPaintBackground(pevent);
41 }
42 }
43}
44
当然,现在这个ImageButton除了能显示一张图片以外什么也不能做,我将在后面一步一步完善它。
OnPaint 事件的特性是它可以根据操作系统的要求无限次调用。在实例化和销毁这些对象上浪费时间将会影响绘图性能。 出现所谓的“闪烁”现象,通常采用“双缓冲”来减小这一因素的影响:
private Bitmap imageBuffer;
protected override void OnPaint(PaintEventArgs e)
{
Graphics gBuffer; //屏幕外的图像
Rectangle imageRect; //图像矩形
//在内存中绘制位图
if (imageBuffer == null)
{
imageBuffer = new Bitmap(ClientSize.Width, ClientSize.Height);
}
imageRect = this.ClientRectangle;
gBuffer = Graphics.FromImage(imageBuffer);
gBuffer.Clear(this.BackColor); //清除绘图面并以背景色填充
gBuffer.DrawImage(this.Image, 0, 0, imageRect, GraphicsUnit.Pixel);
//从内存位图绘制
e.Graphics.DrawImage(imageBuffer, 0, 0);
base.OnPaint(e);
}
在上面的代码中,我们通过调用 Graphics 类的静态 FromImage 方法在与我们的控件大小相同的空位图中创建了一个 Graphics 对象。我们在内存中的 Graphics 对象上进行所有的绘图,完成后,将整个准备好的位图覆盖到控件的图形上即可。源代码如下:protected override void OnPaint(PaintEventArgs e)
{
Graphics gBuffer; //屏幕外的图像
Rectangle imageRect; //图像矩形
//在内存中绘制位图
if (imageBuffer == null)
{
imageBuffer = new Bitmap(ClientSize.Width, ClientSize.Height);
}
imageRect = this.ClientRectangle;
gBuffer = Graphics.FromImage(imageBuffer);
gBuffer.Clear(this.BackColor); //清除绘图面并以背景色填充
gBuffer.DrawImage(this.Image, 0, 0, imageRect, GraphicsUnit.Pixel);
//从内存位图绘制
e.Graphics.DrawImage(imageBuffer, 0, 0);
base.OnPaint(e);
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Animation
{
public partial class ImageButton : Control
{
private Image image;
private bool bePushsd;
private Bitmap imageBuffer;
public ImageButton()
{
this.Size = new Size(100, 100);
bePushsd = false;
}
public Image Image
{
get { return this.image; }
set { this.image = value; }
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics gBuffer;
Rectangle imageRect; //图像矩形
Brush backBrush;
//在内存中绘制位图
if (imageBuffer == null)
{
imageBuffer = new Bitmap(ClientSize.Width, ClientSize.Height);
}
gBuffer = Graphics.FromImage(imageBuffer);
gBuffer.Clear(this.BackColor); //清除绘图面并以背景色填充
if (!bePushsd)
{
backBrush = new SolidBrush(Parent.BackColor);
}
else
{
backBrush = new SolidBrush(Color.LightGray);
}
gBuffer.FillRectangle(backBrush, this.ClientRectangle);
if (this.Image != null)
{
int imageLeft = (this.Width - this.Image.Width) / 2;
int imageTop = (this.Height - this.Image.Height) / 2;
if (!bePushsd)
{
imageRect = new Rectangle(imageLeft, imageTop, this.Image.Width, this.Image.Height);
}
else
{
imageRect = new Rectangle(imageLeft + 2, imageTop + 2, this.Image.Width, this.Image.Height);
}
gBuffer.DrawImage(this.Image, imageRect, 0, 0, this.Image.Width, this.Image.Height, GraphicsUnit.Pixel);
}
//从内存位图绘制
e.Graphics.DrawImage(imageBuffer, 0, 0);
base.OnPaint(e);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
base.OnPaintBackground(pevent);
}
protected override void OnMouseDown(MouseEventArgs e)
{
bePushsd = true;
this.Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
bePushsd = false;
this.Invalidate();
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Animation
{
public partial class ImageButton : Control
{
private Image image;
private bool bePushsd;
private Bitmap imageBuffer;
public ImageButton()
{
this.Size = new Size(100, 100);
bePushsd = false;
}
public Image Image
{
get { return this.image; }
set { this.image = value; }
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics gBuffer;
Rectangle imageRect; //图像矩形
Brush backBrush;
//在内存中绘制位图
if (imageBuffer == null)
{
imageBuffer = new Bitmap(ClientSize.Width, ClientSize.Height);
}
gBuffer = Graphics.FromImage(imageBuffer);
gBuffer.Clear(this.BackColor); //清除绘图面并以背景色填充
if (!bePushsd)
{
backBrush = new SolidBrush(Parent.BackColor);
}
else
{
backBrush = new SolidBrush(Color.LightGray);
}
gBuffer.FillRectangle(backBrush, this.ClientRectangle);
if (this.Image != null)
{
int imageLeft = (this.Width - this.Image.Width) / 2;
int imageTop = (this.Height - this.Image.Height) / 2;
if (!bePushsd)
{
imageRect = new Rectangle(imageLeft, imageTop, this.Image.Width, this.Image.Height);
}
else
{
imageRect = new Rectangle(imageLeft + 2, imageTop + 2, this.Image.Width, this.Image.Height);
}
gBuffer.DrawImage(this.Image, imageRect, 0, 0, this.Image.Width, this.Image.Height, GraphicsUnit.Pixel);
}
//从内存位图绘制
e.Graphics.DrawImage(imageBuffer, 0, 0);
base.OnPaint(e);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
base.OnPaintBackground(pevent);
}
protected override void OnMouseDown(MouseEventArgs e)
{
bePushsd = true;
this.Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
bePushsd = false;
this.Invalidate();
}
}
}
然而,陈现在控件上的一张图片,我们如何让其显示透明图像,为了使图像透明,我们使用下面这个函数来获取图片的背景颜色:
private Color ImageBackColor(Image image)
{
return (new Bitmap(image)).GetPixel(0, 0);
}
然后使用ImageAttributes类的public void SetColorKey(Color colorLow, Color colorHigh) 方法设置透明键值,此方法设置高低颜色键值,以便颜色范围可以成为透明的。对于任何颜色,只要它的三种颜色成分(红、绿、蓝)都处于高低颜色键的对应成分之间,它的颜色就会成为透明的。在使用该类首先要添加如下命名空间:{
return (new Bitmap(image)).GetPixel(0, 0);
}
using System.Drawing.Imaging;
要使用该方法,将上面的红颜色代码改为如下即可:ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorKey(ImageBackColor(this.Image), ImageBackColor(this.Image));
gBuffer.DrawImage(this.Image, imageRect, 0, 0, this.Image.Width, this.Image.Height, GraphicsUnit.Pixel,imageAttr);
imageAttr.SetColorKey(ImageBackColor(this.Image), ImageBackColor(this.Image));
gBuffer.DrawImage(this.Image, imageRect, 0, 0, this.Image.Width, this.Image.Height, GraphicsUnit.Pixel,imageAttr);
这只是一个示例,还有很多不足之处,读者可以自己对其进行扩展,如加入Attributes的支持、为图片在控件中的陈现提供不同的方式(如当图片大于控件的尺寸时,是否对图片进行缩放)等。