|
I have done exactly as you have said...!
But the button click event is not firing??? Any idea why?
|
|
|
|
|
|
Yes indeed there are some bugs in the code. One that had me scratching my head was why the button did not fire the click event. Looking at the code, you can see that the OnMouseUp override calls base.OnMouseDown instead of base.OnMouseUp. Once that was changed, it all worked as expected.
There are, as other comments have suggested, some resource leaks in the code. A judicious sprinkling of 'using' or try/finally/dispose statements throughout the code fixes that.
While there might be sexier looking implementations, this was perfect for me, just looking to add a circular button to my own project without having to go down the rabbit hole of putting it together myself.
Perhaps the haters out there should be a bit kinder to someone who took the time to post something that others can find useful, even if it requires some tweaking. It's a lot easier to criticize womeone else's work than to be a contributor, it seems.
|
|
|
|
|
There is a type (bug) in the last line in the OnMouseUp method. Otherwise, works great.
|
|
|
|
|
How to change the code to make the button with only one rounded corner?
|
|
|
|
|
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace MySensors.Controls
{
public partial class ButtonRoundElliptical : Button
{
public bool IsMouseOver { get; private set; }
private bool IsMouseDown { get; set; }
private int border_radius = 0;
private Color border_over_color;
private Color border_down_color;
private float border_over_width = 0;
private float border_down_width = 0;
private Color backColorGradient1 = System.Drawing.SystemColors.Control;
private Color backColorGradient2 = System.Drawing.SystemColors.Control;
private Color backColorMouseOverGradient1 = System.Drawing.SystemColors.Control;
private Color backColorMouseOverGradient2 = System.Drawing.SystemColors.Control;
private Color backColorMouseDownGradient1 = System.Drawing.SystemColors.Control;
private Color backColorMouseDownGradient2 = System.Drawing.SystemColors.Control;
#region BorderWidth
[Category("Border"), DisplayName("Border Width")]
public float BorderWidth
{
get
{
return FlatAppearance.BorderSize;
}
set
{
if (FlatAppearance.BorderSize == value) return;
FlatAppearance.BorderSize = Convert.ToInt32(value);
Invalidate();
}
}
[Category("Border"), DisplayName("Border MouseOver Width")]
public float BorderOverWidth
{
get
{
return border_over_width;
}
set
{
if (border_over_width == value) return;
border_over_width = value;
Invalidate();
}
}
[Category("Border"), DisplayName("Border MouseDown Width")]
public float BorderDownWidth
{
get
{
return border_down_width;
}
set
{
if (border_down_width == value) return;
border_down_width = value;
Invalidate();
}
}
#endregion
#region BackColorGradient
[Category("BackColor"), DisplayName("BackColor Gradient1 Color")]
public Color BackColorColorGradient1
{
get { return backColorGradient1; }
set
{
if (backColorGradient1 == value) return;
backColorGradient1 = value;
Invalidate();
}
}
[Category("BackColor"), DisplayName("BackColor Gradient2 Color")]
public Color BackColorColorGradient2
{
get { return backColorGradient2; }
set
{
if (backColorGradient2 == value) return;
backColorGradient2 = value;
Invalidate();
}
}
[Category("BackColor"), DisplayName("BackColor MouseOver Gradient1 Color")]
public Color BackColorOverColorGradient1
{
get { return backColorMouseOverGradient1; }
set
{
if (backColorMouseOverGradient1 == value) return;
backColorMouseOverGradient1 = value;
Invalidate();
}
}
[Category("BackColor"), DisplayName("BackColor MouseOver Gradient2 Color")]
public Color BackColorOverColorGradient2
{
get { return backColorMouseOverGradient2; }
set
{
if (backColorMouseOverGradient2 == value) return;
backColorMouseOverGradient2 = value;
Invalidate();
}
}
[Category("BackColor"), DisplayName("BackColor Mouse Down Gradient1 Color")]
public Color BackColorDownColorGradient1
{
get { return backColorMouseDownGradient1; }
set
{
if (backColorMouseDownGradient1 == value) return;
backColorMouseDownGradient1 = value;
Invalidate();
}
}
[Category("BackColor"), DisplayName("BackColor Mouse Down Gradient2 Color")]
public Color BackColorDownColorGradient2
{
get { return backColorMouseDownGradient2; }
set
{
if (backColorMouseDownGradient2 == value) return;
backColorMouseDownGradient2 = value;
Invalidate();
}
}
#endregion
#region BorderColor
[Category("Border"), DisplayName("Border MouseOver Color")]
public Color BorderOverColor
{
get { return border_over_color; }
set
{
if (border_over_color == value) return;
border_over_color = value;
Invalidate();
}
}
[Category("Border"), DisplayName("Border MouseDown Color")]
public Color BorderDownColor
{
get { return border_down_color; }
set
{
if (border_down_color == value) return;
border_down_color = value;
Invalidate();
}
}
[Category("Border"), DisplayName("Border Color")]
public Color BorderColor
{
get { return FlatAppearance.BorderColor; }
set
{
if (FlatAppearance.BorderColor == value) return;
FlatAppearance.BorderColor = value;
Invalidate();
}
}
#endregion
[Category("Border"), DisplayName("Border Radius")]
public int BorderRadius
{
get
{
return border_radius;
}
set
{
if (border_radius == value) return;
border_radius = value;
Invalidate();
}
}
public ButtonRoundElliptical():base()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
BorderWidth = BorderDownWidth = BorderOverWidth = 2;
BackColor = FlatAppearance.MouseDownBackColor = FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control;
BorderColor = BorderDownColor = BorderOverColor = System.Drawing.SystemColors.ControlDark;
ForeColor = System.Drawing.SystemColors.ControlText;
DoubleBuffered = true;
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
RectangleF RectFButton = new RectangleF(0, 0, this.Width, this.Height);
DrawButton(e, RectFButton);
if (BorderWidth != 0 || BorderOverWidth != 0 || BorderDownWidth != 0)
{
DrawBorder(e, RectFButton);
}
DrawText(e.Graphics, RectFButton);
}
protected override void OnMouseEnter(EventArgs e)
{
IsMouseOver = true;
Invalidate();
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
IsMouseOver = false;
IsMouseDown = false;
Invalidate();
base.OnMouseHover(e);
}
protected override void OnMouseDown(MouseEventArgs mevent)
{
IsMouseDown = true;
Invalidate();
base.OnMouseDown(mevent);
}
protected override void OnMouseUp(MouseEventArgs mevent)
{
IsMouseDown = false;
Invalidate();
base.OnMouseDown(mevent);
}
private void DrawButton(PaintEventArgs e, RectangleF Rect)
{
GraphicsPath GraphPath = new GraphicsPath();
GraphPath.AddEllipse(Rect);
this.Region = new System.Drawing.Region(GraphPath);
if (IsMouseDown && !BackColorDownColorGradient1.IsEmpty && !BackColorDownColorGradient2.IsEmpty)
using (LinearGradientBrush mouseDownBrush = new LinearGradientBrush(new PointF(Rect.X, Rect.Y), new PointF(Width, Height), BackColorDownColorGradient1, BackColorDownColorGradient2))
e.Graphics.FillPath(mouseDownBrush, GraphPath);
else if (IsMouseOver && !BackColorOverColorGradient1.IsEmpty && !BackColorOverColorGradient2.IsEmpty)
using (LinearGradientBrush overBrush = new LinearGradientBrush(new PointF(Rect.X, Rect.Y), new PointF(Width, Height), BackColorOverColorGradient1, BackColorOverColorGradient2))
e.Graphics.FillPath(overBrush, GraphPath);
else
using (LinearGradientBrush linGrBrush = new LinearGradientBrush(new PointF(Rect.X, Rect.Y), new PointF(Width, Height), BackColorColorGradient1, BackColorColorGradient2))
e.Graphics.FillPath(linGrBrush, GraphPath);
}
private void DrawBorder(PaintEventArgs e, RectangleF Rect)
{
GraphicsPath GraphInnerPath = new GraphicsPath();
Pen pen;
RectangleF RectB;
if (IsMouseDown && !BorderDownColor.IsEmpty)
{
RectB = new RectangleF(Rect.X, Rect.Y, Rect.Width, Rect.Height);
using (pen = new Pen(BorderDownColor, BorderDownWidth))
{
GraphInnerPath.AddEllipse(RectB);
pen.Alignment = PenAlignment.Inset;
if (pen.Width > 0)
e.Graphics.DrawPath(pen, GraphInnerPath);
}
}
else if (IsMouseOver && !BorderOverColor.IsEmpty)
{
RectB = new RectangleF(Rect.X, Rect.Y, Rect.Width, Rect.Height);
using (pen = new Pen(BorderOverColor, BorderOverWidth))
{
GraphInnerPath.AddEllipse(RectB);
pen.Alignment = PenAlignment.Inset;
if (pen.Width > 0)
e.Graphics.DrawPath(pen, GraphInnerPath);
}
}
else
{
RectB = new RectangleF(Rect.X, Rect.Y, Rect.Width, Rect.Height);
using (pen = new Pen(BorderColor, BorderWidth))
{
GraphInnerPath.AddEllipse(RectB);
pen.Alignment = PenAlignment.Inset;
if (pen.Width > 0)
e.Graphics.DrawPath(pen, GraphInnerPath);
}
}
}
private void DrawText(Graphics g, RectangleF Rect)
{
float r2 = BorderRadius / 2f;
float w2 = BorderWidth / 2f;
Point point = new Point();
StringFormat format = new StringFormat();
switch (TextAlign)
{
case ContentAlignment.TopLeft:
point.X = (int)(Rect.X + r2 / 2 + w2 + Padding.Left);
point.Y = (int)(Rect.Y + r2 / 2 + w2 + Padding.Top);
format.LineAlignment = StringAlignment.Center;
break;
case ContentAlignment.TopCenter:
point.X = (int)(Rect.X + Rect.Width / 2f);
point.Y = (int)(Rect.Y + r2 / 2 + w2 + Padding.Top);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
break;
case ContentAlignment.TopRight:
point.X = (int)(Rect.X + Rect.Width - r2 / 2 - w2 - Padding.Right);
point.Y = (int)(Rect.Y + r2 / 2 + w2 + Padding.Top);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Far;
break;
case ContentAlignment.MiddleLeft:
point.X = (int)(Rect.X + r2 / 2 + w2 + Padding.Left);
point.Y = (int)(Rect.Y + Rect.Height / 2);
format.LineAlignment = StringAlignment.Center;
break;
case ContentAlignment.MiddleCenter:
point.X = (int)(Rect.X + Rect.Width / 2);
point.Y = (int)(Rect.Y + Rect.Height / 2);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
break;
case ContentAlignment.MiddleRight:
point.X = (int)(Rect.X + Rect.Width - r2 / 2 - w2 - Padding.Right);
point.Y = (int)(Rect.Y + Rect.Height / 2);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Far;
break;
case ContentAlignment.BottomLeft:
point.X = (int)(Rect.X + r2 / 2 + w2 + Padding.Left);
point.Y = (int)(Rect.Y + Rect.Height - r2 / 2 - w2 - Padding.Bottom);
format.LineAlignment = StringAlignment.Center;
break;
case ContentAlignment.BottomCenter:
point.X = (int)(Rect.X + Rect.Width / 2);
point.Y = (int)(Rect.Y + Rect.Height - r2 / 2 - w2 - Padding.Bottom);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
break;
case ContentAlignment.BottomRight:
point.X = (int)(Rect.X + Rect.Width - r2 / 2 - w2 - Padding.Right);
point.Y = (int)(Rect.Y + Rect.Height - r2 / 2 - w2 - Padding.Bottom);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Far;
break;
default:
break;
}
using (Brush brush = new SolidBrush(ForeColor))
g.DrawString(Text, Font, brush, point, format);
}
}
}
han6man@gmail.com
www.mydigitalhome.co.il
|
|
|
|
|
if you want a round button or ellipse
rather than rounded corners
private void DrawButton(PaintEventArgs e, RectangleF Rect)
{
GraphicsPath GraphPath = GetRoundPath(Rect, BorderRadius);
this.Region = new Region(GraphPath);
if (IsMouseDown && !BackColorMouseDown.IsEmpty)
using (Brush mouseDownBrush = new SolidBrush(BackColorMouseDown))
e.Graphics.FillPath(mouseDownBrush, GraphPath);
else if (IsMouseOver && !BackColorMouseOver.IsEmpty)
using (Brush overBrush = new SolidBrush(BackColorMouseOver))
e.Graphics.FillPath(overBrush, GraphPath);
else
using (Brush brush = new SolidBrush(this.BackColor))
e.Graphics.FillPath(brush, GraphPath);
}
han6man@gmail.com
https://www.mydigitalhome.co.il/
|
|
|
|
|
We have
FlatAppearance.BorderSize
FlatAppearance.BorderColor
[Category("Border"),DisplayName("Border Width")]
public float BorderWidth
{
get {
return FlatAppearance.BorderSize;
}
set {
if (FlatAppearance.BorderSize == value) return;
FlatAppearance.BorderSize = Convert.ToInt32(value);
Invalidate();
}
}
[Category("Border"), DisplayName("Border Color")]
public Color BorderColor
{
get { return FlatAppearance.BorderColor; }
set
{
if (FlatAppearance.BorderColor == value) return;
FlatAppearance.BorderColor = value;
Invalidate();
}
}
For convenience added
property for
FlatAppearance.MouseDownBackColor
FlatAppearance.MouseOverBackColor
[Category("BackColor"), DisplayName("BackColor MouseDown ButtonColor")]
public Color BackColorMouseDown
{
get { return FlatAppearance.MouseDownBackColor; }
set
{
if (FlatAppearance.MouseDownBackColor == value) return;
FlatAppearance.MouseDownBackColor = value;
Invalidate();
}
}
[Category("BackColor"), DisplayName("BackColor MouseOver ButtonColor")]
public Color BackColorMouseOver
{
get { return FlatAppearance.MouseOverBackColor; }
set
{
if (FlatAppearance.MouseOverBackColor == value) return;
FlatAppearance.BorderColor = value;
Invalidate();
}
}
Extracted To Metod
Extracted to method
now OnPaint
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
RectangleF Rect = new RectangleF(0, 0, this.Width, this.Height);
DrawButton(e, Rect);
DrawBorder(e, Rect);
DrawText(e.Graphics, Rect);
}
private void DrawButton(PaintEventArgs e, RectangleF Rect)
{
GraphicsPath GraphPath = GetRoundPath(Rect, BorderRadius);
this.Region = new Region(GraphPath);
if (IsMouseDown && !FlatAppearance.MouseDownBackColor.IsEmpty)
using (Brush mouseDownBrush = new SolidBrush(FlatAppearance.MouseDownBackColor))
e.Graphics.FillPath(mouseDownBrush, GraphPath);
else if (IsMouseOver && !FlatAppearance.MouseOverBackColor.IsEmpty)
using (Brush overBrush = new SolidBrush(FlatAppearance.MouseOverBackColor))
e.Graphics.FillPath(overBrush, GraphPath);
else
using (Brush brush = new SolidBrush(this.BackColor))
e.Graphics.FillPath(brush, GraphPath);
}
private void DrawBorder(PaintEventArgs e, RectangleF Rect)
{
GraphicsPath GraphInnerPath = new GraphicsPath();
Pen pen;
RectangleF RectB;
if (IsMouseDown && !BorderDownColor.IsEmpty)
{
RectB = new RectangleF(Rect.X + BorderDownWidth / 2f, Rect.Y + BorderDownWidth / 2f, Rect.Width - BorderDownWidth,
Rect.Height - BorderDownWidth);
using (pen = new Pen(BorderDownColor, BorderDownWidth))
{
GraphInnerPath.AddEllipse(RectB);
pen.Alignment = PenAlignment.Inset;
if (pen.Width > 0)
e.Graphics.DrawPath(pen, GraphInnerPath);
}
}
else if (IsMouseOver && !BorderOverColor.IsEmpty)
{
RectB = new RectangleF(Rect.X + BorderOverWidth / 2f, Rect.Y + BorderOverWidth / 2f, Rect.Width - BorderOverWidth,
Rect.Height - BorderOverWidth);
using (pen = new Pen(BorderOverColor, BorderOverWidth))
{
GraphInnerPath.AddEllipse(RectB);
pen.Alignment = PenAlignment.Inset;
if (pen.Width > 0)
e.Graphics.DrawPath(pen, GraphInnerPath);
}
}
else
{
RectB = new RectangleF(Rect.X + BorderWidth / 2f, Rect.Y + BorderWidth / 2f, Rect.Width - BorderWidth,
Rect.Height - BorderWidth);
using (pen = new Pen(BorderColor, BorderWidth))
{
GraphInnerPath.AddEllipse(RectB);
pen.Alignment = PenAlignment.Inset;
if (pen.Width > 0)
e.Graphics.DrawPath(pen, GraphInnerPath);
}
}
}
private void DrawText(Graphics g,RectangleF Rect)
{
float r2 = BorderRadius / 2f;
float w2 = BorderWidth / 2f;
Point point = new Point();
StringFormat format = new StringFormat();
switch (TextAlign)
{
case ContentAlignment.TopLeft:
point.X = (int)(Rect.X + r2/2 + w2 + Padding.Left);
point.Y = (int)(Rect.Y + r2/2 + w2 + Padding.Top);
format.LineAlignment = StringAlignment.Center;
break;
case ContentAlignment.TopCenter:
point.X = (int)(Rect.X + Rect.Width/2f);
point.Y = (int)(Rect.Y + r2/2 + w2 + Padding.Top);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
break;
case ContentAlignment.TopRight:
point.X = (int)(Rect.X + Rect.Width - r2/2 - w2 - Padding.Right);
point.Y = (int)(Rect.Y + r2 / 2 + w2 + Padding.Top);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Far;
break;
case ContentAlignment.MiddleLeft:
point.X = (int)(Rect.X + r2 / 2 + w2 + Padding.Left);
point.Y = (int)(Rect.Y + Rect.Height/2);
format.LineAlignment = StringAlignment.Center;
break;
case ContentAlignment.MiddleCenter:
point.X = (int)(Rect.X +Rect.Width / 2);
point.Y = (int)(Rect.Y + Rect.Height / 2);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
break;
case ContentAlignment.MiddleRight:
point.X = (int)(Rect.X + Rect.Width - r2 / 2 - w2 - Padding.Right);
point.Y = (int)(Rect.Y + Rect.Height / 2);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Far;
break;
case ContentAlignment.BottomLeft:
point.X = (int)(Rect.X + r2 / 2 + w2 + Padding.Left);
point.Y = (int)(Rect.Y + Rect.Height - r2 / 2 - w2 - Padding.Bottom);
format.LineAlignment = StringAlignment.Center;
break;
case ContentAlignment.BottomCenter:
point.X = (int)(Rect.X + Rect.Width/2);
point.Y = (int)(Rect.Y + Rect.Height - r2 / 2 - w2 - Padding.Bottom);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
break;
case ContentAlignment.BottomRight:
point.X = (int)(Rect.X + Rect.Width - r2 / 2 - w2 - Padding.Right);
point.Y = (int)(Rect.Y + Rect.Height - r2 / 2 - w2 - Padding.Bottom);
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Far;
break;
default:
break;
}
using (Brush brush = new SolidBrush(ForeColor))
g.DrawString(Text, Font, brush, point, format);
}
Added constractor withoun we haw sum problems on init
public RoundedButton():base()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
BorderWidth = BorderDownWidth = BorderOverWidth = 2;
BackColor = BackColorMouseDown = BackColorMouseOver = System.Drawing.SystemColors.Control;
BorderColor = BorderDownColor = BorderOverColor = System.Drawing.SystemColors.ControlDark;
ForeColor = System.Drawing.SystemColors.ControlText;
DoubleBuffered = true;
}
For myself, I also added a gradient fill.
han6man@gmail.com
https://www.mydigitalhome.co.il
modified 10-Apr-20 13:12pm.
|
|
|
|
|
Not sure if this is a bug but when navigating between navigation tree items, the button is sometimes overlayed with the application's header image.
Border also doesn't completely surround the button. (The fill "spills over" e.g. The border is inside the rectangle instead of outside it)
|
|
|
|
|
need to set colors and sizes
or add a constructor to the class
|
|
|
|
|
In my opinion there are many and better articles about round/glass buttons and other round/shape controls with pretty cool effects.
And you are leaking memory by not disposing, especially in paint events you should be very careful.
Read some articles about GDI (GDI+ tutorial for beginners) and by experimenting you could create much nicer buttons with glossy shining effects.
|
|
|
|
|
I agree with you that the Control is not sensational - but it is a guideline to create such Controls - so there is no reason to downvote this article in this way ... my opinion ...
|
|
|
|
|
According to me a 'guideline' should be correct and not having memory leaks or bad code. Other said, in production environments this code is potentially dangerous and could get the application in unexpected states.
See the down vote as a warning to readers of this article to not use this code as a guideline.
modified 31-Jan-19 7:01am.
|
|
|
|
|
I'm not the author of this article (please take a look above) - I'm "only" another member of this forum - like you ...
|
|
|
|
|
The Best Base Option I've Found
|
|
|
|
|
|