我创建了以下一组类来创建自己的控件库。目前,它基于asbtract类ShapeControl:Control。但是,我仍然有一些麻烦,没有一些不良的混叠副作用(特别是圆角矩形),我怎么能摆脱它们? (我已经尝试改变平滑度和像素偏移,并刷新并改变OnPaint()过程中的顺序......没有那么多成功= /)。
是否有任何想法正确使用“SmoothingMode”和“PixelOffset”属性?
public abstract class ShapeControl : Control
{
public ShapeControl()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor |
ControlStyles.DoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
this.PixelOffsetMode = PixelOffsetMode.HighQuality;
this.SmoothingMode = SmoothingMode.HighQuality;
this.TextAligmentHorizontal = StringAlignment.Center;
this.TextAligmentVertical = StringAlignment.Center;
this.MouseDown += new MouseEventHandler(Shape_MouseDown);
this.MouseMove += new MouseEventHandler(Shape_MouseMove);
this.BackColor = Color.FromArgb(0, 255, 255, 255);
this.GradientColors = new List<Color>();
this.GradientRadialFocus = 0.5f;
this.GradientRadialScale = 1.0f;
this.GradientRadialType = GradientRadialType.SigmaBell;
}
protected override void OnResize(EventArgs e)
{
this.Region = new Region(this.GraphicsPath);
this.Invalidate();
base.OnResize(e);
}
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
this.Invalidate();
}
}
public override Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
this.Invalidate();
}
}
protected Point LastMouseDownLocation { get; set;}
private void Shape_MouseMove(Object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Left = e.X + this.Left - LastMouseDownLocation.X;
this.Top = e.Y + this.Top - LastMouseDownLocation.Y;
this.Invalidate();
}
}
private void Shape_MouseDown(Object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.LastMouseDownLocation = e.Location;
}
}
protected DashStyle InternalBorderStyle { get; set; }
protected UInt32 InternalBorderWidth { get; set; }
protected Color InternalBorderColor { get; set; }
protected BackType InternalBackType { get; set; }
protected List<Color> InternalGradientColors { get; set; }
protected SmoothingMode InternalSmoothingMode { get; set; }
protected PixelOffsetMode InternalPixelOffsetMode { get; set; }
public DashStyle BorderStyle
{
get { return this.InternalBorderStyle; }
set
{
if (this.InternalBorderStyle != value)
{
this.InternalBorderStyle = value;
this.Invalidate();
}
}
}
public UInt32 BorderWidth
{
get { return this.InternalBorderWidth; }
set
{
if (this.InternalBorderWidth != value)
{
this.InternalBorderWidth = value;
this.Invalidate();
}
}
}
public Color BorderColor
{
get { return this.InternalBorderColor; }
set
{
if (this.InternalBorderColor != value)
{
this.InternalBorderColor = value;
this.Invalidate();
}
}
}
public BackType BackType
{
get { return this.InternalBackType; }
set
{
if (this.InternalBackType != value)
{
this.InternalBackType = value;
this.Invalidate();
}
}
}
public List<Color> GradientColors
{
get { return this.InternalGradientColors; }
set
{
if (this.InternalGradientColors != value)
{
this.InternalGradientColors = value;
this.Invalidate();
}
}
}
public SmoothingMode SmoothingMode
{
get { return this.InternalSmoothingMode; }
set
{
if (this.InternalSmoothingMode != value)
{
this.InternalSmoothingMode = value;
this.Invalidate();
}
}
}
public PixelOffsetMode PixelOffsetMode
{
get { return this.InternalPixelOffsetMode; }
set
{
if (this.InternalPixelOffsetMode != value)
{
this.InternalPixelOffsetMode = value;
this.Invalidate();
}
}
}
protected override Size DefaultSize
{
get
{
return new Size(100, 100);
}
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = this.SmoothingMode;
e.Graphics.PixelOffsetMode = this.PixelOffsetMode;
ProcessBack(e.Graphics);
ProcessBorder(e.Graphics);
ProcessText(e.Graphics);
base.OnPaint(e);
}
protected void ProcessBack(Graphics graphics)
{
switch (this.BackType)
{
case BackType.Solid:
// Nothing special...
break;
case BackType.GradientHorizontal:
case BackType.GradientVertical:
case BackType.GradientRadial:
Single angle = 42;
if (this.BackType == BackType.GradientHorizontal)
{
angle = 0;
}
else if (this.BackType == BackType.GradientVertical)
{
angle = 90;
}
else
{
angle = 42;
}
Brush brushGradient = null;
Boolean isALinearBrush = (this.BackType == BackType.GradientHorizontal) || (this.BackType == BackType.GradientVertical);
if (isALinearBrush)
{
LinearGradientBrush linearGradientBrushHorizontal = new LinearGradientBrush(this.ClientRectangle, Color.Black, Color.Black, angle, false);
brushGradient = linearGradientBrushHorizontal;
}
else
{
PathGradientBrush pathGradientBrush = new PathGradientBrush(this.GraphicsPath);
brushGradient = pathGradientBrush;
}
ColorBlend colorBlend = new ColorBlend();
HashSet<Single> positions = new HashSet<Single>();
if (this.GradientColors.Count > 1)
{
for (Single i = 0; i < this.GradientColors.Count; i++)
{
positions.Add(i / (this.GradientColors.Count - 1));
}
colorBlend.Colors = this.GradientColors.ToArray();
}
else
{
positions.Add(0);
positions.Add(1);
if (this.GradientColors.Count == 1)
{
colorBlend.Colors = new Color[2] { this.GradientColors[0], this.GradientColors[0] };
}
else
{
colorBlend.Colors = new Color[2] { this.BackColor, this.BackColor };
}
}
colorBlend.Positions = positions.ToArray();
if (isALinearBrush)
{
(brushGradient as LinearGradientBrush).InterpolationColors = colorBlend;
}
else
{
PathGradientBrush pathGradientBrush = brushGradient as PathGradientBrush;
if (this.GradientRadialType == GradientRadialType.SigmaBell)
{
pathGradientBrush.SetSigmaBellShape(this.GradientRadialFocus, this.GradientRadialScale);
}
else
{
pathGradientBrush.SetBlendTriangularShape(this.GradientRadialFocus, this.GradientRadialScale);
}
pathGradientBrush.CenterPoint = new PointF(this.ClientRectangle.Right / 2, this.ClientRectangle.Bottom / 2);
pathGradientBrush.InterpolationColors = colorBlend;
}
graphics.FillPath(brushGradient, this.GraphicsPath);
break;
}
}
protected void ProcessBorder(Graphics graphics)
{
if (this.BorderWidth > 0)
{
// Hey wait... * 2, why?
Pen pen = new Pen(this.BorderColor, this.BorderWidth * 2);
pen.DashStyle = this.BorderStyle;
graphics.DrawPath(pen, this.GraphicsPath);
pen.Dispose();
}
}
protected void ProcessText(Graphics graphics)
{
Brush brushText = new SolidBrush(this.ForeColor);
StringFormat stringFormatText = new StringFormat();
stringFormatText.Alignment = this.TextAligmentHorizontal;
stringFormatText.LineAlignment = this.TextAligmentVertical;
Rectangle rectangleText = new Rectangle(0, 0, this.Width, this.Height);
graphics.DrawString(this.Text, this.Font, brushText, rectangleText, stringFormatText);
}
protected StringAlignment InternalTextAligmentHorizontal { get; set; }
protected StringAlignment InternalTextAligmentVertical { get; set; }
public StringAlignment TextAligmentHorizontal
{
get { return this.InternalTextAligmentHorizontal; }
set
{
if (this.InternalTextAligmentHorizontal != value)
{
this.InternalTextAligmentHorizontal = value;
this.Invalidate();
}
}
}
public StringAlignment TextAligmentVertical
{
get { return this.InternalTextAligmentVertical; }
set
{
if (this.InternalTextAligmentVertical != value)
{
this.InternalTextAligmentVertical = value;
this.Invalidate();
}
}
}
protected GradientRadialType InternalGradientRadialType { get; set; }
public GradientRadialType GradientRadialType
{
get { return this.InternalGradientRadialType; }
set
{
if (this.InternalGradientRadialType != value)
{
this.InternalGradientRadialType = value;
this.Invalidate();
}
}
}
protected Single InternalGradientRadialFocus { get; set; }
public Single GradientRadialFocus
{
get { return this.InternalGradientRadialFocus; }
set
{
if (this.InternalGradientRadialFocus != value)
{
if (1.0f < value)
{
this.InternalGradientRadialFocus = 1.0f;
}
else if (value < 0.0f)
{
this.InternalGradientRadialFocus = 0.0f;
}
else
{
this.InternalGradientRadialFocus = value;
}
this.Invalidate();
}
}
}
protected Single InternalGradientRadialScale { get; set; }
public Single GradientRadialScale
{
get { return this.InternalGradientRadialScale; }
set
{
if (this.InternalGradientRadialScale != value)
{
if (1.0f < value )
{
this.InternalGradientRadialScale = 1.0f;
}
else if (value < 0.0f)
{
this.InternalGradientRadialScale = 0.0f;
}
else
{
this.InternalGradientRadialScale = value;
}
this.Invalidate();
}
}
}
protected abstract GraphicsPath GraphicsPath { get; }
}
public enum GradientRadialType
{
SigmaBell,
Triangular,
}
public enum BackType
{
Solid,
GradientHorizontal,
GradientVertical,
GradientRadial,
}
public class EllipseControl : ShapeControl
{
protected override GraphicsPath GraphicsPath
{
get
{
GraphicsPath graphicsPath = new GraphicsPath();
graphicsPath.AddEllipse(this.ClientRectangle);
return graphicsPath;
}
}
}
public class RectangleControl : ShapeControl
{
public RectangleControl()
: base()
{
this.Radius = 5;
}
protected UInt32 InternalRadius { get; set; }
public UInt32 Radius
{
get { return this.InternalRadius; }
set
{
if (this.InternalRadius != value)
{
this.InternalRadius = value;
this.Invalidate();
}
}
}
protected RectangleEdgeType InternalRectangleEdge { get; set; }
public RectangleEdgeType RectangleEdge
{
get { return this.InternalRectangleEdge; }
set
{
if (this.InternalRectangleEdge != value)
{
this.InternalRectangleEdge = value;
this.Invalidate();
}
}
}
protected override GraphicsPath GraphicsPath
{
get
{
GraphicsPath graphicsPath = new GraphicsPath();
if (this.Radius == 0)
{
graphicsPath.AddRectangle(new Rectangle(0, 0, this.Width, this.Height));
}
else
{
Int32 width = this.Width;
Int32 height = this.Height;
Single radius = Convert.ToSingle(this.Radius);
RectangleF rectangleF = this.ClientRectangle;
Graphics graphics = null;
graphicsPath = GenerateRoundedRectangle(graphics, rectangleF, radius, RectangleEdgeType.All);
}
return graphicsPath;
}
}
private static GraphicsPath GenerateRoundedRectangle(Graphics graphics, RectangleF rectangle, Single radius, RectangleEdgeType filter)
{
Single diameter;
GraphicsPath path = new GraphicsPath();
{
if (radius >= (Math.Min(rectangle.Width, rectangle.Height)) / 2.0)
return GenerateCapsule(graphics, rectangle);
diameter = radius * 2.0F;
SizeF sizeF = new SizeF(diameter, diameter);
RectangleF arc = new RectangleF(rectangle.Location, sizeF);
if ((RectangleEdgeType.TopLeft & filter) == RectangleEdgeType.TopLeft)
{
path.AddArc(arc, 180, 90);
}
else
{
path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
}
arc.X = rectangle.Right - diameter;
if ((RectangleEdgeType.TopRight & filter) == RectangleEdgeType.TopRight)
{
path.AddArc(arc, 270, 90);
}
else
{
path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X + arc.Width, arc.Y);
}
arc.Y = rectangle.Bottom - diameter;
if ((RectangleEdgeType.BottomRight & filter) == RectangleEdgeType.BottomRight)
{
path.AddArc(arc, 0, 90);
}
else
{
path.AddLine(arc.X + arc.Width, arc.Y, arc.X + arc.Width, arc.Y + arc.Height);
path.AddLine(arc.X, arc.Y + arc.Height, arc.X + arc.Width, arc.Y + arc.Height);
}
arc.X = rectangle.Left;
if ((RectangleEdgeType.BottomLeft & filter) == RectangleEdgeType.BottomLeft)
{
path.AddArc(arc, 90, 90);
}
else
{
path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X, arc.Y + arc.Height);
path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
}
path.CloseFigure();
}
return path;
}
private static GraphicsPath GenerateCapsule( Graphics graphics, RectangleF rectangle)
{
Single diameter;
RectangleF arc;
GraphicsPath path = new GraphicsPath();
try
{
if (rectangle.Width > rectangle.Height)
{
diameter = rectangle.Height;
SizeF sizeF = new SizeF(diameter, diameter);
arc = new RectangleF(rectangle.Location, sizeF);
path.AddArc(arc, 90, 180);
arc.X = rectangle.Right - diameter;
path.AddArc(arc, 270, 180);
}
else if (rectangle.Width < rectangle.Height)
{
diameter = rectangle.Width;
SizeF sizeF = new SizeF(diameter, diameter);
arc = new RectangleF(rectangle.Location, sizeF);
path.AddArc(arc, 180, 180);
arc.Y = rectangle.Bottom - diameter;
path.AddArc(arc, 0, 180);
}
else
{
path.AddEllipse(rectangle);
}
}
catch
{
path.AddEllipse(rectangle);
}
finally
{
path.CloseFigure();
}
return path;
}
}
public enum RectangleEdgeType
{
None = 0,
TopLeft = 1,
TopRight = 2,
BottomLeft = 4,
BottomRight = 8,
All = TopLeft | TopRight | BottomLeft | BottomRight
}
答案 0 :(得分:3)
路径渐变画笔不遵循用于绘制的Graphics对象的SmoothingMode属性。无论平滑模式如何,使用PathGradientBrush对象填充的区域都以相同的方式呈现(别名)。