I'm currently trying to override the OnPaint()
method of a Custom Control I'm building.
The object is just a simple Panel, but I'm trying to make it look a different type of way, like this:
I'm using a GraphicsPath to help me try and complete this task, but it's not looking/behaving how I expected it to work as it currently looks like this:
Here is the code I've been working on to recreate Fig 1:
private GraphicsPath GetFigurePath(RectangleF rect)
{
GraphicsPath path = new GraphicsPath();
Point TopLeft = new Point((int)rect.X, (int)rect.Y);
Point TopRight = new Point((int)rect.X (int)rect.Width, (int)rect.Height);
Point BottomLeft = new Point((int)rect.X, (int)rect.Y (int)rect.Height);
Point BottomRight = new Point((int)rect.X (int)rect.Width, (int)rect.Y (int)rect.Height);
Point MidPoint = new Point((TopLeft.X BottomLeft.X) / 2, (TopLeft.Y BottomLeft.Y) / 2);
Point Fulcrum = new Point((int)MidPoint.X (int)rect.Width, MidPoint.Y);
path.StartFigure();
// The rectangle
path.AddLine(TopLeft, TopRight);
path.AddLine(TopRight, BottomRight);
path.AddLine(BottomRight, BottomLeft);
path.AddLine(BottomLeft, TopLeft);
// The pointy end
path.AddLine(TopRight, Fulcrum);
path.AddLine(Fulcrum, BottomRight);
path.CloseFigure();
return path;
}
protected override void OnPaint(PaintEventArgs e)
{
if (HasBorderStyle) {
base.OnPaint(e);
this.FlatStyle = FlatStyle.Flat;
this.Size = new Size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
this.BackColor = Color.Silver;
this.ForeColor = Color.White;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
RectangleF rectSurface = new RectangleF(0, 0, this.DEFAULT_WIDTH, this.DEFAULT_HEIGHT);
RectangleF rectBorder = new RectangleF(1, 1, this.DEFAULT_WIDTH - 0.8f, this.DEFAULT_HEIGHT - 1);
using (GraphicsPath pathSurface = GetFigurePath(rectSurface))
using (GraphicsPath pathBorder = GetFigurePath(rectBorder))
using (Pen penSurface = new Pen(this.Parent.BackColor, 2))
using (Pen penBorder = new Pen(borderColour, borderSize)) {
penBorder.Alignment = PenAlignment.Inset;
this.Region = new Region(pathSurface);
e.Graphics.DrawPath(penSurface, pathSurface);
e.Graphics.DrawPath(penBorder, pathBorder);
}
}
}
Could anyone tell me what I'm missing or I'm doing wrong?
CodePudding user response:
A few pointers and an example on the use of
And at Run-Time:
See also:
How to avoid visual artifacts of colored border of zoomable UserControl with rounded corners?
How can I draw a rounded rectangle as the border for a rounded Form?
A shadow created with PathGradientBrush shows undesired thorn results
Custom Control:
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
[ToolboxItem(true)]
[DesignerCategory("code")]
public class NavigationShape : Control
{
private Color m_ArrowColor = Color.SteelBlue;
private Color m_BorderColor = Color.Orange;
private float m_BorderSize = 1.5f;
private bool m_BorderVisible = true;
public NavigationShape() {
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw, true);
MinimumSize = new Size(40, 20);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Region = new Region(GetRegionPath());
}
private GraphicsPath GetRegionPath()
{
// The arrow shape begins at 3/4 or the current width of the container
float arrowSection = ClientSize.Width * .75f;
PointF[] arrowPoints = new PointF[] {
new PointF (0, 0),
new PointF (arrowSection, 0),
new PointF(ClientSize.Width, ClientSize.Height / 2.0f),
new PointF (arrowSection, ClientSize.Height),
new PointF (0, ClientSize.Height),
new PointF (0, 0)
};
var path = new GraphicsPath();
path.AddLines(arrowPoints);
path.CloseFigure();
return path;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
float border = m_BorderVisible ? m_BorderSize : .5f;
using (var path = GetRegionPath()) {
var rect = path.GetBounds();
float scaleX = 1.0f - ((border * 2.5f) / rect.Width);
float scaleY = 1.0f - ((border * 2.0f) / rect.Height);
using (var mx = new Matrix(scaleX, 0, 0, scaleY, border, border))
using (var brush = new SolidBrush(m_ArrowColor)) {
path.Transform(mx);
e.Graphics.FillPath(brush, path);
if (m_BorderVisible) {
using (Pen pen = new Pen(m_BorderColor, m_BorderSize)) {
e.Graphics.DrawPath(pen, path);
}
}
}
}
base.OnPaint(e);
}
[DefaultValue(typeof(Color), "SteelBlue")]
[Description("Color of the shape")]
public Color ArrowColor {
get => m_ArrowColor;
set {
if (m_ArrowColor != value) {
m_ArrowColor = value;
Invalidate();
}
}
}
[DefaultValue(true)]
[Description("Show or hide the Border")]
public bool BorderVisible {
get => m_BorderVisible;
set {
m_BorderVisible = value;
Invalidate();
}
}
[DefaultValue(typeof(Color), "Orange")]
[Description("Color of the Border")]
public Color BorderColor {
get => m_BorderColor;
set {
if (m_BorderColor != value) {
m_BorderColor = value;
Invalidate();
}
}
}
[DefaultValue(1.5f)]
[Description("Size of the Border [1.0, 6.0]")]
public float BorderSize {
get => m_BorderSize;
set {
if (m_BorderSize != value) {
m_BorderSize = Math.Max(Math.Min(value, 6.0f), 1.0f);
Invalidate();
}
}
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public BorderStyle BorderStyle{ get; set; } // Implement if needed
}