When we Draw to a Graphics object we can set AntiAlias so as to make the edges of complex shapes look smooth. This is done by altering the color of some of the pixels on and around the edge so that the jagged edges appear smooth.
When we create a region from a complex shape though, the recoloured pixels outside of the region are lost and as there is no way to trim the edges of the pixels (they are always square) our regions appear jagged. A simple solution to this is to put a pseudo transparent 1 pixel border around the control when shaping it. I doubt very much that you will notice this border, but it will greatly improve the appearance of the edges of your shaped control.
Because the Control in this example has rounded edges, it is not suitable for the AutoScrol property as the ScrollBars will be Clipped. For this reason the Control Inherits from Control and because we want to use it as a Container we have assigned the ParentControlDesigner to the Class.
When we create a region from a complex shape though, the recoloured pixels outside of the region are lost and as there is no way to trim the edges of the pixels (they are always square) our regions appear jagged. A simple solution to this is to put a pseudo transparent 1 pixel border around the control when shaping it. I doubt very much that you will notice this border, but it will greatly improve the appearance of the edges of your shaped control.
Because the Control in this example has rounded edges, it is not suitable for the AutoScrol property as the ScrollBars will be Clipped. For this reason the Control Inherits from Control and because we want to use it as a Container we have assigned the ParentControlDesigner to the Class.
VB net Sample:
Namespace Dotnetrix.Samples.VB
<System.ComponentModel.Designer(GetType(System.Windows.Forms.Design.ParentControlDesigner))> _
Public Class RoundedPanel
Inherits System.Windows.Forms.UserControl
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.DoubleBuffer Or ControlStyles.UserPaint, True)
End Sub
'UserControl overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub
#End Region
Private m_BorderRadius As Int32 = 32
Public Property BorderRadius() As Int32
Get
Return m_BorderRadius
End Get
Set(ByVal Value As Int32)
m_BorderRadius = Value
Me.Invalidate()
End Set
End Property
Protected Overrides ReadOnly Property DefaultSize() As System.Drawing.Size
Get
Return New Size(200, 100)
End Get
End Property
Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
MyBase.OnMove(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
'Draw the Parent onto our Control to give pseudo transparency.
'The BeginContainer and EndContainer calls stop incorrect painting of
'child controls when both container and child have BackColor set to Transparent.
'This only happens as a result of the TranslateTransform() call.
Dim g As System.Drawing.Drawing2D.GraphicsContainer = pevent.Graphics.BeginContainer()
Dim translateRect As Rectangle = Me.Bounds
pevent.Graphics.TranslateTransform(-Me.Left, -Me.Top)
Dim pe As PaintEventArgs = New PaintEventArgs(pevent.Graphics, translateRect)
Me.InvokePaintBackground(Me.Parent, pe)
Me.InvokePaint(Me.Parent, pe)
pevent.Graphics.ResetTransform()
pevent.Graphics.EndContainer(g)
'Define the custom Border Region, Brush and Pen.
Dim border As System.Drawing.Drawing2D.GraphicsPath
Dim paintBrush As New SolidBrush(Me.BackColor)
Dim borderPen As New Pen(Me.ForeColor)
Dim r As Rectangle = Me.ClientRectangle
'Set the Region of the Control
Me.Region = New Region(RoundRegion(r))
r.Inflate(-1, -1)
border = RoundRegion(r)
'Fill The Region with the Controls BackColor
pevent.Graphics.FillPath(paintBrush, border)
'Paint any BackgroundImage that might have been set
If Not (Me.BackgroundImage Is Nothing) Then
Dim br As Brush = New TextureBrush(Me.BackgroundImage)
pevent.Graphics.FillPath(br, border)
br.Dispose()
End If
'Draw the Region
pevent.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
pevent.Graphics.DrawPath(borderPen, border)
'Clean Up
borderPen.Dispose()
paintBrush.Dispose()
border.Dispose()
End Sub
Private Function RoundRegion(ByVal r As Rectangle) As System.Drawing.Drawing2D.GraphicsPath
'Scale the radius if it's too large to fit.
Dim radius As Int32 = m_BorderRadius
If (radius > (r.Width)) Then radius = r.Width
If (radius > (r.Height)) Then radius = r.Height
Dim path As New System.Drawing.Drawing2D.GraphicsPath
If radius <= 0 Then
path.AddRectangle(r)
Else
path.AddArc(r.Left, r.Top, radius, radius, 180, 90)
path.AddArc(r.Right - radius, r.Top, radius, radius, 270, 90)
path.AddArc(r.Right - radius, r.Bottom - radius, radius, radius, 0, 90)
path.AddArc(r.Left, r.Bottom - radius, radius, radius, 90, 90)
path.CloseFigure()
End If
Return path
End Function
End Class
End Namespace
CSharp Sample:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace Dotnetrix.Samples.CSharp
{
/// <summary>
/// Summary description for RoundedPanel.
/// </summary>
[System.ComponentModel.Designer(typeof(System.Windows.Forms.Design.ParentControlDesigner))]
public class RoundedPanel : System.Windows.Forms.Control
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public RoundedPanel()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitializeComponent call
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
private int borderRadius = 32;
public int BorderRadius
{
get{return borderRadius;}
set
{
borderRadius = value;
this.Invalidate();
}
}
protected override Size DefaultSize
{
get{return new Size(200,100);}
}
protected override void OnMove(EventArgs e)
{
base.OnMove (e);
this.Invalidate();
}
protected override void OnResize(EventArgs e)
{
base.OnResize (e);
this.Invalidate();
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//Draw the Parent onto our Control to give pseudo transparency.
//The BeginContainer and EndContainer calls stop incorrect painting of
//child controls when both container and child have BackColor set to Transparent.
//This only happens as a result of the TranslateTransform() call.
System.Drawing.Drawing2D.GraphicsContainer g = pevent.Graphics.BeginContainer();
Rectangle translateRect = this.Bounds;
pevent.Graphics.TranslateTransform(-this.Left,-this.Top);
PaintEventArgs pe = new PaintEventArgs(pevent.Graphics,translateRect);
this.InvokePaintBackground(this.Parent,pe);
this.InvokePaint(this.Parent,pe);
pevent.Graphics.ResetTransform();
pevent.Graphics.EndContainer(g);
//Define the custom Border Region, Brush and Pen.
System.Drawing.Drawing2D.GraphicsPath border;
Brush paintBrush = new SolidBrush(this.BackColor);
Pen borderPen = new Pen(this.ForeColor);
Rectangle r = this.ClientRectangle;
//Set the Region of the Control
this.Region = new Region(RoundRegion(r));
r.Inflate(-1,-1);
border = RoundRegion(r);
//Fill The Region with the Controls BackColor
pevent.Graphics.FillPath(paintBrush,border);
//Paint any BackgroundImage that might have been set
if (this.BackgroundImage != null)
{
Brush br = new TextureBrush(this.BackgroundImage);
pevent.Graphics.FillPath(br,border);
br.Dispose();
}
//Draw the Region
pevent.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
pevent.Graphics.DrawPath(borderPen,border);
//Clean Up
borderPen.Dispose();
paintBrush.Dispose();
border.Dispose();
}
private System.Drawing.Drawing2D.GraphicsPath RoundRegion(Rectangle r)
{
//Scale the radius if it's too large to fit.
int radius = borderRadius;
if (radius > (r.Width))
radius = r.Width;
if (radius > (r.Height))
radius = r.Height;
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
if (radius <= 0)
{
path.AddRectangle(r);
}
else
{
path.AddArc(r.Left,r.Top,radius,radius,180,90);
path.AddArc(r.Right - radius,r.Top,radius,radius,270,90);
path.AddArc(r.Right-radius,r.Bottom-radius,radius,radius,0,90);
path.AddArc(r.Left,r.Bottom-radius,radius,radius,90,90);
path.CloseFigure();
}
return path;
}
}
}
by: Mick Dohertys'













0 comments:
Post a Comment