在Mandelbrot Fractal上拖动鼠标时绘制一个矩形(从Java转换为C#)

时间:2015-11-29 10:31:38

标签: java c# mandelbrot

这是我关于从Java到C#的Mandelbrot分形转换的第二篇文章。 根据我的任务,我需要在一个窗体上绘制一个mandelbrot分形,一旦绘制,允许用户使用鼠标放大,同时还从初始点击点到点击释放点绘制一个矩形。这是我认为负责矩形的代码部分。

private static void Swap<T>(ref T t1, ref T t2)
    {
        T temp = t1;
        t1 = t2;
        t2 = t1;
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        Graphics g1 = e.Graphics;
        g1.DrawImage(bitmap, 0, 0, x1, y1);

        if (action)
        {
            //g.setColor(Color.White);
            if (xe < xs)
            {
                Swap(ref xs, ref xe);
            }

            if (ye < ys)
            {
                Swap(ref ys, ref ye);
            }

            g1.DrawRectangle(Pens.White, xs, ys, (xe - xs), (ye - ys));
            //g1.Dispose();
        }
    }
    //load method here 
    private void Form1_Load(object sender, EventArgs e)
    //while loading
    {
        init();
        start();

    }
    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (action)
        {
            xe = e.X;
            ye = e.Y;
        }
    }

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        action = true;
        // e.consume();
        if (action)
        {
            xs = xe = e.X;
            ys = ye = e.Y;
        }
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        using (Graphics g = this.CreateGraphics())
        {
            Pen pen = new Pen(Color.White);
            g.DrawRectangle(pen, xs, ys, Math.Abs(xs - xe), Math.Abs(ys - ye));

        }

        int z, w;
        if (xs > xe)
        {
            z = xs;
            xs = xe;
            xe = z;
        }
        if (ys > ye)
        {
            z = ys;
            ys = ye;
            ye = z;
        }
        w = (xe - xs);
        z = (ye - ys);
        if ((w < 2) && (z < 2)) initvalues();
        else
        {
            if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
            else xe = (int)((float)xs + (float)z * xy);
            xende = xstart + xzoom * (double)xe;
            yende = ystart + yzoom * (double)ye;
            xstart += xzoom * (double)xs;
            ystart += yzoom * (double)ys;
        }
        xzoom = (xende - xstart) / (double)x1;
        yzoom = (yende - ystart) / (double)y1;
        mandelbrot();

        this.Invalidate();
    }

代码的作用是,在拖动完成后绘制一个矩形,然后放大,同时仍然显示绘制的矩形。我需要的是在拖动鼠标时绘制的矩形。

我提到了这个问题,并且提到的解决方案没有帮助。 Java to C# conversion. How do i draw a rectangle on my bitmap?

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

绘制矩形

首先,似乎Graphics.DrawRectangle方法无法绘制具有负宽度或高度的矩形。因此,您必须编写一个方法,该方法将采用两个点并生成满足要求的正方形(正宽度和高度)。

private Rectangle CreateRectangle(Point pt1, Point pt2)
{
    // we use this method to create the rectangle with positive width and height
    int x1 = Math.Min(pt1.X, pt2.X);
    int y1 = Math.Min(pt1.Y, pt2.Y);


    return new Rectangle(x1, y1, Math.Abs(pt1.X - pt2.X), Math.Abs(pt1.Y - pt2.Y));
}

其次,在MouseDown事件的事件处理程序中,记录鼠标按住的位置。

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
        this.startPoint = e.Location;// record the start position
}

接下来,修改鼠标移动方法以更新保存鼠标当前位置的变量。此外,使表单无效,以便重绘图像(以及矩形)。

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        // record the current position as the end point if the left button is down
        this.endPoint = e.Location;
        // force a redraw
        this.Invalidate();
    }
}

在表单的Paint事件处理程序中,使用矩形的起点和终点调用CreateRectangle方法,以便在表单上绘制矩形。

private void Form1_Paint(object sender, PaintEventArgs e)
{
    // draw the cached Mandelbrot image
    e.Graphics.DrawImage(mandelbrotCache, new Point(0, 0));

    // draw the current rectangle
    e.Graphics.DrawRectangle(rectPen, CreateRectangle(startPoint, endPoint));
}

最后,为了在不再按下鼠标按钮时删除矩形,请将startPointendPoint设置为在图像外部绘制的值。这应该在MouseUp事件处理程序中完成。

private void Form1_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        // setting the point to -1,-1 makes them get drawn off the screen
        startPoint = new Point(-1, -1);
        endPoint = new Point(-1, -1);

        // force an update so that the rectangle disappears
        this.Invalidate();
    }
}

解决闪烁问题

为了在绘图时阻止窗体闪烁,您需要在窗体上启用双缓冲。这是通过将表单的DoubleBuffered属性设置为true来完成的。您可以在任何地方执行此操作,但我更喜欢在创建表单后立即执行此操作,如下所示:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // this reduces the flickering
        this.DoubleBuffered = true;
    }
}

完整代码:

以下是我详细介绍的所有步骤的完整代码。您可以插入方法以获得可行的解决方案。

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private Point startPoint;
        private Point endPoint;
        private Image mandelbrotCache;
        private Pen rectPen;

        public Form1()
        {
            InitializeComponent();

            // this reduces the flickering
            this.DoubleBuffered = true;

            // initialize a dummy image. Cache a copy of your Mandelbrot fractal here
            mandelbrotCache = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
            using (var g = Graphics.FromImage(mandelbrotCache))
            {
                var imgRect = new Rectangle(0, 0,
                                            mandelbrotCache.Width,
                                            mandelbrotCache.Height);

                g.FillRectangle(new HatchBrush(HatchStyle.Cross, Color.DarkBlue,
                                Color.LightBlue), imgRect);
            }

            // this is the pen to draw the rectangle with
            rectPen = new Pen(Color.Red, 3);
        }

        private Rectangle CreateRectangle(Point pt1, Point pt2)
        {
            // we use this method to create a rectangle with positive width and height
            int x1 = Math.Min(pt1.X, pt2.X);
            int y1 = Math.Min(pt1.Y, pt2.Y);

            return new Rectangle(x1, y1, Math.Abs(pt1.X - pt2.X), Math.Abs(pt1.Y - pt2.Y));
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
                this.startPoint = e.Location;// record the start position
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                // record the current position as the end point if the left button is down
                this.endPoint = e.Location;
                // force a redraw
                this.Invalidate();
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                // setting the point to -1,-1 makes them get drawn off the screen
                startPoint = new Point(-1, -1);
                endPoint = new Point(-1, -1);

                // force an update so that the rectangle disappears
                this.Invalidate();
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            // draw the cached Mandelbrot image
            e.Graphics.DrawImage(mandelbrotCache, new Point(0, 0));

            // draw the current rectangle
            e.Graphics.DrawRectangle(rectPen, CreateRectangle(startPoint, endPoint));
        }
    }
}

以下是正在绘制的矩形的屏幕截图 注意:仍然按住鼠标左键。当按钮被释放时,矩形立即消失。

Screenshot of a rectangle being drawn on the form