如何避免可缩放的UserControl带有圆角的彩色边框的视觉伪像? [英] How to avoid visual artifacts of colored border of zoomable UserControl with rounded corners?

查看:112
本文介绍了如何避免可缩放的UserControl带有圆角的彩色边框的视觉伪像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表格,其中包含:


  1. a TrackBar (最小值= 1,最大值= 200,代表缩放百分比);

  2. a UserControl BorderStyle = BorderStyle.None



相关代码



Form1



来自设计者代码



  trackBar1.Value = 100; 
BackColor = Color.Gray;



来自隐藏代码



  private void trackBar1_Scroll(object sender,EventArgs e)
{
userControl11.SetZoomFactor(trackBar1.Value / 100F);
}



UserControl1



 内部浮点数MyBaseWidth; 

public UserControl1()
{
InitializeComponent();

MyBaseWidth =宽度;

SetZoomFactor(1);
}

受保护的覆盖无效OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

Pen p =新型Pen(颜色。黄色);
e.Graphics.DrawPath(p,GraphicsPathWithBorder);
}

内部GraphicsPath GraphicsPathWithBorder;

内部无效SetZoomFactor(float z)
{
Width =(int)(MyBaseWidth * z);

GraphicsPathWithBorder = RoundedCornerRectangle(ClientRectangle);
Region = new Region(GraphicsPathWithBorder);
}

内部静态GraphicsPath RoundedCornerRectangle(Rectangle r)
{
GraphicsPath path = new GraphicsPath();
浮点数= 10 * 2F;

path.StartFigure();

path.AddArc(r.X,r.Y,
size,size,180,90);
path.AddArc((r.X +(r.Width-size)),r.Y,
size,size,270,90);
path.AddArc((r.X +(r.Width-size)),(r.Y +(r.Height-size)),
size,size,0,90);
path.AddArc(r.X,(r.Y +(r.Height-size)),
size,size,90,90);

path.CloseFigure();

返回路径;
}



初始屏幕截图





使用跟踪栏后的屏幕截图





缩小后,黄色边框的右侧不可见;放大时,右侧有多个黄色边框。



更新:



答案是可行的,但其中有一部分控件可以使用越过边界。右上角的屏幕截图,其中 curveSize = 20





,并且 curveSize = 24



< a href = https://i.stack.imgur.com/BwO9Z.png rel = nofollow noreferrer>

解决方案

我建议绘制边框和用户内容的方法稍有不同该控件还应治愈重绘该控件时生成的工件。



当您为控件创建一个Region然后按原样绘制Region时,画图的外部边界不会被消除锯齿:锯齿像素落在外部该区域。在区域的边界周围绘制边框时,当然会产生相同的效果。



在这里,我应用了






 使用System.Drawing; 
使用System.Drawing.Drawing2D;

