在 Mandelbrot 分形上拖动鼠标时绘制矩形(从 Java 转换为 C#)
Drawing a rectangle while dragging the mouse on Mandelbrot Fractal ( Conversion to C# from Java )
这是我第二次 post 从 Java 到 C# 的 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?
如有任何帮助,我们将不胜感激。
绘制矩形
首先,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));
}
最后,为了在不再按下鼠标按钮时删除矩形,将 startPoint
和 endPoint
设置为在图像外部绘制的值。这应该在 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));
}
}
}
这是正在绘制的矩形的屏幕截图。
注意:鼠标左键仍被按住。释放按钮后矩形立即消失。
这是我第二次 post 从 Java 到 C# 的 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?
如有任何帮助,我们将不胜感激。
绘制矩形
首先,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));
}
最后,为了在不再按下鼠标按钮时删除矩形,将 startPoint
和 endPoint
设置为在图像外部绘制的值。这应该在 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));
}
}
}
这是正在绘制的矩形的屏幕截图。
注意:鼠标左键仍被按住。释放按钮后矩形立即消失。