C# 无法将单击坐标转换为picturebox
我有一个带有一些图形的C# 无法将单击坐标转换为picturebox,c#,drawing,C#,Drawing,我有一个带有一些图形的PictureBox,可以通过鼠标滚轮进行缩放。为了使图形保持在(大致)相同的位置,而不必在每次缩放后移动,我在每次缩放后平移图形。这是我的缩放代码: private void pictureBox1_Paint(object sender, PaintEventArgs e) { e.Graphics.Clear(pictureBox1.BackColor); float _step = 1.0f; if (todo == "zoom out")
PictureBox
,可以通过鼠标滚轮进行缩放。为了使图形保持在(大致)相同的位置,而不必在每次缩放后移动,我在每次缩放后平移图形。这是我的缩放代码:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(pictureBox1.BackColor);
float _step = 1.0f;
if (todo == "zoom out")
{
float step = 0;
if (CurrentRate >= 0.60f) step = 0.05f;
else if (CurrentRate >= 0.40f && CurrentRate < 0.60f) step = 0.025f;
else if (CurrentRate >= 0.05f && CurrentRate < 0.40f) step = 0.0125f;
CurrentRate -= step; // current rate is 1.0 on startup
_step = step;
//pictureBox1.Location = new Point((int)(pictureBox1.Location.X + step * 1500), (int)(pictureBox1.Location.Y + step * 1500));
translateX += step * 10500; //achieved these numbers after few dozens of tries, it actually keeps the graphics at the same position..
translateY += step * 8500;
todo = null;
}
else if (todo == "zoom in")
{
float step = 0;
if (CurrentRate >= 1.80f && CurrentRate <= 1.95f) step = 0.0125f;
else if (CurrentRate >= 0.80f && CurrentRate < 1.80f) step = 0.025f;
else if (CurrentRate >= 0.03f && CurrentRate < 0.80f) step = 0.05f;
CurrentRate += step;
_step = step;
translateX -= step * 10500;
translateY -= step * 8500;
//pictureBox1.Location = new Point((int)(pictureBox1.Location.X - step * 1500), (int)(pictureBox1.Location.Y - step * 1500));
todo = null;
}
e.Graphics.TranslateTransform(translateX, translateY); //move it to keep same position
e.Graphics.ScaleTransform(CurrentRate, CurrentRate); //rescale according to the zoom
//the drawing itself (of everything, also the things mentioned below)
但这不起作用。在MouseDown事件中,我也尝试过在没有翻译的情况下进行翻译,但仍然使用偏移量绘制。我不太确定如何正确描述这种行为,所以我做了一个简短的视频(大约30秒)来解释偏移量。。
有什么想法吗?先谢谢你
**
编辑
**
现在,根据答案进行编辑后,我的代码如下所示:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (trackDrawing)
{
Matrix m = transform.Clone();
m.Invert();
Point[] rectanglePos = new Point[1];
rectanglePos[0] = new Point(e.Location.X - 3, e.Location.Y - 3);
m.TransformPoints(rectanglePos);
drawBuffer.Add(rectanglePos);
drawBuffertype.Add("DRAWTRACKRECTANGLE");
if (trackDrawingBuffer.Count > 0)
{
Point[] linePos = new Point[2];
linePos[0] = trackDrawingBuffer[trackDrawingBuffer.Count - 1];
linePos[1] = new Point(e.Location.X, e.Location.Y );
m.TransformPoints(linePos);
drawBuffer.Add(linePos);
drawBuffertype.Add("DRAWTRACKLINE");
}
trackDrawingBuffer.Add(rectanglePos[0]);
pictureBox1.Invalidate();
}
现在,这里是转换部分,包括获取矩阵偏移量的代码
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(pictureBox1.BackColor);
transform.Translate(-translateX, -translateY);
float _step = 1.0f;
if (todo == "zoom out")
{
float step = 0;
if (CurrentRate >= 0.60f) step = 0.05f;
else if (CurrentRate >= 0.40f && CurrentRate < 0.60f) step = 0.025f;
else if (CurrentRate >= 0.05f && CurrentRate < 0.40f) step = 0.0125f;
CurrentRate -= step;
_step = step;
translateX += step * 10500;
translateY += step * 8500;
todo = null;
}
else if (todo == "zoom in")
{
float step = 0;
if (CurrentRate >= 1.80f && CurrentRate <= 1.95f) step = 0.0125f;
else if (CurrentRate >= 0.80f && CurrentRate < 1.80f) step = 0.025f;
else if (CurrentRate >= 0.03f && CurrentRate < 0.80f) step = 0.05f;
CurrentRate += step;
_step = step;
//pictureBox1.Scale((1f + step), (1f + step));
translateX -= step * 10500;
translateY -= step * 8500;
todo = null;
}
transform.Translate(translateX, translateY); // transform is the Matrix
e.Graphics.Transform = transform;
e.Graphics.ScaleTransform(CurrentRate, CurrentRate);
private void pictureBox1\u Paint(对象发送方,PaintEventArgs e)
{
e、 图形。清晰(pictureBox1.背景色);
transform.Translate(-translateX,-translateY);
浮动步进=1.0f;
如果(todo==“缩小”)
{
浮动步长=0;
如果(电流率>=0.60f)阶跃=0.05f;
否则,如果(电流率>=0.40f&&CurrentRate<0.60f)阶跃=0.025f;
否则,如果(电流率>=0.05f&&CurrentRate<0.40f)阶跃=0.0125f;
电流率-=步进;
_步骤=步骤;
translateX+=步骤*10500;
translateY+=步骤*8500;
todo=null;
}
else if(todo==“放大”)
{
浮动步长=0;
如果(电流率>=1.80f&&CurrentRate=0.80f&&CurrentRate<1.80f)阶跃=0.025f;
否则,如果(电流率>=0.03f&&CurrentRate<0.80f)阶跃=0.05f;
电流率+=阶跃;
_步骤=步骤;
//图1.刻度((一层+台阶),(一层+台阶));
translateX-=步骤*10500;
translateY-=步骤*8500;
todo=null;
}
transform.Translate(translateX,translateY);//transform是矩阵
e、 图形。变换=变换;
e、 图形.缩放转换(CurrentRate,CurrentRate);
这里是图纸本身:
for (int i = 0; i < drawBuffer.Count; i++)
{
//...
else if (drawBuffertype[i].ToUpper().Contains("DRAWTRACKRECTANGLE"))
{
e.Graphics.FillRectangle(new SolidBrush(Color.Red), drawBuffer[i][0].X, drawBuffer[i][0].Y, 6, 6);
}
else if (drawBuffertype[i].ToUpper().Contains("DRAWTRACKLINE"))
{
e.Graphics.DrawLine(new Pen(Color.OrangeRed, 2), drawBuffer[i][0], drawBuffer[i][1]);
}
for(int i=0;i
仍然像视频的第一部分那样画画。我只是缺少一些非常基本的东西…也许这段简单的代码可以帮助你。这一切都是在没有任何转换或缩放的情况下完成的。但是如果你对图形应用缩放,效果也一样
this.pictureBox1.Scale(new SizeF(2.5f, 2.5f));
所以
实际上,我将矩形的边定义为15个单位宽
private int RectSideLen = 15;
所以每次我点击图片框时,我假设我点击了要绘制的矩形的中心。这意味着我们的矩形将从点击位置减去半个矩形边开始
int cornerOffset = RectSideLen / 2;
Point newUpLeftCorner = e.Location;
newUpLeftCorner.Offset(-cornerOffset, -cornerOffset);
然后我将它添加到一个矩形列表中,并刷新图片框,用添加的新矩形重新绘制它
pictureBox1.Refresh();
在图片框的绘画事件中,我只画了一个预先计算好的矩形
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Red, 1))
{
foreach (Rectangle r in DrawBuffer)
{
e.Graphics.DrawRectangle(pen, r);
}
}
}
这是完整的样本
public partial class Form1 : Form
{
private int RectSideLen = 15;
private IList<Rectangle> DrawBuffer = new List<Rectangle>();
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
int cornerOffset = RectSideLen / 2;
Point newUpLeftCorner = e.Location;
newUpLeftCorner.Offset(-cornerOffset, -cornerOffset);
DrawBuffer.Add(new Rectangle(newUpLeftCorner, new Size(RectSideLen, RectSideLen)));
pictureBox1.Refresh();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Red, 1))
{
foreach (Rectangle r in DrawBuffer)
{
e.Graphics.DrawRectangle(pen, r);
}
}
}
}
公共部分类表单1:表单
{
private int RectSideLen=15;
私有IList DrawBuffer=新列表();
公共表格1()
{
初始化组件();
}
私有无效图片Box1u鼠标单击(对象发送器,MouseEventArgs e)
{
int cornerOffset=矩形边/2;
点newUpLeftCorner=e.位置;
newUpLeftCorner.Offset(-cornerOffset,-cornerOffset);
添加(新矩形(newUpLeftCorner,新大小(RectSideLen,RectSideLen));
pictureBox1.Refresh();
}
私有void pictureBox1_Paint(对象发送方,PaintEventArgs e)
{
使用(钢笔=新钢笔(颜色:红色,1))
{
foreach(DrawBuffer中的矩形r)
{
e、 绘图矩形(钢笔,r);
}
}
}
}
不是我的专业领域
…但您可以保留一个类级矩阵来表示“世界”的当前状态。您可以平移、缩放和/或旋转该矩阵来操纵世界。只需将该矩阵指定给e.Graphics。在绘制所有内容之前变换
现在,当用户单击时,您可以克隆该矩阵并将其反转(),允许您使用其TransformPoints()方法。这将从屏幕坐标转换为等效的世界坐标。将转换后的世界坐标存储在列表中,以便您可以在Paint()事件中重用它们
玩这个例子。在一个空白表单中添加两个按钮,并将它们的单击事件关联到下面的相应典型方法名称。运行它并单击屏幕上的几个点。现在单击第一个按钮旋转,和/或第二个按钮放大。现在通过单击表单上的更多点尝试添加更多点。单击按钮看看会发生什么。一切都应该保持相对(我希望):
公共部分类表单1:表单
{
私有矩阵MyMatrix=新矩阵();
私有列表点=新列表();
公共表格1()
{
初始化组件();
this.WindowState=FormWindowState.Maximized;
this.show+=新的EventHandler(如图所示为Form1_);
}
所示为void Form1_(对象发送方、事件参数e)
{
点中心=新点(this.ClientRectangle.Width/2,this.ClientRectangle.Height/2);
MyMatrix.Translate(Center.X,Center.Y);
this.MouseDown+=新的MouseEventHandler(Form1\u MouseDown);
this.Paint+=新的PaintEventHandler(Form1_Paint);
public partial class Form1 : Form
{
private int RectSideLen = 15;
private IList<Rectangle> DrawBuffer = new List<Rectangle>();
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
int cornerOffset = RectSideLen / 2;
Point newUpLeftCorner = e.Location;
newUpLeftCorner.Offset(-cornerOffset, -cornerOffset);
DrawBuffer.Add(new Rectangle(newUpLeftCorner, new Size(RectSideLen, RectSideLen)));
pictureBox1.Refresh();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Red, 1))
{
foreach (Rectangle r in DrawBuffer)
{
e.Graphics.DrawRectangle(pen, r);
}
}
}
}
public partial class Form1 : Form
{
private Matrix MyMatrix = new Matrix();
private List<Point> Points = new List<Point>();
public Form1()
{
InitializeComponent();
this.WindowState = FormWindowState.Maximized;
this.Shown += new EventHandler(Form1_Shown);
}
void Form1_Shown(object sender, EventArgs e)
{
Point Center = new Point(this.ClientRectangle.Width / 2, this.ClientRectangle.Height / 2);
MyMatrix.Translate(Center.X, Center.Y);
this.MouseDown += new MouseEventHandler(Form1_MouseDown);
this.Paint += new PaintEventHandler(Form1_Paint);
}
void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Transform = MyMatrix;
// draw the origin in the center of the form:
e.Graphics.DrawLine(Pens.Red, new Point(-10, 0), new Point(10, 0));
e.Graphics.DrawLine(Pens.Red, new Point(0, -10), new Point(0, 10));
// draw our stored points (that have already been converted to world coords)
foreach (Point pt in Points)
{
Rectangle rc = new Rectangle(pt, new Size(1, 1));
rc.Inflate(10, 10);
e.Graphics.DrawRectangle(Pens.Black, rc);
}
}
void Form1_MouseDown(object sender, MouseEventArgs e)
{
Matrix m = MyMatrix.Clone();
m.Invert();
Point[] pts = new Point[] {new Point(e.X, e.Y)};
m.TransformPoints(pts);
Points.Add(pts[0]);
this.Refresh();
}
private void button1_Click(object sender, EventArgs e)
{
MyMatrix.Rotate(10);
this.Refresh();
}
private void button2_Click(object sender, EventArgs e)
{
MyMatrix.Scale(1.1f, 1.1f);
this.Refresh();
}
}