公共局部类RoundControl:UserControl
{
private GraphicsPath GraphicsPathWithBorder;
private float MyBaseWidth;
private float m_PenSize = 2f;
private Color m_BorderColor = Color.Yellow;
private Color m_FillColor = Color.Green;

public RoundControl()
{
this.ResizeRedraw = true;
InitializeComponent();
MyBaseWidth =宽度;
}

public float BorderSize
{
get => this.m_PenSize;
set {
this.m_PenSize = value;
this.Invalidate();
}
}

public Color BorderColor
{
get => this.m_BorderColor;
set {
this.m_BorderColor = value;
this.Invalidate();
}
}

public Color FillColor
{
get => this.m_FillColor;
set {
this.m_FillColor = value;
this.Invalidate();
}
}

受保护的覆盖无效OnLayout(LayoutEventArgs e){
this.UpdateRegion();
base.OnLayout(e);
}

受保护的覆盖无效OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
RectangleF rect = GraphicsPathWithBorder.GetBounds();
float scaleX = 1-(((m_PenSize + 1)/矩形宽度);
float scaleY = 1-((m_PenSize + 1)/矩形高度);
使用(钢笔=​​新的Pen(m_BorderColor,m_PenSize))
使用(画笔笔=新的SolidBrush(m_FillColor))
使用(矩阵mx =新的Matrix(scaleX,0,0, scaleY,pen.Width / 2,pen.Width / 2))
{
e.Graphics.Transform = mx;
e.Graphics.FillPath(brush,GraphicsPathWithBorder);
e.Graphics.DrawPath(pen,GraphicsPathWithBorder);
}
base.OnPaint(e);
}

内部无效SetZoomFactor(float z){
int newWidth =(int)(MyBaseWidth * z);
if(newWidth< =(30 + this.m_PenSize * 2))返回;
this.Width = newWidth;
this.UpdateRegion();
}


private void UpdateRegion(){
GraphicsPathWithBorder = RoundedCornerRectangle(ClientRectangle);
Region = new Region(GraphicsPathWithBorder);
this.Invalidate();
}

Private GraphicsPath RoundedCornerRectangle(Rectangle r)
{
GraphicsPath path = new GraphicsPath();
//固定曲线大小,因为我们仅按X维度缩放
// //否则,请考虑高度
进行调整float curveSize = 10 * 2.4F;

path.StartFigure();
path.AddArc(r.X,r.Y,curveSize,curveSize,180,90);
path.AddArc(r.Right-curveSize,r.Y,curveSize,curveSize,270,90);
path.AddArc(r.Right-curveSize,r.Bottom-curveSize,curveSize,curveSize,0,90);
path.AddArc(r.X,r.Bottom-curveSize,curveSize,curveSize,90,90);
path.CloseFigure();
返回路径;
}
}


I have a Form which contains:

  1. a TrackBar (minimum = 1, maximum = 200, represents zoom percent);
  2. a UserControl with BorderStyle = BorderStyle.None.

Relevant code

Form1

From designer code

trackBar1.Value = 100;
BackColor = Color.Gray;

From code-behind

private void trackBar1_Scroll(object sender, EventArgs e)
{
    userControl11.SetZoomFactor(trackBar1.Value / 100F);
}

UserControl1

internal float MyBaseWidth;

public UserControl1()
{
    InitializeComponent();

    MyBaseWidth = Width;

    SetZoomFactor(1);
}

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
    e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
    e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

    Pen p = new Pen(Color.Yellow);
    e.Graphics.DrawPath(p, GraphicsPathWithBorder);
}

internal GraphicsPath GraphicsPathWithBorder;

internal void SetZoomFactor(float z)
{
    Width = (int)(MyBaseWidth * z);

    GraphicsPathWithBorder = RoundedCornerRectangle(ClientRectangle);
    Region = new Region(GraphicsPathWithBorder);
}

internal static GraphicsPath RoundedCornerRectangle(Rectangle r)
{
    GraphicsPath path = new GraphicsPath();
    float size = 10 * 2F;

    path.StartFigure();

    path.AddArc(r.X, r.Y,
        size, size, 180, 90);
    path.AddArc((r.X + (r.Width - size)), r.Y,
        size, size, 270, 90);
    path.AddArc((r.X + (r.Width - size)), (r.Y + (r.Height - size)),
        size, size, 0, 90);
    path.AddArc(r.X, (r.Y + (r.Height - size)),
        size, size, 90, 90);

    path.CloseFigure();

    return path;
}

Initial screenshot

Screenshot after using the trackbar

The right side of the yellow border becomes invisible after zooming out, and when zooming in there are multiple yellow borders on the right side.

Update:

The answer Works, but there is a part of the control that goes beyond the border. Screenshot for top-right corner, for curveSize = 20:

and for curveSize = 24:

解决方案

I suggest a slightly different method to draw the Border and the content of the User Control that should also cure the artifacts generated when the control is redrawn.

