创建ImageButton自定义控件

*本文大部分都参考了MSDN的文章,非原创

在创建自行绘制的控件时,应从 System.Windows.Forms.Control 中派生,并覆盖 OnPaintOnPaintBackground 事件。 下面是一个最简单的例子:
 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

当然,现在这个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, 00, imageRect, GraphicsUnit.Pixel);

    
//从内存位图绘制
    e.Graphics.DrawImage(imageBuffer, 00);

    
base.OnPaint(e);
}
在上面的代码中,我们通过调用 Graphics 类的静态 FromImage 方法在与我们的控件大小相同的空位图中创建了一个 Graphics 对象。我们在内存中的 Graphics 对象上进行所有的绘图,完成后,将整个准备好的位图覆盖到控件的图形上即可。源代码如下:
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(100100);
            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, 00);

            
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(00);
}
然后使用ImageAttributes类的public void SetColorKey(Color colorLow, Color colorHigh) 方法设置透明键值,此方法设置高低颜色键值,以便颜色范围可以成为透明的。对于任何颜色,只要它的三种颜色成分(红、绿、蓝)都处于高低颜色键的对应成分之间,它的颜色就会成为透明的。在使用该类首先要添加如下命名空间:
using System.Drawing.Imaging;
要使用该方法,将上面的红颜色代码改为如下即可:
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorKey(ImageBackColor(
this.Image), ImageBackColor(this.Image));

gBuffer.DrawImage(
this.Image, imageRect, 00this.Image.Width, this.Image.Height, GraphicsUnit.Pixel,imageAttr);

这只是一个示例,还有很多不足之处,读者可以自己对其进行扩展,如加入Attributes的支持、为图片在控件中的陈现提供不同的方式(如当图片大于控件的尺寸时,是否对图片进行缩放)等。


posted on 2006-07-17 15:44  Nihgwu  阅读(960)  评论(1编辑  收藏  举报