先看效果:
如图,上面使用了LinearGradientBrush。从而让GroupBox显得更为个性化。
再看源码:
using CommonUtils.Controls.GroupControls;
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Collections.Generic;
namespace CommonUtils.Controls.GroupBoxControls
{
/// <summary>A special custom rounding GroupBox with many painting features.</summary>
[ToolboxBitmap(typeof(LinearGradientGrouper), "MyControls.Grouper.bmp")]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public class LinearGradientGrouper : UserControl
{
#region Variables
private System.ComponentModel.Container components = null;
private int _RoundCorners = 10;
private string _GroupTitle = "The Grouper";
private Color _BorderColor = Color.Black;
private float _BorderThickness = 1;
private bool _ShadowControl = false;
private Color _BackgroundColor = Color.White;
private Color _BackgroundGradientColor = Color.White;
private GroupBoxGradientMode _BackgroundGradientMode = GroupBoxGradientMode.None;
private Color _ShadowColor = Color.DarkGray;
private int _ShadowThickness = 3;
private Image _GroupImage = null;
private Color _CustomGroupBoxColor = Color.White;
private bool _PaintGroupBox = false;
private Color _BackColor = Color.Transparent;
Color[] colors = new Color[] { Color.Red, Color.OrangeRed, Color.DarkRed, Color.DarkGoldenrod, Color.Orange, Color.Yellow, Color.White };
#endregion
#region Constructor
/// <summary>This method will construct a new GroupBox control.</summary>
public LinearGradientGrouper()
{
InitializeStyles();
InitializeGroupBox();
}
#region Initialization
/// <summary>This method will initialize the controls custom styles.</summary>
private void InitializeStyles()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
/// <summary>This method will initialize the GroupBox control.</summary>
private void InitializeGroupBox()
{
components = new System.ComponentModel.Container();
this.Resize += new EventHandler(GroupBox_Resize);
this.DockPadding.All = 20;
this.Name = "GroupBox";
this.Size = new System.Drawing.Size(368, 288);
}
#endregion Initialization
#endregion Constructor
#region Properties
/// <summary>This feature will paint the background color of the control.</summary>
[Category("Appearance"), Description("This feature will paint the background color of the control.")]
public override Color BackColor
{
get { return _BackColor; }
set { _BackColor = value; this.Refresh(); }
}
/// <summary>This feature will paint the group title background to the specified color if PaintGroupBox is set to true.</summary>
[Category("Appearance"), Description("This feature will paint the group title background to the specified color if PaintGroupBox is set to true.")]
public Color CustomGroupBoxColor
{
get { return _CustomGroupBoxColor; }
set { _CustomGroupBoxColor = value; this.Refresh(); }
}
/// <summary>This feature will paint the group title background to the CustomGroupBoxColor.</summary>
[Category("Appearance"), Description("This feature will paint the group title background to the CustomGroupBoxColor.")]
public bool PaintGroupBox
{
get { return _PaintGroupBox; }
set { _PaintGroupBox = value; this.Refresh(); }
}
/// <summary>This feature can add a 16 x 16 image to the group title bar.</summary>
[Category("Appearance"), Description("This feature can add a 16 x 16 image to the group title bar.")]
public Image GroupImage
{
get { return _GroupImage; }
set { _GroupImage = value; this.Refresh(); }
}
/// <summary>This feature will change the control's shadow color.</summary>
[Category("Appearance"), Description("This feature will change the control's shadow color.")]
public Color ShadowColor
{
get { return _ShadowColor; }
set { _ShadowColor = value; this.Refresh(); }
}
/// <summary>This feature will change the size of the shadow border.</summary>
[Category("Appearance"), Description("This feature will change the size of the shadow border.")]
public int ShadowThickness
{
get { return _ShadowThickness; }
set
{
if (value > 10)
_ShadowThickness = 10;
else
_ShadowThickness = (value < 1) ? 1 : value;
this.Refresh();
}
}
/// <summary>This feature will change the group control color. This color can also be used in combination with BackgroundGradientColor for a gradient paint.</summary>
[Category("Appearance"), Description("This feature will change the group control color. This color can also be used in combination with BackgroundGradientColor for a gradient paint.")]
public Color BackgroundColor
{
get { return _BackgroundColor; }
set { _BackgroundColor = value; this.Refresh(); }
}
/// <summary>This feature can be used in combination with BackgroundColor to create a gradient background.</summary>
[Category("Appearance"), Description("This feature can be used in combination with BackgroundColor to create a gradient background.")]
public Color BackgroundGradientColor
{
get { return _BackgroundGradientColor; }
set { _BackgroundGradientColor = value; this.Refresh(); }
}
/// <summary>This feature turns on background gradient painting.</summary>
[Category("Appearance"), Description("This feature turns on background gradient painting.")]
public GroupBoxGradientMode BackgroundGradientMode
{
get { return _BackgroundGradientMode; }
set { _BackgroundGradientMode = value; this.Refresh(); }
}
/// <summary>This feature will round the corners of the control.</summary>
[Category("Appearance"), Description("This feature will round the corners of the control.")]
public int RoundCorners
{
get { return _RoundCorners; }
set
{
if (value > 25)
_RoundCorners = 25;
else
_RoundCorners = (value < 1) ? 1 : value;
this.Refresh();
}
}
/// <summary>This feature will add a group title to the control.</summary>
[Category("Appearance"), Description("This feature will add a group title to the control.")]
public string GroupTitle
{
get { return _GroupTitle; }
set { _GroupTitle = value; this.Refresh(); }
}
/// <summary>This feature will allow you to change the color of the control's border.</summary>
[Category("Appearance"), Description("This feature will allow you to change the color of the control's border.")]
public Color BorderColor
{
get { return _BorderColor; }
set { _BorderColor = value; this.Refresh(); }
}
/// <summary>This feature will allow you to set the control's border size.</summary>
[Category("Appearance"), Description("This feature will allow you to set the control's border size.")]
public float BorderThickness
{
get { return _BorderThickness; }
set
{
if (value > 3)
_BorderThickness = 3;
else
_BorderThickness = (value < 1) ? 1 : value;
this.Refresh();
}
}
/// <summary>This feature will allow you to turn on control shadowing.</summary>
[Category("Appearance"), Description("This feature will allow you to turn on control shadowing.")]
public bool ShadowControl
{
get { return _ShadowControl; }
set { _ShadowControl = value; this.Refresh(); }
}
#endregion
#region DeConstructor
/// <summary>This method will dispose of the GroupBox control.</summary>
protected override void Dispose(bool disposing)
{
if (disposing) { if (components != null) { components.Dispose(); } }
base.Dispose(disposing);
}
#endregion
#region Protected Methods
/// <summary>Overrides the OnPaint method to paint control.</summary>
/// <param name="e">The paint event arguments.</param>
protected override void OnPaint(PaintEventArgs e)
{
PaintBack(e.Graphics);
PaintGroupText(e.Graphics);
}
#endregion
#region Private Methods
/// <summary>This method will paint the group title.</summary>
/// <param name="g">The paint event graphics object.</param>
private void PaintGroupText(System.Drawing.Graphics g)
{
if (this.GroupTitle == string.Empty) { return; }
g.SmoothingMode = SmoothingMode.AntiAlias;
SizeF StringSize = g.MeasureString(this.GroupTitle, this.Font);
Size StringSize2 = StringSize.ToSize();
if (this.GroupImage != null) { StringSize2.Width += 18; }
int ArcWidth = this.RoundCorners;
int ArcHeight = this.RoundCorners;
int ArcX1 = 20;
int ArcX2 = (StringSize2.Width + 34) - (ArcWidth + 1);
int ArcY1 = 0;
int ArcY2 = 24 - (ArcHeight + 1);
GraphicsPath path = new GraphicsPath();
Brush BorderBrush = new SolidBrush(this.BorderColor);
Pen BorderPen = new Pen(BorderBrush, this.BorderThickness);
Brush BackgroundBrush = (this.PaintGroupBox) ? new SolidBrush(this.CustomGroupBoxColor) : new SolidBrush(this.BackgroundColor);
SolidBrush TextColorBrush = new SolidBrush(this.ForeColor);
SolidBrush ShadowBrush = null;
GraphicsPath ShadowPath = null;
if (this.ShadowControl)
{
ShadowBrush = new SolidBrush(this.ShadowColor);
ShadowPath = new GraphicsPath();
ShadowPath.AddArc(ArcX1 + (this.ShadowThickness - 1), ArcY1 + (this.ShadowThickness - 1), ArcWidth, ArcHeight, 180, GroupBoxConstants.SweepAngle); // Top Left
ShadowPath.AddArc(ArcX2 + (this.ShadowThickness - 1), ArcY1 + (this.ShadowThickness - 1), ArcWidth, ArcHeight, 270, GroupBoxConstants.SweepAngle); //Top Right
ShadowPath.AddArc(ArcX2 + (this.ShadowThickness - 1), ArcY2 + (this.ShadowThickness - 1), ArcWidth, ArcHeight, 360, GroupBoxConstants.SweepAngle); //Bottom Right
ShadowPath.AddArc(ArcX1 + (this.ShadowThickness - 1), ArcY2 + (this.ShadowThickness - 1), ArcWidth, ArcHeight, 90, GroupBoxConstants.SweepAngle); //Bottom Left
ShadowPath.CloseAllFigures();
g.FillPath(ShadowBrush, ShadowPath);
}
path.AddArc(ArcX1, ArcY1, ArcWidth, ArcHeight, 180, GroupBoxConstants.SweepAngle); // Top Left
path.AddArc(ArcX2, ArcY1, ArcWidth, ArcHeight, 270, GroupBoxConstants.SweepAngle); //Top Right
path.AddArc(ArcX2, ArcY2, ArcWidth, ArcHeight, 360, GroupBoxConstants.SweepAngle); //Bottom Right
path.AddArc(ArcX1, ArcY2, ArcWidth, ArcHeight, 90, GroupBoxConstants.SweepAngle); //Bottom Left
path.CloseAllFigures();
if (!this.PaintGroupBox)
g.FillPath(BackgroundBrush, path);
else
{
if (this.BackgroundGradientMode == GroupBoxGradientMode.None)
g.FillPath(BackgroundBrush, path);
else
{
RectangleF rectF = path.GetBounds();
LinearGradientBrush lgb = new LinearGradientBrush(rectF,
this.BackgroundColor, this.BackgroundGradientColor,
(LinearGradientMode)this.BackgroundGradientMode);
ColorBlend cb = new ColorBlend();
List<Color> colorList = new List<Color>();
foreach (Color color in colors)
{
colorList.Add(ControlPaint.Light(color, 0.68f));
}
colorList.Reverse();
Color[] groupTitleColors = colorList.ToArray();
cb.Colors = groupTitleColors;
cb.Positions = new float[] { 0.0f, 0.1f, .25f, .4f, .8f, .9f, 1.0f };
lgb.InterpolationColors = cb;
g.FillPath(lgb, path);
}
}
g.DrawPath(BorderPen, path);
int CustomStringWidth = (this.GroupImage != null) ? 44 : 28;
g.DrawString(this.GroupTitle, this.Font, TextColorBrush, CustomStringWidth, 5);
if (this.GroupImage != null)
g.DrawImage(this.GroupImage, 28, 4, 16, 16);
if (path != null) { path.Dispose(); }
if (BorderBrush != null) { BorderBrush.Dispose(); }
if (BorderPen != null) { BorderPen.Dispose(); }
if (BackgroundBrush != null) { BackgroundBrush.Dispose(); }
if (TextColorBrush != null) { TextColorBrush.Dispose(); }
if (ShadowBrush != null) { ShadowBrush.Dispose(); }
if (ShadowPath != null) { ShadowPath.Dispose(); }
}
/// <summary>This method will paint the control.</summary>
/// <param name="g">The paint event graphics object.</param>
private void PaintBack(Graphics g)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
int ArcWidth = this.RoundCorners * 2;
int ArcHeight = this.RoundCorners * 2;
int ArcX1 = 0;
int ArcX2 = (this.ShadowControl) ? (this.Width - (ArcWidth + 1)) - this.ShadowThickness : this.Width - (ArcWidth + 1);
int ArcY1 = 10;
int ArcY2 = (this.ShadowControl) ? (this.Height - (ArcHeight + 1)) - this.ShadowThickness : this.Height - (ArcHeight + 1);
GraphicsPath path = new GraphicsPath();
Brush BorderBrush = new SolidBrush(this.BorderColor);
Pen BorderPen = new Pen(BorderBrush, this.BorderThickness);
Brush BackgroundBrush = new SolidBrush(this.BackgroundColor);
SolidBrush ShadowBrush = null;
GraphicsPath ShadowPath = null;
if (this.ShadowControl)
{
ShadowBrush = new SolidBrush(this.ShadowColor);
ShadowPath = new GraphicsPath();
ShadowPath.AddArc(ArcX1 + this.ShadowThickness, ArcY1 + this.ShadowThickness, ArcWidth, ArcHeight, 180, GroupBoxConstants.SweepAngle); // Top Left
ShadowPath.AddArc(ArcX2 + this.ShadowThickness, ArcY1 + this.ShadowThickness, ArcWidth, ArcHeight, 270, GroupBoxConstants.SweepAngle); //Top Right
ShadowPath.AddArc(ArcX2 + this.ShadowThickness, ArcY2 + this.ShadowThickness, ArcWidth, ArcHeight, 360, GroupBoxConstants.SweepAngle); //Bottom Right
ShadowPath.AddArc(ArcX1 + this.ShadowThickness, ArcY2 + this.ShadowThickness, ArcWidth, ArcHeight, 90, GroupBoxConstants.SweepAngle); //Bottom Left
ShadowPath.CloseAllFigures();
g.FillPath(ShadowBrush, ShadowPath);
}
path.AddArc(ArcX1, ArcY1, ArcWidth, ArcHeight, 180, GroupBoxConstants.SweepAngle); // Top Left
path.AddArc(ArcX2, ArcY1, ArcWidth, ArcHeight, 270, GroupBoxConstants.SweepAngle); //Top Right
path.AddArc(ArcX2, ArcY2, ArcWidth, ArcHeight, 360, GroupBoxConstants.SweepAngle); //Bottom Right
path.AddArc(ArcX1, ArcY2, ArcWidth, ArcHeight, 90, GroupBoxConstants.SweepAngle); //Bottom Left
path.CloseAllFigures();
if (this.BackgroundGradientMode == GroupBoxGradientMode.None)
g.FillPath(BackgroundBrush, path);
else
{
LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0, 0, this.Width, this.Height),
this.BackgroundColor, this.BackgroundGradientColor,
(LinearGradientMode)this.BackgroundGradientMode);
ColorBlend cb = new ColorBlend();
cb.Colors = colors;
cb.Positions = new float[] { 0.0f, 0.1f, .25f, .4f, .68f, .86f, 1.0f };
lgb.InterpolationColors = cb;
g.FillPath(lgb, path);
}
g.DrawPath(BorderPen, path);
if (path != null) { path.Dispose(); }
if (BorderBrush != null) { BorderBrush.Dispose(); }
if (BorderPen != null) { BorderPen.Dispose(); }
if (BackgroundBrush != null) { BackgroundBrush.Dispose(); }
if (ShadowBrush != null) { ShadowBrush.Dispose(); }
if (ShadowPath != null) { ShadowPath.Dispose(); }
}
/// <summary>This method fires when the GroupBox resize event occurs.</summary>
/// <param name="sender">The object the sent the event.</param>
/// <param name="e">The event arguments.</param>
private void GroupBox_Resize(object sender, EventArgs e)
{
this.Refresh();
}
#endregion
}
}
其他辅助代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CommonUtils.Controls.GroupBoxControls
{
/// <summary>A special gradient enumeration.</summary>
public enum GroupBoxGradientMode
{
/// <summary>Specifies no gradient mode.</summary>
None = -1,
/// <summary>Specifies a gradient from upper right to lower left.</summary>
BackwardDiagonal = 3,
/// <summary>Specifies a gradient from upper left to lower right.</summary>
ForwardDiagonal = 2,
/// <summary>Specifies a gradient from left to right.</summary>
Horizontal = 0,
/// <summary>Specifies a gradient from top to bottom.</summary>
Vertical = 1
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CommonUtils.Controls.GroupControls
{
/// <summary>This class holds all GroupBox constants.</summary>
public class GroupBoxConstants
{
/// <summary>The sweep angle of the arc.</summary>
public const int SweepAngle = 90;
/// <summary>The minimum control height.</summary>
public const int MinControlHeight = 32;
/// <summary>The minimum control width.</summary>
public const int MinControlWidth = 96;
}
}
OK.