When you create a Region for a Control and then you paint the Region as it is, the outer borders of the painting are not anti-aliased: the aliased pixels fall outside the Region. The same effect of course is applies when a border is painted around the bounds of the Region.

Here, I apply a Scale Matrix and a Translate Matrix that scale and move the bounds of the Region on the inside of the outer Region that defines the control's bounds.
The size of the scale and the translate transformations are determined by the Pen size.
More information on the Matrix usage here: Flip the GraphicsPath

In this case, when the borders are painted the outer, anti-aliased section of the border is inside the Region bounds and the anti-aliasing is preserved.
The background color of the Control is set to Color.Transparent (a User Control supports color transparency on its own).

I've also added a couple of (non decorated) properties that allow to define the inner Color (the Control's BackgroundColor) and Size and Color of the Border. The rest is more or less what it was before.

Sample results:


using System.Drawing;
using System.Drawing.Drawing2D;

public partial class RoundControl : UserControl
{
    private GraphicsPath GraphicsPathWithBorder;
    private float MyBaseWidth;
    private float m_PenSize = 2f;
    private Color m_BorderColor = Color.Yellow;
    private Color m_FillColor = Color.Green;

    public RoundControl()
    {
        this.ResizeRedraw = true;
        InitializeComponent();
        MyBaseWidth = Width;
    }

    public float BorderSize
    {
        get => this.m_PenSize;
        set {
            this.m_PenSize = value;
            this.Invalidate();
        }
    }

    public Color BorderColor
    {
        get => this.m_BorderColor;
        set {
            this.m_BorderColor = value;
            this.Invalidate();
        }
    }

    public Color FillColor
    {
        get => this.m_FillColor;
        set {
            this.m_FillColor = value;
            this.Invalidate();
        }
    }

    protected override void OnLayout(LayoutEventArgs e) {
        this.UpdateRegion();
        base.OnLayout(e);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        RectangleF rect = GraphicsPathWithBorder.GetBounds();
        float scaleX = 1 - ((m_PenSize + 1) / rect.Width);
        float scaleY = 1 - ((m_PenSize + 1) / rect.Height);
        using (Pen pen = new Pen(m_BorderColor, m_PenSize))
        using (Brush brush = new SolidBrush(m_FillColor))
        using (Matrix mx = new Matrix(scaleX, 0, 0, scaleY, pen.Width / 2, pen.Width / 2))
        {
            e.Graphics.Transform = mx;
            e.Graphics.FillPath(brush, GraphicsPathWithBorder);
            e.Graphics.DrawPath(pen, GraphicsPathWithBorder);
        }
        base.OnPaint(e);
    }

    internal void SetZoomFactor(float z) {
        int newWidth = (int)(MyBaseWidth * z);
        if (newWidth <= (30 + this.m_PenSize * 2)) return;
        this.Width = newWidth;
        this.UpdateRegion();
    }


    private void UpdateRegion() {
        GraphicsPathWithBorder = RoundedCornerRectangle(ClientRectangle);
        Region = new Region(GraphicsPathWithBorder);
        this.Invalidate();
    }

    private GraphicsPath RoundedCornerRectangle(Rectangle r)
    {
        GraphicsPath path = new GraphicsPath();
        // Fixed curve size since we only scale on X-dimension
        // Otherwise, adjust also considering the height
        float curveSize = 10 * 2.4F;

        path.StartFigure();
        path.AddArc(r.X, r.Y, curveSize, curveSize, 180, 90);
        path.AddArc(r.Right - curveSize, r.Y, curveSize, curveSize, 270, 90);
        path.AddArc(r.Right - curveSize, r.Bottom - curveSize, curveSize, curveSize, 0, 90);
        path.AddArc(r.X, r.Bottom - curveSize, curveSize, curveSize, 90, 90);
        path.CloseFigure();
        return path;
    }
}

这篇关于如何避免可缩放的UserControl带有圆角的彩色边框的视觉伪像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