1.直接使用编译好的PicButton.dll在项目中添加引用,在"工具栏"--右键--选择项--.NET Framework 组件--浏览--找到PicButton添加--PicButton图片按钮在工具栏中
2.在项目中编辑PicButton项目,其实上边方法的dll文件 就是在这里编译出来的具体实现方法:
1.在项目中在重新新建一个项目(添加类库),如下图中PicButton类库
添加完后:
添加引用,并编辑class1.cs,如下:
class1.cs修改后如下,当把class1修改为继承Control时,注意到Class1的文件标志发生了变化:
然后生成项目,可以看到在窗口上看到Class1控件(也可以根据需要改成自己喜欢的名字),将其添加到窗体上改写
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace PicButton
{
public class Class1:Control
{
//私有成员
private Image imageOri, imageHover;
//表示按下状态的标记
private bool bPushed, bHovered;
//缓冲位图
private Bitmap m_bmpOffscreen;
//是否自动调整控件大小,以适合不同大小的图片
private bool bAutoSetSize;
public Class1():base()
{
bPushed = false;
bHovered = false;
bAutoSetSize = true;
}
[Description("默认的的图片,大小应与ImageHover一致"), Category("自定义")]
public Image ImageOri
{
get
{
return imageOri;
}
set
{ imageOri = value;
if (bAutoSetSize)
SetSizeToImage(value);
this.Invalidate();
}
}
[Description("鼠标悬停时的图片,大小应与ImageOriginal一致"), Category("自定义")]
public Image ImageHover
{
get
{ return imageHover;
}
set
{ imageHover = value;
if (bAutoSetSize)
SetSizeToImage(value);
this.Invalidate();
}
}
[Description("是否自动调整以适应ImageOri的大小"), Category("自定义")]
public bool AutoSetSize
{ get
{ return bAutoSetSize;
}
set
{
bAutoSetSize = value;
if (bAutoSetSize)
{
SetSizeToImage(this.imageOri);
}
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//不执行任何操作
}
protected override void OnClick(EventArgs e)
{
//触发Click事件前更新UI,避免事件处理完毕才响应UI
this.bPushed = false;
this.bHovered = true;
this.Refresh();
base.OnClick(e);
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
Graphics gxOff; //屏幕外的图像
Rectangle imgRect; //图像矩形
if (imageOri == null)
{
e.Graphics.Clear(this.BackColor);
return;
}
if (m_bmpOffscreen == null) //要双缓冲的位图
{//见OnResize方法
m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);
}
gxOff = Graphics.FromImage(m_bmpOffscreen);
gxOff.Clear(Parent.BackColor);
ImageAttributes imageAttr = new ImageAttributes();
Image imageNow = imageOri;
//将图像相对于控件居中
imgRect = new Rectangle((this.Width - imageNow.Width) / 2, (this.Height - imageNow.Height) / 2,
imageNow.Width, imageNow.Height);
if (this.Enabled && bPushed && imageHover != null)
{
imageNow = imageHover;
imgRect = new Rectangle((this.Width - imageNow.Width) / 2, (this.Height - imageNow.Height) / 2,
imageNow.Width, imageNow.Height);
imgRect.Offset(1, 1);
}
else if (this.Enabled && bHovered && imageHover != null)
{
imageNow = imageHover;
}
imageAttr.SetColorKey(BackgroundImageColor(imageNow), BackgroundImageColor(imageNow));
//如果不可用,使用变换办法,将当前图象变换为灰度
if (!this.Enabled)
GetColorTrans(imageAttr);
//绘制图像
gxOff.DrawImage(imageNow, imgRect, 0, 0, imageNow.Width, imageNow.Height, GraphicsUnit.Pixel, imageAttr);
//从内存位图绘制
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
gxOff.Dispose();
gxOff = null;
}
private void SetSizeToImage(Image img)
{
if (img != null)
{
System.Drawing.Rectangle r = new Rectangle(0, 0, img.Width, img.Height);
r.Inflate(2, 2);
this.Width = r.Width;
this.Height = r.Height;
}
}
private Color BackgroundImageColor(Image image)
{
Bitmap bmp = new Bitmap(image);
return bmp.GetPixel(0, 0);
}
private void GetColorTrans(ImageAttributes imageAttributes)
{
//将当前r,g,b彩色分量按公式grey = r * 0.39 + g * 0.50 + b * 0.11进行变换
//注意是 r=grey,g=grey,b=grey
float[][] colorMatrixElements = {
new float[] {0.39f, 0.39f, 0.39f, 0, 0}, // red scaling factor of 2
new float[] {0.50f, 0.50f, 0.50f, 0, 0}, // green scaling factor of 1
new float[] {0.11f, 0.11f, 0.11f, 0, 0}, // blue scaling factor of 1
new float[] {0, 0, 0, 1, 0}, // alpha scaling factor of 1
new float[] {0, 0, 0, 0, 1}}; // three translations of 0.2
ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
imageAttributes.SetColorMatrix(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
}
public new bool Enabled
{
get { return base.Enabled; }
set
{
base.Enabled = value;
this.Invalidate();
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
bHovered = true;
this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
bHovered = false;
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{//鼠标处于按下状态时移到客户区之外仍会接收Move消息,但不会接收Leave消息
//因此需要在Move消息中判断当前鼠标是否在客户区内,并触发相应的OnMouseLeave或OnMouseEnter
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left)
{
if (!this.ClientRectangle.Contains(e.X, e.Y))
{//鼠标处于按下状态时从客户区内移到客户区之外时,模拟OnMouseLeave
if (this.bHovered)
{
this.bPushed = false;
OnMouseLeave(EventArgs.Empty);
}
}
else
{//鼠标处于按下状态时从客户区内移到客户区之外,再移回客户区内时,模拟OnMouseEnter,同时bPushed = true
if (!this.bHovered)
bPushed = true;
OnMouseEnter(EventArgs.Empty);
}
}//以下为增加的处理:
else
{//***模拟OnMouseEnter,参见 关于空闲处理的必要性
if (bHovered == false)
{//***收得到Move消息时鼠标也不一定是在客户区内,必须进行if (this.ClientRectangle.Contains(e.X, e.Y))判断
if (this.ClientRectangle.Contains(e.X, e.Y))
{
bHovered = true;
this.Invalidate();
}
}
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
/*重要,为节省资源,不在每次paint时都调用生成缓冲位图
* 但在大小改变时必须重新生成新的大小的m_bmpOffscreen以适应新的大小
*/
m_bmpOffscreen = null;
this.Invalidate();
}
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
bPushed = true;
this.Invalidate();
}
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{ base.OnMouseUp(e);
bPushed = false;
this.Invalidate();
}
public void PerformClick()
{
this.OnClick(EventArgs.Empty);
}
}
}