What about ‘GDI’?
Implementation Example:
#region <Round Corners> : (Properties)
// [Use Round Corners]
private bool useRoundCorners = false;
[Category("Control Corners"), DisplayName("Round Corners")]
[Description("Set Round Corners.")]
[Browsable(true)]
public bool UseRoundBorders
{
get { return useRoundCorners; }
set { if (useRoundCorners != value) { useRoundCorners = value; Invalidate(); } }
}
// [Ellipse Radius]
private int ellipseRadius = 20;
[Category("Control Corners"), DisplayName("Radius")]
[Description("Set Corner (Ellipse) Radius")]
[Browsable(true)]
public int EllipseRadius
{
get { return ellipseRadius.FixedValue(0, 90); }
set { if (ellipseRadius != value.FixedValue(0, 90)) { ellipseRadius = value; Invalidate(); } }
}
#endregion
#region <Round Corners> : (Draw)
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner-
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // width of ellipse
int nHeightEllipse // height of ellipse
);
/// <summary> Draw Corners (Round or Square). </summary>
/// <param name="e"></param>
private void DrawCorners()
{
if (useRoundCorners) { this.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, ellipseRadius, ellipseRadius)); }
else { this.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 0, 0)); }
}
#endregion
/// <summary> Redraw (Update) the Control. </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
DrawCorners();
}
Extension to Limit Round Corner Radius (*Range: 0-90)
Author: Salvador
// Extension to Set Min. & Max. Values to Properties
public static class Extensions
{
public static int FixedValue(this int value, int min, int max)
{
if (value >= min && value <= max) { return value; }
else if (value > max) { return max; }
else if (value < min) { return min; }
else { return 1; }
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
public class RoundButton : Control { public Color BackColor2 { get; set; } public Color ButtonBorderColor { get; set; } public int ButtonRoundRadius { get; set; } public Color ButtonHighlightColor { get; set; } public Color ButtonHighlightColor2 { get; set; } public Color ButtonHighlightForeColor { get; set; } public Color ButtonPressedColor { get; set; } public Color ButtonPressedColor2 { get; set; } public Color ButtonPressedForeColor { get; set; } private bool IsHighlighted; private bool IsPressed; public RoundButton() { Size = new Size(100, 40); ButtonRoundRadius = 30; BackColor = Color.Gainsboro; BackColor2 = Color.Silver; ButtonBorderColor = Color.Black; ButtonHighlightColor = Color.Orange; ButtonHighlightColor2 = Color.OrangeRed; ButtonHighlightForeColor = Color.Black; ButtonPressedColor = Color.Red; ButtonPressedColor2 = Color.Maroon; ButtonPressedForeColor = Color.White; } protected override CreateParams CreateParams { get { CreateParams createParams = base.CreateParams; createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT return createParams; } } protected override void OnPaint(PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.HighQuality; var foreColor = IsPressed ? ButtonPressedForeColor : IsHighlighted ? ButtonHighlightForeColor : ForeColor; var backColor = IsPressed ? ButtonPressedColor : IsHighlighted ? ButtonHighlightColor : BackColor; var backColor2 = IsPressed ? ButtonPressedColor2 : IsHighlighted ? ButtonHighlightColor2 : BackColor2; using (var pen = new Pen(ButtonBorderColor, 1)) e.Graphics.DrawPath(pen, Path); using (var brush = new LinearGradientBrush(ClientRectangle, backColor, backColor2, LinearGradientMode.Vertical)) e.Graphics.FillPath(brush, Path); using (var brush = new SolidBrush(foreColor)) { var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; var rect = ClientRectangle; rect.Inflate(-4, -4); e.Graphics.DrawString(Text, Font, brush, rect, sf); } base.OnPaint(e); } protected override void OnPaintBackground(PaintEventArgs e) { } protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); IsHighlighted = true; Parent.Invalidate(Bounds, false); Invalidate(); } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); IsHighlighted = false; IsPressed = false; Parent.Invalidate(Bounds, false); Invalidate(); } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); Parent.Invalidate(Bounds, false); Invalidate(); IsPressed = true; } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); Parent.Invalidate(Bounds, false); Invalidate(); IsPressed = false; } protected GraphicsPath Path { get { var rect = ClientRectangle; rect.Inflate(-1, -1); return GetRoundedRectangle(rect, ButtonRoundRadius); } } public static GraphicsPath GetRoundedRectangle(Rectangle rect, int d) { var gp = new GraphicsPath(); gp.AddArc(rect.X, rect.Y, d, d, 180, 90); gp.AddArc(rect.X + rect.Width - d, rect.Y, d, d, 270, 90); gp.AddArc(rect.X + rect.Width - d, rect.Y + rect.Height - d, d, d, 0, 90); gp.AddArc(rect.X, rect.Y + rect.Height - d, d, d, 90, 90); gp.CloseFigure(); return gp; } } |
- Remove From My Forums
-
Question
-
I have used many codes for generating Rounded Corner button. But, that are all have some issue in the edge or in the corner radius border.
I want the clean code, which should be like perfect Rounded corner edge in the button (like our mobile phone edge with descent color).
Can anybody share the sample source code with clean examples…?
-
Moved by
Tuesday, May 5, 2020 1:28 PM
Winforms related
-
Moved by
Answers
-
It was just a test to create it dynamically and see that it is anti-aliased
For a real control, you must add a Constructor without parameters
Test, to be improved =>
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(System.ComponentModel.Design.IDesigner))] public partial class RoundedUserControl : System.Windows.Forms.UserControl { private int nRadius = 20; // crash on VS 2015 //[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)] //[Description("Text for User Control"), Category("Data")] //public override string Text //{ // get { return this.Text; } // set { this.Text = value; } //} [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)] [Description("Text for User Control"), Category("Data")] public string ControlText { get { return this.Text; } set { this.Text = value; } } public int Radius { get { return nRadius; } set { nRadius = value; } } private System.Drawing.Color borderColor = System.Drawing.Color.Red; public System.Drawing.Color BorderColor { get { return borderColor; } set { borderColor = value; } } private System.Drawing.Color fillColor = System.Drawing.SystemColors.ButtonFace; public System.Drawing.Color FillColor { get { return fillColor; } set { fillColor = value; } } private System.Drawing.Color oldFillColor; protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); oldFillColor = FillColor; FillColor = System.Drawing.SystemColors.ButtonHighlight; this.Invalidate(); } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); FillColor = oldFillColor; this.Invalidate(); } private int nBorderSize = 4; public int BorderSize { get { return nBorderSize; } set { nBorderSize = value; } } public RoundedUserControl() { //InitializeComponent(); } public RoundedUserControl(int nRadius = 20, System.Drawing.Color? fillColor = null, System.Drawing.Color? borderColor = null, int borderSize = 4) : this() { Radius = nRadius; FillColor = fillColor ?? System.Drawing.SystemColors.ButtonFace; BorderColor = borderColor ?? System.Drawing.Color.Red; BorderSize = borderSize; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; nRadius = Math.Min(nRadius, Height - BorderSize * 2); Rectangle rect = new Rectangle(BorderSize, BorderSize, Width - BorderSize * 2, Height - BorderSize * 2); using (System.Drawing.Drawing2D.GraphicsPath gp = CreatePath(rect, nRadius, false)) { System.Drawing.Pen pen = new System.Drawing.Pen(BorderColor, BorderSize); pen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round; e.Graphics.FillPath(new SolidBrush(FillColor), gp); e.Graphics.DrawPath(pen, gp); } //System.Drawing.Size textSize = TextRenderer.MeasureText(this.Text, this.Font); System.Drawing.Size textSize = TextRenderer.MeasureText(this.ControlText, this.Font); var nWidth = ((this.Width - textSize.Width) / 2); var nHeight = ((this.Height - textSize.Height) / 2); System.Drawing.Point drawPoint = new System.Drawing.Point(nWidth, nHeight); Rectangle normalRect = new Rectangle(drawPoint, textSize); TextRenderer.DrawText(e.Graphics, this.Text, this.Font, normalRect, ForeColor); } public static System.Drawing.Drawing2D.GraphicsPath CreatePath(Rectangle rect, int nRadius, bool bOutline) { int nShift = bOutline ? 1 : 0; System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath(); path.AddArc(rect.X + nShift, rect.Y, nRadius, nRadius, 180f, 90f); path.AddArc((rect.Right - nRadius) - nShift, rect.Y, nRadius, nRadius, 270f, 90f); path.AddArc((rect.Right - nRadius) - nShift, (rect.Bottom - nRadius) - nShift, nRadius, nRadius, 0f, 90f); path.AddArc(rect.X + nShift, (rect.Bottom - nRadius) - nShift, nRadius, nRadius, 90f, 90f); path.CloseFigure(); return path; } }
-
Marked as answer by
Gani tpt
Tuesday, May 12, 2020 7:43 AM -
Unmarked as answer by
Gani tpt
Tuesday, May 12, 2020 11:36 AM -
Marked as answer by
Gani tpt
Wednesday, May 13, 2020 3:29 AM
-
Marked as answer by
-
You must call Invalidate() after you change the text (or
Refresh()).Text should work but as I put in comments, it crashes on my configuration (VS 2015, Windows 10)…
-
Marked as answer by
Gani tpt
Wednesday, May 13, 2020 5:22 PM
-
Marked as answer by
- Download demo (RAR) — 50.1 KB
- Download demo (ZIP) — 52.4 KB
Introduction
This tip gives an overview to modify existing button control in Winforms to achieve rounded edge Button Control (or rounded corner button control).
Background
Recently, I came across a requirement which asked for rounded edge button (or rounded corner button). I know WinForms is almost outdated and this feature can be achieved very easily in WPF. This tip is written for any programmer who is struggling to get this requirement done.
Final Output
Using the Code
The basic idea of getting this done is to inherit button control to a class ButtonModified
and override OnPaint
to obtain our requirement.
The first thing is to set the button’s FlatStyle
as «Flat
» from constructor. We can also set the common properties which we use throughout our project like Font
, BorderSize
, etc. This can also be modified individually from the forms which we refer this
.
class ButtonModified : System.Windows.Forms.Button { public Color BorderColor = Color.LightGray; public int BorderSize = 5; public ButtonModified() { FlatStyle = FlatStyle.Flat; BackColor = Color.White; FlatAppearance.BorderColor = BorderColor; FlatAppearance.BorderSize = BorderSize; Font = new System.Drawing.Font("VAGRounded-Light", 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel, ((byte)(0))); ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(84)))), ((int)(((byte)(33)))), ((int)(((byte)(107))))); this.MouseDown += new MouseEventHandler(ButtonLastest_MouseDown); this.MouseUp += new MouseEventHandler(ButtonLastest_MouseUp); } void ButtonLastest_MouseUp(object sender, MouseEventArgs e) { ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(84)))), ((int)(((byte)(33)))), ((int)(((byte)(107))))); BackColor = Color.White; } void ButtonLastest_MouseDown(object sender, MouseEventArgs e) { BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(84)))), ((int)(((byte)(33)))), ((int)(((byte)(107))))); ForeColor = System.Drawing.Color.White; } int top ; int left; int right ; int bottom; protected override void OnPaint(PaintEventArgs pevent) { base.OnPaint(pevent); int CornerRadius = 18; Pen DrawPen = new Pen(BorderColor); GraphicsPath gfxPath_mod = new GraphicsPath(); top = 0; left = 0; right = Width; bottom = Height; gfxPath_mod.AddArc(left, top, CornerRadius, CornerRadius, 180, 90); gfxPath_mod.AddArc(right - CornerRadius, top, CornerRadius, CornerRadius, 270, 90); gfxPath_mod.AddArc(right - CornerRadius, bottom - CornerRadius, CornerRadius, CornerRadius, 0, 90); gfxPath_mod.AddArc(left, bottom - CornerRadius, CornerRadius, CornerRadius, 90, 90); gfxPath_mod.CloseAllFigures(); pevent.Graphics.DrawPath(DrawPen, gfxPath_mod); int inside = 1; Pen newPen = new Pen(BorderColor, BorderSize); GraphicsPath gfxPath = new GraphicsPath(); gfxPath.AddArc(left + inside + 1, top + inside, CornerRadius, CornerRadius, 180, 100); gfxPath.AddArc(right - CornerRadius - inside - 2, top + inside, CornerRadius, CornerRadius, 270, 90); gfxPath.AddArc(right - CornerRadius - inside - 2, bottom - CornerRadius - inside - 1, CornerRadius, CornerRadius, 0, 90); gfxPath.AddArc(left + inside + 1, bottom - CornerRadius - inside, CornerRadius, CornerRadius, 95, 95); pevent.Graphics.DrawPath(newPen, gfxPath); this.Region = new System.Drawing.Region(gfxPath_mod); } }
Now we have two approaches.
Easier Approach
The easier way is to first build your solution and the button will be available in your toolbar which you can use like normal button control.
Approach Two to Modify Existing Buttons Already Aligned and Placed In Project
We all know that normal buttons when placed in winform by dragging and dropping will generate a designer class. We can easily modify our designer class as explained below. To modify the existing buttons in our project:
Partial Class Buttontype { Private System.ComponentModel.IContainer Components = Null; Protected Override Void Dispose(bool Disposing) { if (Disposing && (Components != null)) { components.Dispose(); } base.Dispose(disposing); } #Region Windows Form Designer Generated Code Private Void Initializecomponent() { this.btn_Next = new System.Windows.Forms.Button(); this.SuspendLayout(); this.btn_Next.BackColor = System.Drawing.Color.White; this.btn_Next.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; this.btn_Next.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btn_Next.Font = New System.Drawing.Font("Verdana", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((Byte)(0))); this.btn_Next.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(84)))), ((Int)(((byte)(33)))), ((Int)(((byte)(107))))); this.btn_Next.Location = New System.Drawing.Point(244, 204); this.btn_Next.Name = "Btn_next"; this.btn_Next.Size = New System.Drawing.Size(234, 94); this.btn_Next.TabIndex = 63; this.btn_Next.Text = "Next"; this.btn_Next.UseCompatibleTextRendering = True; this.btn_Next.UseVisualStyleBackColor = False; this.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = New System.Drawing.Size(778, 374); this.Controls.Add(this.btn_Next); this.Name = "Buttontype"; this.Text = "Aint"; this.ResumeLayout(false); } #Endregion Public System.Windows.Forms.Button Btn_next; }
See the bolded portion of the code:
this.btn_Next = new System.Windows.Forms.Button();
This needs to be replaced as:
this.btn_Next = new ButtonDemo.ButtonModified();
This will update your designer once you rebuild the solution.
The method is depicted here so as to modify any existing project easily without any hassles, i.e., you wouldn’t need to align your existing button or modify the font, etc. Use this only if your requirement is just to round off your existing Buttons which were previously aligned and set.
Points of Interest
This is just a method which I came up with. If someone comes up with a better solution, it can be posted here so that it can be a reference to anyone who needs this in the future.
This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.
Да-да, я знаю, что лучше не делать на Windows Forms красивые приложения – для этого есть WPF. Однако, если проект уже разросся, то переносить его из-за пары красивостей не хочется. Тем более, что при достаточной сноровке можно делать симпатичные кнопочки и на Windows Forms.
Итак, сначала создаем кнопку. Называем её неоригинально – button1. Сначала закругляем ей края при загрзуке формы (событие лоад):
System.Drawing.Drawing2D.GraphicsPath Button_Path = new System.Drawing.Drawing2D.GraphicsPath(); Button_Path.AddEllipse(-10, -9, this.button1.Width+20, 40); Region Button_Region = new Region(Button_Path); this.button1.Region = Button_Region;
Числа подбираются индивидуально — чтобы края у кнопки были закруглены равномерно — я же не заню, какого размера она у вас.
Теперь нам надо закрасить кнопку. Но не просто однотонно, а с градиентом. Это тоже реализуется довольно просто. В обработчик перерисовщика кнопки кидаем:
private void button1_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; g.FillRectangle( new LinearGradientBrush(PointF.Empty, new PointF(0, button1.Height), Color.Black, Color.Green), new RectangleF(PointF.Empty, button1.Size)); g.DrawString("Вход за преподавателя", new Font("Arial", 10), System.Drawing.Brushes.White, new Point(10, 3)); }
И получается вот такая картина:
Не сказать, чтобы очень красиво, но своей цели мы все же добились. Если вам требуется помощь программиста по C# или другим языкам программирования, то вы можете написать мне — за небольшую плату я вам с удовольствием помогу.
Автор этого материала — я — Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML — то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
заметки, visual studio, windows forms