为什么在Paint事件中绘制的是小正方形而非圆形?
问题原因排查
1. 缩放因子计算方向完全颠倒
你当前的缩放因子用图像尺寸 / 控件尺寸计算,这会导致椭圆尺寸被错误缩小(当图像比控件大时),甚至因整数截断变成极小的正方形。正确逻辑应该是将图像坐标转换为控件显示坐标,缩放因子应为控件尺寸 / 图像尺寸:
// 修正后的缩放因子计算 double xFactor = (double)pictureBoxPoints.Width / bitmap.Width; double yFactor = (double)pictureBoxPoints.Height / bitmap.Height;
2. 未适配PictureBox的SizeMode
如果SizeMode设为Zoom或CenterImage,图像会在控件内居中,存在空白偏移;若设为StretchImage,PictureBox会自动对Paint事件的Graphics应用拉伸变换,手动二次缩放会导致圆形被拉伸变形。
- 针对
Zoom模式,需先计算图像显示偏移量,再调整椭圆坐标:
此时int offsetX = (pictureBoxPoints.Width - (int)(bitmap.Width * scaleFactor)) / 2; int offsetY = (pictureBoxPoints.Height - (int)(bitmap.Height * scaleFactor)) / 2; int ellipseX = offsetX + (int)(point.X * scaleFactor) - ellipseSize / 2; int ellipseY = offsetY + (int)(point.Y * scaleFactor) - ellipseSize / 2;scaleFactor应取Math.Min(xFactor, yFactor)(Zoom模式按最小比例保持图像比例)。
3. 整数截断导致尺寸失真
直接用(int)强制转换会截断小数部分,导致椭圆宽高虽代码中一致,但实际显示因误差变成近似正方形。建议用Math.Round取整后再转换:
int ellipseSize = (int)Math.Round(5 * scaleFactor); int ellipseX = (int)Math.Round(point.X * scaleFactor) - ellipseSize / 2; int ellipseY = (int)Math.Round(point.Y * scaleFactor) - ellipseSize / 2;
4. 可选优化:开启图形平滑模式
虽不影响形状,但开启后椭圆边缘更圆润,避免锯齿:
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
修正后的完整代码示例
private void PictureBoxPoints_Paint(object sender, PaintEventArgs e) { if (pictureBoxPoints.Image != null) { Bitmap bitmap = pictureBoxPoints.Image as Bitmap; double xFactor = (double)pictureBoxPoints.Width / bitmap.Width; double yFactor = (double)pictureBoxPoints.Height / bitmap.Height; double scaleFactor = 1; int offsetX = 0; int offsetY = 0; // 根据SizeMode调整参数 if (pictureBoxPoints.SizeMode == PictureBoxSizeMode.Zoom) { scaleFactor = Math.Min(xFactor, yFactor); offsetX = (pictureBoxPoints.Width - (int)(bitmap.Width * scaleFactor)) / 2; offsetY = (pictureBoxPoints.Height - (int)(bitmap.Height * scaleFactor)) / 2; } else if (pictureBoxPoints.SizeMode == PictureBoxSizeMode.StretchImage) { scaleFactor = 1; xFactor = yFactor = 1; } e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; foreach (System.Drawing.Point point in _dotPoints) { int ellipseSize = (int)Math.Round(5 * scaleFactor); int ellipseX = offsetX + (int)Math.Round(point.X * xFactor) - ellipseSize / 2; int ellipseY = offsetY + (int)Math.Round(point.Y * yFactor) - ellipseSize / 2; e.Graphics.FillEllipse(Brushes.Red, new Rectangle(ellipseX, ellipseY, ellipseSize, ellipseSize)); } } }
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

