C# WinForms:获取光标相对于PictureBox图像的位置而非窗体
解决PictureBox绘图时鼠标坐标偏移问题
你的问题出在:当PictureBox的SizeMode为非Normal(比如StretchImage、Zoom)时,e.Location是相对于控件的坐标,但你直接在原始Image上绘图,两者的尺寸和显示比例不匹配,导致绘图位置偏移。
解决方案:将控件坐标转换为图像实际坐标
先实现一个坐标转换函数,根据PictureBox的SizeMode计算控件坐标对应的图像像素坐标:
private PointF GetImagePoint(PictureBox pb, Point controlPoint) { var imageSize = pb.Image.Size; var displayRect = pb.ClientRectangle; float scaleX = 1f; float scaleY = 1f; PointF offset = PointF.Empty; switch (pb.SizeMode) { case PictureBoxSizeMode.StretchImage: scaleX = (float)imageSize.Width / displayRect.Width; scaleY = (float)imageSize.Height / displayRect.Height; break; case PictureBoxSizeMode.Zoom: float displayScale = Math.Min((float)displayRect.Width / imageSize.Width, (float)displayRect.Height / imageSize.Height); offset.X = (displayRect.Width - imageSize.Width * displayScale) / 2; offset.Y = (displayRect.Height - imageSize.Height * displayScale) / 2; scaleX = 1 / displayScale; scaleY = 1 / displayScale; break; case PictureBoxSizeMode.CenterImage: offset.X = (displayRect.Width - imageSize.Width) / 2; offset.Y = (displayRect.Height - imageSize.Height) / 2; break; // Normal和AutoSize模式下坐标无需转换,直接使用 case PictureBoxSizeMode.Normal: case PictureBoxSizeMode.AutoSize: default: break; } float x = (controlPoint.X - offset.X) * scaleX; float y = (controlPoint.Y - offset.Y) * scaleY; // 确保坐标不超出图像范围 x = Math.Clamp(x, 0, imageSize.Width - 1); y = Math.Clamp(y, 0, imageSize.Height - 1); return new PointF(x, y); }
修改原有绘图代码
- 把
lastPoint的类型改为PointF(转换后的坐标可能是浮点数,提升绘图精度):
private PointF? lastPoint; private bool mouseDown;
- 修改MouseDown、MouseMove方法,使用转换后的坐标:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { lastPoint = GetImagePoint(pictureBox1, e.Location); mouseDown = true; } private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { mouseDown = false; } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (mouseDown && lastPoint.HasValue) { PointF currentPoint = GetImagePoint(pictureBox1, e.Location); using (Graphics g = Graphics.FromImage(pictureBox1.Image)) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.DrawLine(pen, lastPoint.Value, currentPoint); } pictureBox1.Invalidate(); lastPoint = currentPoint; } }
这样修改后,无论PictureBox用哪种SizeMode,鼠标位置都能准确对应到原始图像的像素位置,解决绘图偏移问题。
内容的提问来源于stack exchange,提问作者Darcy
相关产品推荐
相关产品推荐

