实现八个句柄调整区域大小的功能,包括光标切换和区域调整逻辑

This commit is contained in:
zqm
2025-11-07 15:12:24 +08:00
parent bbaa0ebde9
commit d511c3a93c

View File

@@ -35,6 +35,13 @@ namespace JoyD.Windows.CS
// 当前选中的区域索引
private int _selectedRegionIndex = -1;
// 句柄调整相关变量
private enum ResizeHandle { None, TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left }
private ResizeHandle _currentHandle = ResizeHandle.None;
private bool _isResizing = false;
private Point _resizeStartPoint;
private Rectangle _originalRectangle;
public Setting()
{
InitializeComponent();
@@ -61,7 +68,7 @@ namespace JoyD.Windows.CS
}
/// <summary>
/// 鼠标按下事件 - 处理右击退出绘制状态左击开始绘制矩形
/// 鼠标按下事件 - 处理右击退出绘制状态左击开始绘制矩形和开始调整区域大小
/// </summary>
private void PicBoxTemp_MouseDown(object sender, MouseEventArgs e)
{
@@ -88,6 +95,26 @@ namespace JoyD.Windows.CS
// 刷新绘制
picBoxTemp.Invalidate();
}
// 处理选中区域的调整大小
else if (e.Button == MouseButtons.Left && !_isDrawingMode && _selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
Rectangle controlRectangle = ImageRectangleToControlRectangle(selectedRegion.ImageRectangle);
// 检查是否点击在句柄上
_currentHandle = GetHoveredHandle(controlRectangle, e.Location);
if (_currentHandle != ResizeHandle.None)
{
// 开始调整大小
_isResizing = true;
_resizeStartPoint = e.Location;
_originalRectangle = controlRectangle;
}
}
}
// 处理左击开始绘制矩形
else if (e.Button == MouseButtons.Left && _isDrawingMode)
{
@@ -189,11 +216,43 @@ namespace JoyD.Windows.CS
/// <summary>
/// 鼠标移动事件 - 更新矩形大小检测鼠标悬停区域
/// 鼠标移动事件 - 更新矩形大小检测鼠标悬停区域或更新光标
/// </summary>
private void PicBoxTemp_MouseMove(object sender, MouseEventArgs e)
{
if (_isDrawing && _isDrawingMode)
// 处理调整大小
if (_isResizing && !_isDrawingMode && _selectedRegionIndex != -1)
{
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
// 计算新的矩形大小
Rectangle newRect = CalculateNewRectangle(_originalRectangle, _resizeStartPoint, e.Location, _currentHandle);
// 确保矩形有最小尺寸
if (newRect.Width > 10 && newRect.Height > 10)
{
// 转换为图像坐标并更新区域
Point imageTopLeft = ControlPointToImagePoint(new Point(newRect.Left, newRect.Top));
Point imageBottomRight = ControlPointToImagePoint(new Point(newRect.Right, newRect.Bottom));
selectedRegion.ImageRectangle = new Rectangle(
imageTopLeft.X,
imageTopLeft.Y,
imageBottomRight.X - imageTopLeft.X,
imageBottomRight.Y - imageTopLeft.Y
);
// 重新创建叠加层以反映变化
CreateRectangleOverlayImage();
// 触发重绘
picBoxTemp.Invalidate();
}
}
}
// 处理绘制新矩形
else if (_isDrawing && _isDrawingMode)
{
int width = e.X - _startPoint.X;
int height = e.Y - _startPoint.Y;
@@ -206,28 +265,56 @@ namespace JoyD.Windows.CS
picBoxTemp.Invalidate();
}
else if (!_isDrawingMode && !_isDrawing) // 就绪状态
// 处理鼠标悬停(更新光标或检测悬停区域)
else if (!_isDrawingMode && !_isDrawing && !_isResizing) // 就绪状态
{
// 将鼠标坐标转换为图像坐标
Point imagePoint = ControlPointToImagePoint(e.Location);
// 检查鼠标是否在某个区域内,选择索引号最大的区域
int newHoveredRegionIndex = -1;
int maxIndex = -1;
foreach (RegionInfo region in _drawnRectangles)
// 如果有选中的区域,检查是否悬停在句柄上
if (_selectedRegionIndex != -1)
{
if (region.ImageRectangle.Contains(imagePoint) && region.Index > maxIndex)
RegionInfo selectedRegion = _drawnRectangles.FirstOrDefault(r => r.Index == _selectedRegionIndex);
if (selectedRegion != null)
{
maxIndex = region.Index;
newHoveredRegionIndex = region.Index;
Rectangle controlRectangle = ImageRectangleToControlRectangle(selectedRegion.ImageRectangle);
ResizeHandle hoveredHandle = GetHoveredHandle(controlRectangle, e.Location);
if (hoveredHandle != ResizeHandle.None)
{
// 设置相应的光标
SetCursorByHandle(hoveredHandle);
return; // 不需要检查悬停区域
}
else
{
// 重置光标
picBoxTemp.Cursor = Cursors.Default;
}
}
}
// 如果悬停的区域发生变化,更新并触发重绘
if (newHoveredRegionIndex != _hoveredRegionIndex)
// 如果没有悬停在句柄上,检查是否悬停在区域上
if (_currentHandle == ResizeHandle.None)
{
_hoveredRegionIndex = newHoveredRegionIndex;
picBoxTemp.Invalidate();
// 将鼠标坐标转换为图像坐标
Point imagePoint = ControlPointToImagePoint(e.Location);
// 检查鼠标是否在某个区域内,选择索引号最大的区域
int newHoveredRegionIndex = -1;
int maxIndex = -1;
foreach (RegionInfo region in _drawnRectangles)
{
if (region.ImageRectangle.Contains(imagePoint) && region.Index > maxIndex)
{
maxIndex = region.Index;
newHoveredRegionIndex = region.Index;
}
}
// 如果悬停的区域发生变化,更新并触发重绘
if (newHoveredRegionIndex != _hoveredRegionIndex)
{
_hoveredRegionIndex = newHoveredRegionIndex;
picBoxTemp.Invalidate();
}
}
}
}
@@ -333,12 +420,22 @@ namespace JoyD.Windows.CS
}
/// <summary>
/// 鼠标释放事件 - 完成矩形绘制(优化版)
/// 鼠标释放事件 - 完成矩形绘制或调整大小
/// 使用增量绘制,避免每次都重绘所有矩形
/// 确保矩形坐标相对于图像而非控件
/// </summary>
private void PicBoxTemp_MouseUp(object sender, MouseEventArgs e)
{
// 结束调整大小
if (_isResizing && e.Button == MouseButtons.Left)
{
_isResizing = false;
_currentHandle = ResizeHandle.None;
picBoxTemp.Cursor = Cursors.Default;
return;
}
// 结束绘制新矩形
if (_isDrawing && _isDrawingMode && e.Button == MouseButtons.Left && picBoxTemp.Image != null)
{
_isDrawing = false;
@@ -693,6 +790,134 @@ namespace JoyD.Windows.CS
/// <summary>
/// 定时器每秒触发的事件处理方法
/// </summary>
/// <summary>
/// 获取鼠标当前悬停的句柄
/// </summary>
/// <param name="rectangle">控件坐标的矩形</param>
/// <param name="mousePoint">鼠标坐标</param>
/// <returns>鼠标悬停的句柄类型</returns>
private ResizeHandle GetHoveredHandle(Rectangle rectangle, Point mousePoint)
{
int handleSize = 8; // 句柄检测范围稍大,提高用户体验
// 检查各个句柄
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left - handleSize/2, rectangle.Top - handleSize/2, handleSize, handleSize)))
return ResizeHandle.TopLeft;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left + rectangle.Width/2 - handleSize/2, rectangle.Top - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Top;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Right - handleSize/2, rectangle.Top - handleSize/2, handleSize, handleSize)))
return ResizeHandle.TopRight;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Right - handleSize/2, rectangle.Top + rectangle.Height/2 - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Right;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Right - handleSize/2, rectangle.Bottom - handleSize/2, handleSize, handleSize)))
return ResizeHandle.BottomRight;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left + rectangle.Width/2 - handleSize/2, rectangle.Bottom - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Bottom;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left - handleSize/2, rectangle.Bottom - handleSize/2, handleSize, handleSize)))
return ResizeHandle.BottomLeft;
if (IsPointInRegion(mousePoint, new Rectangle(rectangle.Left - handleSize/2, rectangle.Top + rectangle.Height/2 - handleSize/2, handleSize, handleSize)))
return ResizeHandle.Left;
return ResizeHandle.None;
}
/// <summary>
/// 检查点是否在矩形区域内
/// </summary>
private bool IsPointInRegion(Point point, Rectangle region)
{
return region.Contains(point);
}
/// <summary>
/// 根据句柄类型设置光标
/// </summary>
private void SetCursorByHandle(ResizeHandle handle)
{
switch (handle)
{
case ResizeHandle.TopLeft:
case ResizeHandle.BottomRight:
picBoxTemp.Cursor = Cursors.SizeNWSE;
break;
case ResizeHandle.TopRight:
case ResizeHandle.BottomLeft:
picBoxTemp.Cursor = Cursors.SizeNESW;
break;
case ResizeHandle.Top:
case ResizeHandle.Bottom:
picBoxTemp.Cursor = Cursors.SizeNS;
break;
case ResizeHandle.Left:
case ResizeHandle.Right:
picBoxTemp.Cursor = Cursors.SizeWE;
break;
default:
picBoxTemp.Cursor = Cursors.Default;
break;
}
}
/// <summary>
/// 根据鼠标移动计算新的矩形大小
/// </summary>
private Rectangle CalculateNewRectangle(Rectangle original, Point startPoint, Point currentPoint, ResizeHandle handle)
{
Rectangle newRect = original;
switch (handle)
{
case ResizeHandle.TopLeft:
newRect.X = currentPoint.X;
newRect.Y = currentPoint.Y;
newRect.Width = original.Right - currentPoint.X;
newRect.Height = original.Bottom - currentPoint.Y;
break;
case ResizeHandle.Top:
newRect.Y = currentPoint.Y;
newRect.Height = original.Bottom - currentPoint.Y;
break;
case ResizeHandle.TopRight:
newRect.Y = currentPoint.Y;
newRect.Width = currentPoint.X - original.Left;
newRect.Height = original.Bottom - currentPoint.Y;
break;
case ResizeHandle.Right:
newRect.Width = currentPoint.X - original.Left;
break;
case ResizeHandle.BottomRight:
newRect.Width = currentPoint.X - original.Left;
newRect.Height = currentPoint.Y - original.Top;
break;
case ResizeHandle.Bottom:
newRect.Height = currentPoint.Y - original.Top;
break;
case ResizeHandle.BottomLeft:
newRect.X = currentPoint.X;
newRect.Width = original.Right - currentPoint.X;
newRect.Height = currentPoint.Y - original.Top;
break;
case ResizeHandle.Left:
newRect.X = currentPoint.X;
newRect.Width = original.Right - currentPoint.X;
break;
}
// 确保矩形不会变成负尺寸
if (newRect.Width < 0)
{
newRect.X += newRect.Width;
newRect.Width = Math.Abs(newRect.Width);
}
if (newRect.Height < 0)
{
newRect.Y += newRect.Height;
newRect.Height = Math.Abs(newRect.Height);
}
return newRect;
}
/// <summary>
/// 绘制矩形的八个句柄
/// </summary>
@@ -754,7 +979,7 @@ namespace JoyD.Windows.CS
private void PicBoxTemp_MouseClick(object sender, MouseEventArgs e)
{
// 仅在就绪状态(非绘制模式)下处理
if (!_isDrawingMode && e.Button == MouseButtons.Left && picBoxTemp.Image != null)
if (!_isDrawingMode && e.Button == MouseButtons.Left && picBoxTemp.Image != null && !_isResizing)
{
// 将控件坐标转换为图像坐标
Point imagePoint = ControlPointToImagePoint(e.Location);