弧形图形质量

时间:2019-01-08 23:25:44

标签: c# winforms graphics graphicspath

回到这里。有什么方法可以提高电弧的质量?
我正在使用e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

这是创建弧的代码:

using (GraphicsPath gp = new GraphicsPath())
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    gp.Reset();
    gp.AddPie(_OuterRectangle, (float)_Properties.Origin, (float)_Properties.GaugeType);
    gp.Reverse();

    gp.AddPie(_InnerRectangle, (float)_Properties.Origin, (float)_Properties.GaugeType);
    gp.Reverse();
    pArea.SetClip(gp);

    using (Pen oPen = new Pen(this.ForeColor, 2f))
    {
       e.Graphics.DrawPath(oPen, gp);
    }
    e.Graphics.SetClip(ClientRectangle);
}

enter image description here

谢谢。

编辑:
我做了LarsTech提出的建议,现在质量很完美,但是我没有所需的身材:

enter image description here

  • OuterRectangle :是ClientRectangle区域,我正在对其进行操作以使Width和Height的长度相同;
  • InnerRectangle :是OuterRectangle的ClientRectangle区域ergo的2/3;
  • 属性。来源:是圆弧开始的角度。我将其作为基数存在于枚举器中,其中北为270,东为0,
    所以。如果是数字,则为西南,为135度;

  • Properties.GaugeType :是另一个枚举器,它表示是否Complete = 360,Half = 180,Quarter = 90,这样我就可以确定扫角。如果数字是ThreeQuarter,则为270度。

1 个答案:

答案 0 :(得分:2)

问题
裁剪当前图形的某个区域(Graphics.SetClip方法)时,由于丢失了 Graphics.SmoothingMode = SmoothingMode.AntiAlias 产生的抗锯齿效果,因此生成的图形会失去质量。

一种可能的解决方案是避免剪切由用于设计弧的GraphicsPath定义的区域(GraphicsPath.AddPie方法);但是,这使饼图的线条可见,从而损害了形状。

另一种解决方案是使用“画布”的背景色在圆弧的中心绘制一个省略号。由于弧线是使用两个矩形绘制的,因此我们可以使用内部矩形,根据需要对其进行充气(Rectangle.Inflate方法)(通常是用于椭圆形的Pen大小的一部分-Pen.Width / 2)。

Rectangle inflate

这允许删除GraphicsPath形状生成的伪像,并在形状的中心绘制一些其他图形内容。

例如,使用不同的画笔:

LinearGradienBrush - HatchBrush - TextureBrush

  LinearGradientBrush           HatchBrush               TextureBrush

当然,还有其他方法可以达到相同的结果。我们可以使用GraphicsPath.AddArc方法绘制圆弧,提取或计算圆弧的第一个点和最后一个点,然后使用它们绘制两条线(GraphicsPath.AddLine)以闭合图形。

但是,由于我们要在圆弧的中心绘制不同的图形对象,因此这些对象将始终覆盖中心区域。

如何使用此代码

  • 在表单中,添加 TrackBar (在此处称为 tbarSpeed
  • 添加大小为Canvas Panel (称为 (200, 200) )。使用此处提供的“自定义面板”控件,该控件会在其构造函数中添加一些ControlStyles。这样可以避免闪烁和伪影
  • 连接TrackBar tbarSpeed_Scroll 事件和面板 Canvas_Paint 事件。

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


float GaugeValue = 88.0f;
float GaugeSweepAngle = 270.0f;
float GaugeStartAngle = 135.0F;

private void Canvas_Paint(object sender, PaintEventArgs e)
{
    Control canvas = sender as Control;
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    Rectangle outerRectangle = new Rectangle(10, 10, 180, 180);
    Rectangle innerRectangle = new Rectangle(30, 30, 140, 140);
    Rectangle blendRectangle = new Rectangle(10, 10, 180, 160);
    PointF innerCenter = new PointF(outerRectangle.Left + (outerRectangle.Width / 2),
                                    outerRectangle.Top + (outerRectangle.Height / 2));
    float gaugeLength = (outerRectangle.Width / 2) - 2;

    using (GraphicsPath path = new GraphicsPath())
    {
        path.AddPie(outerRectangle, GaugeStartAngle, GaugeSweepAngle);
        path.AddPie(innerRectangle, GaugeStartAngle, GaugeSweepAngle);
        innerRectangle.Inflate(-1, -1);

        using (Pen pen = new Pen(Color.White, 3f))
        using (SolidBrush backgroundbrush = new SolidBrush(canvas.BackColor))
        using (LinearGradientBrush gradientBrush = new LinearGradientBrush(blendRectangle,
               Color.Green, Color.Red, LinearGradientMode.ForwardDiagonal))
        {
            Blend blend = new Blend()
            {
                Factors = new[] { 0.0f, 0.0f, 0.1f, 0.3f, 0.7f, 1.0f },
                Positions = new[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }
            };

            gradientBrush.Blend = blend;
            e.Graphics.FillPath(gradientBrush, path);
            e.Graphics.DrawPath(pen, path);

            e.Graphics.FillEllipse(backgroundbrush, innerRectangle);

            using (StringFormat format = new StringFormat())
            {
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;
                innerRectangle.Location = new Point(innerRectangle.X, innerRectangle.Y + canvas.Font.Height);
                e.Graphics.DrawString(GaugeValue.ToString() + "%", canvas.Font, Brushes.White, innerRectangle, format);
            }

            using (Matrix matrix = new Matrix())
            {
                matrix.RotateAt(GaugeStartAngle + 90 + (GaugeValue * (GaugeSweepAngle / 100)), innerCenter);
                e.Graphics.Transform = matrix;
                e.Graphics.DrawLine(pen, innerCenter, new PointF(innerCenter.X, innerCenter.Y - gaugeLength));
                e.Graphics.ResetTransform();
            }
        }
    }
}

private void tbarSpeed_Scroll(object sender, EventArgs e)
{
    GaugeValue = tbarSpeed.Value;
    Canvas.Invalidate();
}

自定义面板控件

using System.ComponentModel;
using System.Windows.Forms;

[DesignerCategory("code")]
public class DrawingPanel : Panel
{
    public DrawingPanel()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.UserPaint |
                      ControlStyles.OptimizedDoubleBuffer, true);
        this.UpdateStyles();
    }
}

Gauge control

Sample code on PasteBin

相关问题