继续前一节的内容,本节将介绍自定义Button控件。代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace JFormControl
{
public class JControlBase:Control
{
public JControlBase() : base()
{
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0085 || m.Msg == 0x000F || m.Msg == 0x0007 || m.Msg == 0x0005)
{
Invalidate();
}
base.WndProc(ref m);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.ComponentModel;
namespace JFormControl
{
public class JButton:JControlBase
{
private int edgeWidth = 0;
public struct Angle
{
public const float Up = 50F;
public const float Down = Angle.Up + 180F;
public const float Defualt = 60F;
}
public JButton()
{
}
#region EllipseAlign
private ControlEllipseAlign eAlignt = ControlEllipseAlign.Right;
/// <summary>
/// 设置椭圆方向
/// </summary>
[Browsable(true),Category("杂项"),Description("获取和设置椭圆的方向")]
public ControlEllipseAlign EllipseAlign
{
set
{
if(eAlignt!=value)
{
eAlignt = value;
Invalidate();
}
}
get
{
return this.eAlignt;
}
}
#endregion
#region EllipseAngle
private float fAngle=.0f;
/// <summary>
/// 获取和设置椭圆幅度
/// </summary>
[Browsable(true), Category("杂项"), Description("获取和设置椭圆幅度")]
public float EllipseAngle
{
set
{
this.fAngle = value;
}
get
{
return this.fAngle;
}
}
#endregion
#region RecessDepth
private int iRecessDepth = 0;
public int RecessDepth
{
set
{
this.iRecessDepth = value;
Invalidate();
}
get
{
return this.iRecessDepth;
}
}
#endregion
#region lightAngle
private float lightAngle = Angle.Defualt;
public float LightAngle
{
set
{
this.lightAngle = value;
Invalidate();
}
get
{
return this.lightAngle;
}
}
#endregion
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rect = this.ClientRectangle;
edgeWidth = GetEdgeWidth(rect);
Graphics g = e.Graphics;
//画背景色
FillBackColor(e.Graphics, rect);
g.SmoothingMode = SmoothingMode.AntiAlias;
//
if (RecessDepth > 0)
{
DrawRecess(g, ref rect);
}
DrawEdges(g, ref rect);
}
#region FillBackColor
private void FillBackColor(Graphics g, Rectangle rect)
{
SolidBrush sBrush = new SolidBrush(this.Parent.BackColor);
rect.Inflate(1, 1);
g.FillRectangle(sBrush, rect);
sBrush.Dispose();
}
#endregion
#region DrawRecess
protected virtual void DrawRecess(Graphics g, ref Rectangle recessRect)
{
LinearGradientBrush recessBrush = new LinearGradientBrush(recessRect,
ControlPaint.Dark(Parent.BackColor),
ControlPaint.LightLight(Parent.BackColor),
GetLightAngle(Angle.Up));
Blend recessBlend = new Blend();
recessBlend.Positions = new float[] { 0.0f, .2f, .4f, .6f, .8f, 1.0f };
recessBlend.Factors = new float[] { .2f, .2f, .4f, .4f, 1f, 1f };
recessBrush.Blend = recessBlend;
Rectangle rect2 = recessRect;
ShrinkShape(ref rect2, 1);
GraphicsPath gPath = CreateGraphicsPath(rect2);
g.FillPath(recessBrush, gPath);
recessBrush.Dispose();
gPath.Dispose();
ShrinkShape(ref recessRect, iRecessDepth);
}
#endregion
#region DrawEdges
protected virtual void DrawEdges(Graphics g, ref Rectangle edgeRect)
{
ShrinkShape( ref edgeRect, 1);
Rectangle lgbRect = edgeRect;
lgbRect.Inflate(1, 1);
LinearGradientBrush edgeBrush = new LinearGradientBrush(lgbRect,
ControlPaint.LightLight(BackColor),
ControlPaint.DarkDark(BackColor),
GetLightAngle(lightAngle));
// Blend colours for realism
Blend edgeBlend = new Blend();
edgeBlend.Positions = new float[] { 0.0f, .2f, .4f, .6f, .8f, 1.0f };
edgeBlend.Factors = new float[] { .0f, .0f, .2f, .4f, 1f, 1f };
edgeBrush.Blend = edgeBlend;
GraphicsPath gPath = CreateGraphicsPath(lgbRect);
g.FillPath(edgeBrush, gPath);
edgeBrush.Dispose();
gPath.Dispose();
ShrinkShape(ref edgeRect, edgeWidth);
}
#endregion
#region Method
protected float GetLightAngle(float angle)
{
float f = 1 - (float)this.Width / this.Height; // Calculate proportions of button
float a = angle - (15 * f); // Move virtual light source accordingly
return a;
}
private void ShrinkShape(ref Rectangle rect, int amount)
{
rect.Inflate(-amount, -amount);
}
protected int GetEdgeWidth(Rectangle rect)
{
if (rect.Width < 50 | rect.Height < 50) return 1;
else return 2;
}
#endregion
#region CreateGraphicsPath
/// <summary>
/// 创建控件路径
/// </summary>
/// <param name="r"></param>
/// <returns></returns>
private GraphicsPath CreateGraphicsPath(Rectangle r)
{
float x0 = (float)r.X;
float y0 = (float)r.Y;
float width = (float)r.Width / 10;
float height = (float)r.Height;
float x1 = (float)(x0 + width * 9);
float y1 = (float)(y0 + height);
GraphicsPath gPaths = new GraphicsPath();
switch (this.eAlignt)
{
case ControlEllipseAlign.Right:
gPaths.AddBezier(x0, y0, x0 + width, y0 + height / 4, x0 + width, y0 + height / 4 * 3, x0, y1);
gPaths.AddLine(x0, y0, x1, y0);
gPaths.AddBezier(x1, y0, x1 + width, y0 + height / 4, x1 + width, y0 + height / 4 * 3, x1, y1);
gPaths.AddLine(x1, y1, x0, y1);
break;
case ControlEllipseAlign.Left:
x1 = (float)(x0 + r.Width);
x0 = x0 + width ;
gPaths.AddBezier(x0, y0, x0 - width, y0 + height / 4, x0 - width, y0 + height / 4 * 3, x0, y1);
gPaths.AddLine(x0 , y0, x1, y0);
gPaths.AddBezier(x1, y0, x1 - width, y0 + height / 4, x1 - width, y0 + height / 4 * 3, x1, y1);
gPaths.AddLine(x1, y1, x0 , y1);
break;
}
gPaths.CloseFigure();
return gPaths;
}
#endregion
}
/// <summary>
/// 设置控件椭圆方向
/// </summary>
public enum ControlEllipseAlign:short
{
Right=0,
Left,
}
}
运行结果:
主要的方法在于创建控件路径和填充的角度。