Hello, through some research around here and other sites, I've made a rounded edges button.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle Rect = new Rectangle(0, 0, this.Width, this.Height);
GraphicsPath GraphPath = new GraphicsPath();
GraphPath.AddArc(Rect.X, Rect.Y, 50, 50, 180, 90);
GraphPath.AddArc(Rect.X + Rect.Width - 50, Rect.Y, 50, 50, 270, 90);
GraphPath.AddArc(Rect.X + Rect.Width - 50, Rect.Y + Rect.Height - 50, 50, 50, 0, 90);
GraphPath.AddArc(Rect.X, Rect.Y + Rect.Height - 50, 50, 50, 90, 90);
this.Region = new Region(GraphPath);
}
The problem I'm facing is the button's "blue highlight": It shows on most of the button, but it doesn't show on the rounded edges, so my button is part highlighted and part non-highlighted (on the edges). What could I do to solve this? Thank you.
PS: I can't use WPF. The application is for an very old computer; so, please, don't suggest it. Also, the client doesn't have the money to get a newer computer.
This is a quick one, you may want to fine tune things and optimize quite a few details..
class RoundedButton : Button
{
GraphicsPath GetRoundPath(RectangleF Rect, int radius)
{
float r2 = radius / 2f;
GraphicsPath GraphPath = new GraphicsPath();
GraphPath.AddArc(Rect.X, Rect.Y, radius, radius, 180, 90);
GraphPath.AddLine(Rect.X + r2, Rect.Y, Rect.Width - r2, Rect.Y);
GraphPath.AddArc(Rect.X + Rect.Width - radius, Rect.Y, radius, radius, 270, 90);
GraphPath.AddLine(Rect.Width, Rect.Y + r2, Rect.Width, Rect.Height - r2);
GraphPath.AddArc(Rect.X + Rect.Width - radius,
Rect.Y + Rect.Height - radius, radius, radius, 0, 90);
GraphPath.AddLine(Rect.Width - r2, Rect.Height, Rect.X + r2, Rect.Height);
GraphPath.AddArc(Rect.X, Rect.Y + Rect.Height - radius, radius, radius, 90, 90);
GraphPath.AddLine(Rect.X, Rect.Height - r2, Rect.X, Rect.Y + r2);
GraphPath.CloseFigure();
return GraphPath;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
RectangleF Rect = new RectangleF(0, 0, this.Width, this.Height);
using (GraphicsPath GraphPath = GetRoundPath(Rect, 50))
{
this.Region = new Region(GraphPath);
using (Pen pen = new Pen(Color.CadetBlue, 1.75f))
{
pen.Alignment = PenAlignment.Inset;
e.Graphics.DrawPath(pen, GraphPath);
}
}
}
}
Obviously, since we have a class we can cache the GraphicsPath in a class variable. And of course you pick the color..
This is a tweak on TaW's answer to more easily tweak the borderRadius and borderThickness. If you get random white space between the border and the button background color, m needs to be tweaked.
public class RoundedButton : Button
{
GraphicsPath GetRoundPath(RectangleF Rect, int radius)
{
float m = 2.75F;
float r2 = radius / 2f;
GraphicsPath GraphPath = new GraphicsPath();
GraphPath.AddArc(Rect.X + m, Rect.Y + m, radius, radius, 180, 90);
GraphPath.AddLine(Rect.X + r2 + m, Rect.Y + m, Rect.Width - r2 - m, Rect.Y + m);
GraphPath.AddArc(Rect.X + Rect.Width - radius - m, Rect.Y + m, radius, radius, 270, 90);
GraphPath.AddLine(Rect.Width - m, Rect.Y + r2, Rect.Width - m, Rect.Height - r2 - m);
GraphPath.AddArc(Rect.X + Rect.Width - radius - m,
Rect.Y + Rect.Height - radius - m, radius, radius, 0, 90);
GraphPath.AddLine(Rect.Width - r2 - m, Rect.Height - m, Rect.X + r2 - m, Rect.Height - m);
GraphPath.AddArc(Rect.X + m, Rect.Y + Rect.Height - radius - m, radius, radius, 90, 90);
GraphPath.AddLine(Rect.X + m, Rect.Height - r2 - m, Rect.X + m, Rect.Y + r2 + m);
GraphPath.CloseFigure();
return GraphPath;
}
protected override void OnPaint(PaintEventArgs e)
{
int borderRadius = 50;
float borderThickness = 1.75f;
base.OnPaint(e);
RectangleF Rect = new RectangleF(0, 0, this.Width, this.Height);
GraphicsPath GraphPath = GetRoundPath(Rect, borderRadius);
this.Region = new Region(GraphPath);
using (Pen pen = new Pen(Color.Silver, borderThickness))
{
pen.Alignment = PenAlignment.Inset;
e.Graphics.DrawPath(pen, GraphPath);
}
}
}
Cheers!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace button2
{
public partial class Form1 : Form
{
private Button button1;
private GroupBox box;
public Form1()
{
InitializeComponent();
show();
}
private void show()
{
box = new GroupBox();
button1 = new Button();
button1.Location = new Point(50, 50);
ElipseControl nn = new ElipseControl();
nn.TargetControl = button1;
button1.Text = "First Name";
button1.BackColor = Color.Cyan;
button1.FlatStyle = FlatStyle.Flat;
button1.FlatAppearance.BorderSize = 0;
button1.FlatAppearance.BorderColor = Color.White;
nn.CornerRadius = 10;
button1.ForeColor = Color.Blue;
button1.Font = new Font("Arial", 9, FontStyle.Bold);
box.Controls.Add(button1);
box.AutoSize = true;
this.Controls.Add(box);
}
}
class ElipseControl : Component
{
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
public static extern IntPtr CreateRoundRectRgn
(
int nLeftRect,
int nTopRect,
int nRightRect,
int nBottomRect,
int nWidthEllipse,
int nHeightEllipse
);
private Control _cntrl;
private int _CornerRadius = 30;
public Control TargetControl
{
get { return _cntrl; }
set
{
_cntrl = value;
_cntrl.SizeChanged += (sender, eventArgs) => _cntrl.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, _cntrl.Width, _cntrl.Height, _CornerRadius, _CornerRadius));
}
}
public int CornerRadius
{
get { return _CornerRadius; }
set
{
_CornerRadius = value;
if (_cntrl != null)
_cntrl.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, _cntrl.Width, _cntrl.Height, _CornerRadius, _CornerRadius));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
namespace ButtonRounded
{
public enum ButtonAction
{
Highlight,
Click,
Disabled,
Normal,
}
public enum ShadowPosition
{
BottomRight,
Bottom,
BottomLeft,
Left,
TopLeft,
Top,
TopRight,
Right,
}
public enum ShadowSize
{
Thin,
Normal,
Thick,
None,
}
public static class ControlExtensions
{
public static T Clone<T>(this T controlToClone)
where T : Control
{
PropertyInfo[] controlProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
T instance = Activator.CreateInstance<T>();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite && propInfo.Name != "WindowTarget")
{
propInfo.SetValue(instance, propInfo.GetValue(controlToClone, null), null);
}
}
return instance;
}
public static void Copy<T>(this T controlToClone, ref T targetControl)
where T : Control
{
foreach (PropertyInfo propInfo in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (propInfo.CanWrite && propInfo.Name != "WindowTarget")
{
propInfo.SetValue(targetControl, propInfo.GetValue(controlToClone, null), null);
}
}
}
}
public class RoundedButtons : IDisposable
{
public bool IsDisposed;
private readonly Dictionary<Button, Button> _ButtonDataDictionary = new Dictionary<Button, Button>();
public RoundedButtons()
{
MouseEventClick = (sender, e) => Button_MouseAction(sender, ButtonAction.Click);
MouseEventHighlight = (sender, e) => Button_MouseAction(sender, ButtonAction.Highlight);
EventHighlight = (sender, e) => Button_MouseAction(sender, ButtonAction.Highlight);
EventNormal = (sender, e) => Button_MouseAction(sender, ButtonAction.Normal);
}
private event EventHandler EventHighlight;
private event EventHandler EventNormal;
private event MouseEventHandler MouseEventClick;
private event MouseEventHandler MouseEventHighlight;
public int Btn_CornerRadius { get; set; } = 8;
public int Btn_LineWidth { get; set; } = 1;
public ShadowPosition Btn_ShadowLocation { get; set; }
public ShadowSize Btn_ShadowWidth { get; set; } = ShadowSize.Normal;
public Padding Btn_TextPadding { get; set; } = new Padding(0);
public Color ClickBGColor { get; set; } = Color.Empty;
public Color ClickLineColor { get; set; } = Color.Black;
public Color ClickShadowColor { get; set; } = Color.Black;
public Color ClickTextColor { get; set; } = Color.GhostWhite;
public Color DisabledBGColor { get; set; } = Color.Empty;
public Color DisabledLineColor { get; set; } = Color.LightGray;
public Color DisabledShadowColor { get; set; } = Color.DarkGray;
public Color DisabledTextColor { get; set; } = Color.Gray;
public Color HighlightBGColor { get; set; } = Color.Empty;
public Color HighlightLineColor { get; set; } = Color.Blue;
public Color HighlightShadowColor { get; set; } = Color.Black;
public Color HighlightTextColor { get; set; } = Color.Empty;
public Color MainBGColor { get; set; } = Color.Empty;
public Color MainLineColor { get; set; } = Color.Black;
public Color MainShadowColor { get; set; } = Color.DarkGray;
public Color MainTextColor { get; set; } = Color.Empty;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public string GetButtonText(Button button)
{
string text = "";
_ButtonDataDictionary.TryGetValue(button, out Button copy);
if (copy != null)
{
text = copy.Text;
}
return text;
}
public void PaintButton(object sender)
{
if (sender is Button b)
{
_ButtonDataDictionary.Add(b, b.Clone());
b.TabStop = false;
b.FlatStyle = FlatStyle.Flat;
b.FlatAppearance.BorderSize = 0;
b.FlatAppearance.MouseDownBackColor = Color.FromArgb(0, 255, 255, 255);
b.FlatAppearance.MouseOverBackColor = Color.FromArgb(0, 255, 255, 255);
b.FlatAppearance.BorderColor = Color.FromArgb(0, 255, 255, 255);
b.BackColor = Color.FromArgb(0, 255, 255, 255);
//Clear text field to prevent double drawn text with Transparency.
b.Text = "";
b.Paint += B_Paint;
b.EnabledChanged += EventNormal;
b.MouseEnter += EventHighlight;
b.MouseLeave += EventNormal;
b.MouseDown += MouseEventClick;
b.MouseUp += MouseEventHighlight;
b.TextChanged += B_TextChanged;
b.Refresh();
}
}
protected virtual void Dispose(bool disposing)
{
if (!IsDisposed && disposing)
{
Button[] keys = _ButtonDataDictionary.Keys.ToArray();
for (int i = 0; i < keys.Length; i++)
{
Button b = _ButtonDataDictionary.ElementAt(i).Key;
Button copy = _ButtonDataDictionary.ElementAt(i).Value;
b.Paint -= B_Paint;
b.EnabledChanged -= EventNormal;
b.MouseEnter -= EventHighlight;
b.MouseLeave -= EventNormal;
b.MouseDown -= MouseEventClick;
b.MouseUp -= MouseEventHighlight;
b.TextChanged -= B_TextChanged;
copy?.Copy(ref b);
copy?.Dispose();
b?.Refresh();
}
_ButtonDataDictionary.Clear();
IsDisposed = true;
}
}
private void B_Paint(object sender, PaintEventArgs e)
{
RoundedButton_Paint(sender, e, ButtonAction.Normal);
}
private void B_Paint_Click(object sender, PaintEventArgs e)
{
RoundedButton_Paint(sender, e, ButtonAction.Click);
}
private void B_Paint_Disable(object sender, PaintEventArgs e)
{
RoundedButton_Paint(sender, e, ButtonAction.Disabled);
}
private void B_Paint_Hightlight(object sender, PaintEventArgs e)
{
RoundedButton_Paint(sender, e, ButtonAction.Highlight);
}
private void B_TextChanged(object sender, EventArgs e)
{
if (sender is Button b)
{
_ButtonDataDictionary.TryGetValue(b, out Button copy);
copy.Text = b.Text;
b.TextChanged -= B_TextChanged;
b.Text = "";
b.TextChanged += B_TextChanged;
}
}
private void Button_MouseAction(object sender, ButtonAction action)
{
if (sender is Button b)
{
b.Paint -= B_Paint_Disable;
b.Paint -= B_Paint_Click;
b.Paint -= B_Paint_Hightlight;
b.Paint -= B_Paint;
b.Paint += action switch
{
ButtonAction.Click => B_Paint_Click,
ButtonAction.Disabled => B_Paint_Disable,
ButtonAction.Highlight => B_Paint_Hightlight,
_ => B_Paint
};
b.Refresh();
}
}
private Rectangle[] CalculateRects(Button b, int shadowWidth)
{
int width = b.Size.Width - 1;
int height = b.Size.Height - 1;
if (Btn_ShadowLocation.ToString().Contains("Bottom") || Btn_ShadowLocation.ToString().Contains("Top"))
{
height -= Btn_LineWidth * 2; height -= shadowWidth;
}
if (Btn_ShadowLocation.ToString().Contains("Right") || Btn_ShadowLocation.ToString().Contains("Left"))
{
width -= Btn_LineWidth * 2; width -= shadowWidth;
}
Size size = new Size(width, height);
Rectangle shadow = new Rectangle(new Point(0, 0), size);
Rectangle button = new Rectangle(new Point(0, 0), size);
if (Btn_ShadowLocation.ToString().Contains("Right"))
{
shadow.X = shadowWidth;
button.X = 0;
}
if (Btn_ShadowLocation.ToString().Contains("Bottom"))
{
shadow.Y = shadowWidth;
button.Y = 0;
}
if (Btn_ShadowLocation.ToString().Contains("Left"))
{
shadow.X = 0;
button.X = shadowWidth;
}
if (Btn_ShadowLocation.ToString().Contains("Top"))
{
shadow.Y = 0;
button.Y = shadowWidth;
}
return new Rectangle[] { shadow, button };
}
private void RoundedButton_Paint(object sender, PaintEventArgs e, ButtonAction action = ButtonAction.Normal)
{
if (sender is Button b)
{
if (!b.Enabled)
{
action = ButtonAction.Disabled;
}
//================Setup================
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
e.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
e.Graphics.TextRenderingHint = TextRenderingHint.SystemDefault; //Causes issues with application text.
StringFormat stringFormat = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
int shadowWidth = (Btn_ShadowWidth == ShadowSize.Thin) ? 1 : (Btn_ShadowWidth == ShadowSize.Normal) ? 2 : (Btn_ShadowWidth == ShadowSize.Thick) ? 3 : 0;
Rectangle[] rect = CalculateRects(b, shadowWidth);
_ButtonDataDictionary.TryGetValue(b, out Button copy);
//=====================================
//===============Colors================
Color shadowColor = action switch
{
ButtonAction.Click => ClickShadowColor,
ButtonAction.Disabled => DisabledShadowColor,
ButtonAction.Highlight => HighlightShadowColor,
ButtonAction.Normal => MainShadowColor,
_ => MainShadowColor
};
shadowColor = shadowColor == Color.Transparent ? Color.FromArgb(0, 255, 255, 255) : shadowColor;
Color bgColor = action switch
{
ButtonAction.Click => ClickBGColor,
ButtonAction.Disabled => DisabledBGColor,
ButtonAction.Highlight => HighlightBGColor,
ButtonAction.Normal => MainBGColor,
_ => MainBGColor
};
bgColor = bgColor == Color.Transparent ? Color.FromArgb(0, 255, 255, 255) : bgColor;
bgColor = bgColor.IsEmpty ? copy.BackColor : bgColor;
Color lineColor = action switch
{
ButtonAction.Click => ClickLineColor,
ButtonAction.Disabled => DisabledLineColor,
ButtonAction.Highlight => HighlightLineColor,
ButtonAction.Normal => MainLineColor,
_ => MainLineColor
};
lineColor = lineColor == Color.Transparent ? Color.FromArgb(0, 255, 255, 255) : lineColor;
Color textColor = action switch
{
ButtonAction.Click => ClickTextColor,
ButtonAction.Disabled => DisabledTextColor,
ButtonAction.Highlight => HighlightTextColor,
ButtonAction.Normal => MainTextColor,
_ => MainTextColor
};
textColor = textColor == Color.Transparent ? Color.FromArgb(0, 255, 255, 255) : textColor;
if (shadowWidth > 0)
{
//Draw shadow in the back
using Brush shadowBrush = new SolidBrush(shadowColor);
using Pen shadowPen = new Pen(shadowBrush, shadowWidth * 2);
if (b.Parent is PictureBox || copy.BackColor == Color.FromArgb(0, 255, 255, 255))
{
e.Graphics.DrawRoundedRectanglePart(shadowPen, rect[0], Btn_CornerRadius, Btn_ShadowLocation);
}
else
{
e.Graphics.DrawRoundedRectangle(shadowPen, rect[0], Btn_CornerRadius);
}
}
//Draw over any existing button graphics
using Brush clearBrush = new SolidBrush((b.Parent is PictureBox) ? Color.FromArgb(0, 255, 255, 255) : ExtensionMethods.GetParentBackColor(b));
e.Graphics.FillRoundedRectangle(clearBrush, rect[1], Btn_CornerRadius);
//Draw background color of the button
using Brush backBrush = new SolidBrush(bgColor);
e.Graphics.FillRoundedRectangle(backBrush, rect[1], Btn_CornerRadius);
//Draw outline of the button
using Brush buttonBrush = new SolidBrush(lineColor);
using Pen buttonPen = new Pen(buttonBrush, Btn_LineWidth);
e.Graphics.DrawRoundedRectangle(buttonPen, rect[1], Btn_CornerRadius);
//Draw text of the button
//Button text is set to "" so that transparency will not show the original text.
//I use a copy of the button to pull the text to draw.
using Brush textBrush = new SolidBrush(textColor.IsEmpty ? b.ForeColor : textColor);
Rectangle rectangleText = new Rectangle(
rect[1].X + Btn_TextPadding.Left,
rect[1].Y + Btn_TextPadding.Top,
rect[1].Width - Btn_TextPadding.Right,
rect[1].Height - Btn_TextPadding.Bottom
);
e.Graphics.DrawString(copy.Text, b.Font, textBrush, rectangleText, stringFormat);
}
}
}
internal static class ExtensionMethods
{
public static void DrawRoundedRectangle(this Graphics graphics, Pen pen, Rectangle bounds, int cornerRadius)
{
using GraphicsPath path = RoundedRect(bounds, cornerRadius);
graphics.DrawPath(pen, path);
}
public static void DrawRoundedRectanglePart(this Graphics graphics, Pen pen, Rectangle bounds, int cornerRadius, ShadowPosition position)
{
using GraphicsPath path = RoundedRectPart(bounds, cornerRadius, position);
path.Flatten(new Matrix(), 0.12f);
PointF prevP = new PointF();
int total = path.PathPoints.Length;
int count = 1;
float penSize;
int trim;
if (position == ShadowPosition.Bottom || position == ShadowPosition.Top || position == ShadowPosition.Left || position == ShadowPosition.Right)
{
trim = 1;
}
else
{
trim = 2;
}
foreach (PointF p in path.PathPoints)
{
if (prevP.IsEmpty || count <= trim || count >= total - trim)
{
prevP = p; count++; continue;
}
if (count <= 3 || count >= total - 3)
{
penSize = 1;
}
else if (count <= 5 || count >= total - 5)
{
penSize = 2;
}
else if (count <= 8 || count >= total - 8)
{
penSize = 3;
}
else
{
penSize = pen.Width;
}
if (penSize > pen.Width)
{
penSize = pen.Width;
}
graphics.DrawLine(new Pen(pen.Color, penSize), prevP, p);
prevP = p;
count++;
}
}
public static void FillRoundedRectangle(this Graphics graphics, Brush brush, Rectangle bounds, int cornerRadius)
{
using GraphicsPath path = RoundedRect(bounds, cornerRadius);
graphics.FillPath(brush, path);
}
internal static Color GetParentBackColor(object sender)
{
Color c;
try
{
if ((sender as dynamic)?.Parent != null)
{
c = (sender as dynamic)?.Parent.BackColor;
}
else
{
c = Color.White;
}
}
catch
{
c = Color.White;
}
if (c == Color.Transparent)
{
try
{
if ((sender as dynamic)?.Parent != null)
{
c = GetParentBackColor((sender as dynamic)?.Parent);
}
else
{
c = Color.White;
}
}
catch
{
c = Color.White;
}
}
return c;
}
internal static GraphicsPath RoundedRect(Rectangle bounds, int radius)
{
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath { FillMode = FillMode.Alternate };
if (radius == 0)
{
path.AddRectangle(bounds);
return path;
}
path.AddArc(arc, 180, 90);
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
return path;
}
internal static GraphicsPath RoundedRectPart(Rectangle bounds, int radius, ShadowPosition position)
{
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath { FillMode = FillMode.Alternate, };
if (radius == 0)
{
path.AddRectangle(bounds);
return path;
}
if (position == ShadowPosition.Right)
{
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
}
else if (position == ShadowPosition.BottomRight)
{
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
}
else if (position == ShadowPosition.Bottom)
{
arc.X = bounds.Right - diameter;
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
}
else if (position == ShadowPosition.BottomLeft)
{
arc.X = bounds.Right - diameter;
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
arc.Y = bounds.Top;
path.AddArc(arc, 180, 90);
}
else if (position == ShadowPosition.Left)
{
arc.Y = bounds.Bottom - diameter;
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
arc.Y = bounds.Top;
path.AddArc(arc, 180, 90);
}
else if (position == ShadowPosition.TopLeft)
{
arc.Y = bounds.Bottom - diameter;
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
arc.Y = bounds.Top;
path.AddArc(arc, 180, 90);
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
}
else if (position == ShadowPosition.Top)
{
path.AddArc(arc, 180, 90);
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
}
else if (position == ShadowPosition.TopRight)
{
path.AddArc(arc, 180, 90);
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
}
return path;
}
}
}
Short of painting it yourself, I don't think there's anything you can do. The base button paint logic isn't written as "show a blue highlight around such-and-such portion of whatever the window region is". Instead, it's written with the type of region it expects -- a rectangular one. So the base paint is always going to paint a rectangular image into a cropped shape. You'll have an easier time of such things in WPF.
You can use a WebBrowser, make a button with HTML and CSS, then use webbrowser.DocumentText = "your html";
In C# I have written an application where you select a box to take a screen shot of and what happens is if you are above a 0 on the X axis it doesn't take a picture. I drew a small image to show what I mean:
Red = Image will actually not be of that section
Black = Ok
My code is as follows:
#region testing
private Point start = Point.Empty;
private Point end = Point.Empty;
private void Form2_MouseDown(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) != 0)
{
start.X = e.X;
start.Y = e.Y;
}
}
private void Form2_MouseMove(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
if (((e.Button & MouseButtons.Left) != 0) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
if (end != Point.Empty)
{
p2 = PointToScreen(end);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints(p1, p2),
Color.Black, FrameStyle.Dashed);
}
end.X = e.X;
end.Y = e.Y;
p2 = PointToScreen(end);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints(p1, p2),
Color.Black, FrameStyle.Dashed);
}
}
}
private void Form2_MouseUp(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
if ((end != Point.Empty) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
p2 = PointToScreen(end);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints(p1, p2),
Color.Black, FrameStyle.Dashed);
int x1 = p1.X;
int y1 = p1.Y;
int x2 = p2.X;
int y2 = p2.Y;
int x = x2 - x1;
int y = y2 - y1;
string[] xsp;
int rx = 0;
string[] ysp;
int ry = 0;
if (x.ToString().Contains("-"))
{
xsp = x.ToString().Split('-');
rx = Convert.ToInt32(xsp[1]);
}
else
{
rx = x;
}
if (y.ToString().Contains("-"))
{
ysp = y.ToString().Split('-');
ry = Convert.ToInt32(ysp[1]);
}
else
{
ry = y;
}
using (Bitmap bmpScreenCapture = new Bitmap(rx, ry, g))
{
using (Graphics gra = Graphics.FromImage(bmpScreenCapture))
{
if(x.ToString().Contains("-"))
{
gra.CopyFromScreen(x2, y1, 0, 0, bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
else if(!x.ToString().Contains("-"))
{
gra.CopyFromScreen(x1, y1, 0, 0, bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
else if(y.ToString().Contains("-"))
{
gra.CopyFromScreen(x1, y2, 0, 0, bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
else if (!y.ToString().Contains("-"))
{
gra.CopyFromScreen(x1, y1, 0, 0, bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
else if (x.ToString().Contains("-") && y.ToString().Contains("-"))
{
gra.CopyFromScreen(x2, y2, 0, 0, bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
string filename = GenerateRandomString(20) + ".png";
bmpScreenCapture.Save(Path.GetTempPath() + "" + filename,
ImageFormat.Png);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints
(new Point(0), new Point(0)), Color.Black, FrameStyle.Dashed);
//Upload(Path.GetTempPath() + "" + filename, filename);
}
}
}
}
start = Point.Empty;
end = Point.Empty;
}
private Rectangle GetRectangleForPoints(Point beginPoint, Point endPoint)
{
int top = beginPoint.Y < endPoint.Y ? beginPoint.Y : endPoint.Y;
int bottom = beginPoint.Y > endPoint.Y ? beginPoint.Y : endPoint.Y;
int left = beginPoint.X < endPoint.X ? beginPoint.X : endPoint.X;
int right = beginPoint.X > endPoint.X ? beginPoint.X : endPoint.X;
rect = new Rectangle(left, top, (right - left), (bottom - top));
return rect;
}
#endregion
I have attempted to correct it and I have had no success. I mean the picture still shows up but it is not the right region of the screen.
I started to use a different selection method and that allowed for me to get the rectangles X and Y and Size. A lot better solution :)
Code:
#region testing
private Point start = Point.Empty;
private Point end = Point.Empty;
private void Form2_MouseDown(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) != 0)
{
start.X = e.X;
start.Y = e.Y;
}
}
private void Form2_MouseMove(object sender, MouseEventArgs e)
{
//this.Invalidate();
Point p1;
Point p2;
if (((e.Button & MouseButtons.Left) != 0) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
g.Clear(this.BackColor);
p1 = PointToScreen(start);
if (end != Point.Empty)
{
p2 = PointToScreen(end);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints(p1, p2), Color.Black, FrameStyle.Dashed);
}
end.X = e.X;
end.Y = e.Y;
p2 = PointToScreen(end);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints(p1, p2), Color.Black, FrameStyle.Dashed);
}
}
}
private void Form2_MouseUp(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
if ((end != Point.Empty) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
p2 = PointToScreen(end);
ControlPaint.DrawReversibleFrame(GetRectangleForPoints(p1, p2), Color.Black, FrameStyle.Dashed);
int x1 = p1.X;
int y1 = p1.Y;
int x2 = p2.X;
int y2 = p2.Y;
int x = x2 - x1;
int y = y2 - y1;
string[] xsp;
int rx = 0;
string[] ysp;
int ry = 0;
if (x.ToString().Contains("-"))
{
xsp = x.ToString().Split('-');
rx = Convert.ToInt32(xsp[1]);
}
else
{
rx = x;
}
if (y.ToString().Contains("-"))
{
ysp = y.ToString().Split('-');
ry = Convert.ToInt32(ysp[1]);
}
else
{
ry = y;
}
using (Bitmap bmpScreenCapture = new Bitmap(rect.Width, rect.Height, g))
{
using (Graphics gra = Graphics.FromImage(bmpScreenCapture))
{
gra.CopyFromScreen(rect.X, rect.Y, 0, 0, bmpScreenCapture.Size, CopyPixelOperation.SourceCopy);
string filename = GenerateRandomString(20) + ".png";
bmpScreenCapture.Save(Path.GetTempPath() + "" + filename, ImageFormat.Png);
g.Clear(this.BackColor);
//Upload(Path.GetTempPath() + "" + filename, filename);
}
}
}
}
start = Point.Empty;
end = Point.Empty;
}
private Rectangle GetRectangleForPoints(Point beginPoint, Point endPoint)
{
int top = beginPoint.Y < endPoint.Y ? beginPoint.Y : endPoint.Y;
int bottom = beginPoint.Y > endPoint.Y ? beginPoint.Y : endPoint.Y;
int left = beginPoint.X < endPoint.X ? beginPoint.X : endPoint.X;
int right = beginPoint.X > endPoint.X ? beginPoint.X : endPoint.X;
rect = new Rectangle(left, top, (right - left), (bottom - top));
return rect;
}
#endregion
private void picZoom_MouseMove(object sender, MouseEventArgs e)
{
if (PicImageClicked == false)
{
if (checkBox1.Checked)
{
int x = e.X + picZoom.Left - picImage.Left;
int y = e.Y + picZoom.Top - picImage.Top;
if (x <= picImage.Width && y <= picImage.Height &&
x <= picImage.Top && y <= picImage.Left)
{
MouseEventArgs e2 = new MouseEventArgs(MouseButtons.None, 0, x, y, 0);
picImageReposition(null, e2);
}
}
else
{
UpdateZoomedImage(e);
}
}
}
picImage is a bigger pictureBox and picZoom is a smaller pictureBox the picZoom i'm moving aorund inside the picImage are with the mouse.
This condition:
if (x <= picImage.Width && y <= picImage.Height
Is working if i'm moving the picZoom to the left border or the bottom border it stop on it and not continue.
But the second condition:
x <= picImage.Top && y <= picImage.Left
Is not working good it make everything slow and it's not stopping on the left or top borders.
I want to make a condition/s so the picZoom will stay in the picImage area borders.
What i tried now is:
private void picZoom_MouseMove(object sender, MouseEventArgs e)
{
Point pnt;
int x, y;
if (MouseButtons.Left == e.Button)
{
pnt = picZoom.PointToScreen(e.Location);
pnt = this.PointToClient(pnt);
x = pnt.X - mouseDown.X;
y = pnt.Y - mouseDown.Y;
if (x < picImage.Left)
{
x = picImage.Left;
}
else if (x + picZoom.Width > picImage.Left + picImage.Width)
{
x = picImage.Left + picImage.Width - picZoom.Width;
}
else
{ }
if (y < picImage.Top)
{
y = picImage.Top;
}
else if (y + picZoom.Height > picImage.Top + picImage.Height)
{
y = picImage.Top + picImage.Height - picZoom.Height;
}
else
{ }
picZoom.Location = new Point(x, y);
if (PicImageClicked == false)
{
if (checkBox1.Checked)
{
MouseEventArgs e2 = new MouseEventArgs(MouseButtons.None, 0, x, y, 0);
picImageReposition(null, e2);
}
else
{
UpdateZoomedImage(e);
}
}
}
}
picImageReposition is:
private void picImageReposition(object sender, MouseEventArgs e)
{
// If no picture is loaded, return
if (picImage.Image == null)
return;
if (PicImageClicked == false)
{
picZoom.BringToFront();
picZoom.Left = e.X + picImage.Left - picZoom.Width/2;
picZoom.Top = e.Y + picImage.Top - picZoom.Height/2;
UpdateZoomedImage(e);
}
}
And UpdateZoomedImage is:
private void UpdateZoomedImage(MouseEventArgs e)
{
// Calculate the width and height of the portion of the image we want
// to show in the picZoom picturebox. This value changes when the zoom
// factor is changed.
int zoomWidth = picZoom.Width / _ZoomFactor;
int zoomHeight = picZoom.Height / _ZoomFactor;
// Calculate the horizontal and vertical midpoints for the crosshair
// cursor and correct centering of the new image
int halfWidth = zoomWidth / 2;
int halfHeight = zoomHeight / 2;
// Create a new temporary bitmap to fit inside the picZoom picturebox
tempBitmap = new Bitmap(zoomWidth, zoomHeight, PixelFormat.Format24bppRgb);
// Create a temporary Graphics object to work on the bitmap
Graphics bmGraphics = Graphics.FromImage(tempBitmap);
// Clear the bitmap with the selected backcolor
bmGraphics.Clear(_BackColor);
// Set the interpolation mode
bmGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the portion of the main image onto the bitmap
// The target rectangle is already known now.
// Here the mouse position of the cursor on the main image is used to
// cut out a portion of the main image.
bmGraphics.DrawImage(picImage.Image,
new Rectangle(0, 0, zoomWidth, zoomHeight),
new Rectangle(e.X - halfWidth, e.Y - halfHeight, zoomWidth, zoomHeight),
GraphicsUnit.Pixel);
// Draw the bitmap on the picZoom picturebox
picZoom.Image = tempBitmap;
// Draw a crosshair on the bitmap to simulate the cursor position
bmGraphics.DrawLine(Pens.Black, halfWidth + 1, halfHeight - 4, halfWidth + 1, halfHeight - 1);
bmGraphics.DrawLine(Pens.Black, halfWidth + 1, halfHeight + 6, halfWidth + 1, halfHeight + 3);
bmGraphics.DrawLine(Pens.Black, halfWidth - 4, halfHeight + 1, halfWidth - 1, halfHeight + 1);
bmGraphics.DrawLine(Pens.Black, halfWidth + 6, halfHeight + 1, halfWidth + 3, halfHeight + 1);
// Dispose of the Graphics object
bmGraphics.Dispose();
// Refresh the picZoom picturebox to reflect the changes
picZoom.Refresh();
}
If the formula of moving the picZoom control is what you want eg
int x = e.X + picZoom.Left - picImage.Left;
int y = e.Y + picZoom.Top - picImage.Top;
then the comparison is(x, y is the position in picImage meaning that 0,0 is the left top position):
if(x >= 0 && y >= 0 && x + picZoom.Width <= picImage.Width && y + picZoom.Height <= picImage.Height)
{
...
...
}
EDIT
When you click in picZoom and drag, the control moves with the mouse:
private Point mouseDown;
private void picZoom_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = e.Location;
}
private void picZoom_MouseMove(object sender, MouseEventArgs e)
{
Point pnt;
int x, y;
if (MouseButtons.Left == e.Button)
{
pnt = picZoom.PointToScreen(e.Location);
pnt = this.PointToClient(pnt);
x = pnt.X - mouseDown.X;
y = pnt.Y - mouseDown.Y;
if (x < picImage.Left)
{
x = picImage.Left;
}
else if (x + picZoom.Width > picImage.Left + picImage.Width)
{
x = picImage.Left + picImage.Width - picZoom.Width;
}
else
{ }
if (y < picImage.Top)
{
y = picImage.Top;
}
else if (y + picZoom.Height > picImage.Top + picImage.Height)
{
y = picImage.Top + picImage.Height - picZoom.Height;
}
else
{ }
picZoom.Location = new Point(x, y);
}
}
valter
This is not an answer to your question as much as it is a suggestion. Could you not create a Rect() directly over your picture and simply check if the mouse position is within it's bounds.
Something along the lines of:
Rectangle rect = obj.GetBounds(e.Graphics);
if (!rect.Intersects(e.ClipRectangle))
continue;
(stolen from another post)
So I looked over your code again, and it struck me.
You are comparing an x value to the top bound of your picture and a y value to the left bound...
x <= picImage.Top && y <= picImage.Left
should be
x <= picImage.Left && y <= picImage.Top
That is, if I understand what you are trying to do.
Good luck!