【问题标题】:How to redraw a PictureBox using a TrackBar Value to affect the drawing如何使用 TrackBar 值重绘 PictureBox 以影响绘图
【发布时间】:2020-03-06 23:06:28
【问题描述】:

我一直在绘制不同的分形,当我更改某些 TrackBar 的值时,我需要重新绘制分形。
在这种情况下,值会改变分形函数的递归深度。
我的问题是在我的分形完成绘制后它消失了。

我试过尝试使用:

pictureBox1.Invalidate();
DrawCloverFractal(...);    //fractal drawing method

但我找不到让它正常工作的方法。

我也试过用:

if (pictureBox1.InitialImage != null)
{
    pictureBox1.InitialImage.Dispose();
    pictureBox1.InitialImage = null;
    pictureBox1.Invalidate(); 
}

但它根本没有重新绘制任何东西。

完整代码:

//Drawing method
int DrawCloverFractal(int x0, int y0, int r, int dir, int iter)

{
    var g = pictureBox1.CreateGraphics();
    var S = new SolidBrush(Color.Black);

    g.FillEllipse(S, x0 - r, y0 - r, 2 * r, 2 * r);

    if (iter == 0)
        return 0;
    int[] x = new int[4];
    int[] y = new int[4];
    int d = 3 * r / 2;
    x[0] = x0 - d;
    y[0] = y0;
    x[1] = x0;
    y[1] = y0 - d;
    x[2] = x0 + d;
    y[2] = y0;
    x[3] = x0;
    y[3] = y0 + d;

    for (int i = 0; i < 4; i++)
    {
        if (i - dir == 2 || i - dir == -2)
            continue;
        DrawCloverFractal(x[i], y[i], r / 2, i, iter - 1);
    }
    return 0;
}

//Scroll method where I call DrawCloverFractal
private void RecursionLevel_Scroll(object sender, EventArgs e)
{
    pictureBox1.Invalidate();
    DrawCloverFractal(pictureBox1.Width / 2, pictureBox1.Height / 2, (int)(pictureBox1.Height * 0.17), 1, RecursionLevel.Value);
}

【问题讨论】:

  • 将您的DrawCloverFractal 调用放在pictureBox1.Paint 事件处理程序中,并使用e.Graphics 对象进行绘图
  • @Jimi 这是生成绘图的代码code(由于字符太多,无法在此处插入代码)我在那里使用 .CreateGraphics() ,我的问题是完成绘图后面板框清除。

标签: c# winforms graphics drawing gdi+


【解决方案1】:

目前的代码有几个问题:

  1. 您正在使用Control.CreateGraphics()
    使用此方法创建的 Graphics 对象不是永久性的,每次需要重新绘制 Control 时都会在内部重新创建它;经常发生的事件。如果您使用此对象在 Control 的表面上绘图,则绘图将不会持续存在:描述 Control 设备上下文的 Graphics 对象将不一样。

    另请参阅:
    Getting Started with Graphics Programming
    How to: Create Graphics Objects for Drawing

  2. 整数值用于生成绘图
    几乎所有的 Graphics 度量都应该用浮点值表示。整数除法导致的舍入会影响计算。最终的 Graphics 函数是否需要 - 有时 - 整数参数并不重要:这是一个最终值,通常以这种形式使用,因为内部方法 - 或 Graphics 对象 - 不支持浮点测量(处理像素位置是原因之一)。

    例如看这个:Rotate Point around pivot Point repeatedly

在 WinForms Graphics 中,当必须在 Control 的表面上进行绘图时,Paint event(或 OnPaint 方法覆盖)提供用于执行绘图的 Graphics 对象。

在示例中,PictureBox Paint 事件的 PaintEventArgs 提供了该 Graphics 对象,然后 DrawCloverFractal() 方法使用它来绘制分形。

TrackBar 控件的ValueChanged 事件提供了函数用来创建嵌套代的递归级别。

生成分形的方法已移至类对象,该对象提供公共方法来配置分形:

  • 将提供绘图表面的控件 (Canvas)
  • 绘图方向
  • 迭代次数
  • 画笔的颜色

DrawCloverFractal() 方法接受一个 Graphics 对象作为参数。当 Canvas 的 Paint 事件生成时,此对象将传递给方法。

我们可以在需要时强制控件重绘自身,调用 它的Invalidate() 方法(它在 异步方式)。

► 公共DrawCloverFractal() 方法然后调用内部DrawCloverFractalinternal(),将它需要的参数传递给递归方法,使用分配给类属性的值并生成其他值在当前递归中保持不变,作为 Canvas 的中心。

► 拖动 TrackBar 控件的旋钮时,会引发 ValueChanged 事件。事件处理程序只需将类对象的 Iterations 属性设置为当前值,然后调用 pictureBox1.Invalidate() 来刷新用作 Canvas 的 PictureBox,然后调用 DrawCloverFractal() 方法传递一个 fresh图形对象:

public partial class Form1 : Form
{
    private MyFractal fractalDrawing = null;

    public Form1()
    {
        InitializeComponent();
        fractalDrawing = new MyFractal(this.pictureBox1);
    }

    private void trkRecursionLevel_ValueChanged(object sender, EventArgs e)
    {
        fractalDrawing.Iterations = (sender as TrackBar).Value;
        pictureBox1.Invalidate();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (fractalDrawing == null) return;
        fractalDrawing.DrawCloverFractal(e.Graphics);
    }
}

结果的视觉样本:

包含所有绘图方法和逻辑的类对象:

public class MyFractal
{
    public MyFractal() : this(null) { }
    public MyFractal(Control canvas) => this.Canvas = canvas;

    public Control Canvas { get; set; }
    public Color Color { get; set; } = Color.LightGreen;
    public int Direction { get; set; } = 1;
    public int Iterations { get; set; } = 1;

    public void DrawCloverFractal(Graphics g)
    {
        if (this.Canvas == null) return;
        PointF center = new PointF(this.Canvas.Width / 2.0f, this.Canvas.Height / 2.0f);
        float r = this.Canvas.Height * .17f;
        DrawCloverFractalinternal(g, center, r, this.Direction, this.Iterations);
    }

    internal void DrawCloverFractalinternal(Graphics g, PointF center, float r, int dir, int iter)
    {
        g.SmoothingMode = SmoothingMode.AntiAlias;
        using (var brush = new SolidBrush(this.Color)) {
            g.FillEllipse(brush, center.X - r, center.Y - r, 2 * r, 2 * r);
        }

        if (iter == 0) return;
        float[] x = new float[4];
        float[] y = new float[4];
        float d = 3 * r / 2;
        x[0] = center.X - d;
        y[0] = center.Y;
        x[1] = center.X;
        y[1] = center.Y - d;
        x[2] = center.X + d;
        y[2] = center.Y;
        x[3] = center.X;
        y[3] = center.Y + d;

        for (int i = 0; i < 4; i++) {
            if (i - dir == 2 || i - dir == -2) continue;
            DrawCloverFractalinternal(g, new PointF(x[i], y[i]), r / 2, i, iter - 1);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 2019-11-02
    • 2012-07-15
    • 2012-11-15
    • 2011-04-23
    • 2020-06-17
    • 2012-05-10
    相关资源
    最近更新 更多