HandleShapeStateBase

张开发
2026/4/7 10:49:07 15 分钟阅读

分享文章

HandleShapeStateBase
HandleShapeStateBase 详解 - 控制点交互状态基类usingH.LabelImg.ShapeBox.Shapes.Handles;usingSystem.Windows.Input;namespaceH.LabelImg.ShapeBox.State.Base;publicabstractclassHandleShapeStateBase:PreviewShapeStateBase{privateIHandle_hitHandle;protectedIHandleCurrentHitHandlethis._hitHandle;privateCursor_originalCursor;publicoverridevoidMouseDown(objectsender,MouseButtonEventArgse){base.MouseDown(sender,e);varpositione.GetPosition(this.GetElementView());this._hitHandlethis.HitHandle(position);if(this._hitHandle!null){e.Handledtrue;if(this._hitHandle.Cursor!null){_originalCursorMouse.OverrideCursor;Mouse.OverrideCursorthis._hitHandle.Cursor;}if(this._hitHandleisIMouseClickHandlehandle)handle.MouseDown(sender,e);if(this._hitHandleisIDeleteHandledeleteHandle)this.OnClickDeleteHandle(deleteHandle);}}protectedvirtualvoidOnClickDeleteHandle(IDeleteHandledeleteHandle){}publicoverridevoidMouseLeave(objectsender,MouseEventArgse){base.MouseLeave(sender,e);this.ClearHitHande();}publicoverridevoidMouseUp(objectsender,MouseButtonEventArgse){base.MouseUp(sender,e);if(this._hitHandleisIMouseClickHandlehandle)handle.MouseUp(sender,e);this.ClearHitHande();}publicoverridevoidMouseMove(objectsender,MouseEventArgse){base.MouseMove(sender,e);if(this._hitHandlenull)return;varpositione.GetPosition(this.GetElementView());if(this._hitHandleisIMoveToHandlehandle){handle.MoveTo(position);this.OnHitHandleMoved();}}protectedvirtualvoidOnHitHandleMoved(){}protectedvirtualvoidClearHitHande(){if(this._hitHandle?.Cursor!null)Mouse.OverrideCursor_originalCursor;this._hitHandlenull;}protectedoverridevoidClear(){base.Clear();this.ClearHitHande();}publicvirtualIHandleHitHandle(Pointpoint){returnnull;}}这是状态机系统中处理控制点交互的核心基类它实现了控制点的命中检测、拖拽移动、点击事件等完整交互逻辑。继承此类的状态可以响应用户对形状控制点的操作如拖拽缩放、移动形状等。 文件头部和引用// 版权信息同前// Copyright (c) HeBianGu Authors. All Rights Reserved.// ...省略usingH.LabelImg.ShapeBox.Shapes.Handles;// 控制点相关类usingSystem.Windows.Input;// 鼠标输入namespaceH.LabelImg.ShapeBox.State.Base;// 命名空间存放形状状态机相关的基础类️ HandleShapeStateBase 抽象类// 抽象基类用于处理控制点交互的状态// 继承自 PreviewShapeStateBase预览形状状态基类publicabstractclassHandleShapeStateBase:PreviewShapeStateBase{// 私有字段 // 当前被点击/选中的控制点privateIHandle_hitHandle;// 原始鼠标光标用于恢复privateCursor_originalCursor;// 保护属性 // 当前命中的控制点只读供子类访问protectedIHandleCurrentHitHandlethis._hitHandle;️ 鼠标按下事件// 鼠标按下 publicoverridevoidMouseDown(objectsender,MouseButtonEventArgse){// 1. 调用基类方法base.MouseDown(sender,e);// 2. 获取鼠标位置varpositione.GetPosition(this.GetElementView());// 3. 检测是否点击了控制点this._hitHandlethis.HitHandle(position);// 4. 如果点击了控制点if(this._hitHandle!null){// 标记事件已处理不再传递给其他控件e.Handledtrue;// 5. 如果控制点有自定义光标设置光标if(this._hitHandle.Cursor!null){_originalCursorMouse.OverrideCursor;// 保存原始光标Mouse.OverrideCursorthis._hitHandle.Cursor;// 设置控制点光标}// 6. 如果控制点支持鼠标点击调用其 MouseDown 方法if(this._hitHandleisIMouseClickHandlehandle)handle.MouseDown(sender,e);// 7. 如果是删除控制点调用删除处理方法if(this._hitHandleisIDeleteHandledeleteHandle)this.OnClickDeleteHandle(deleteHandle);}}️ 删除控制点处理// 删除控制点处理 // 虚方法子类可重写protectedvirtualvoidOnClickDeleteHandle(IDeleteHandledeleteHandle){// 默认空实现子类可在此执行删除逻辑// 例如从视图中移除形状}️ 鼠标离开事件// 鼠标离开 publicoverridevoidMouseLeave(objectsender,MouseEventArgse){// 调用基类方法base.MouseLeave(sender,e);// 清除当前命中的控制点this.ClearHitHande();}️ 鼠标释放事件// 鼠标释放 publicoverridevoidMouseUp(objectsender,MouseButtonEventArgse){// 调用基类方法base.MouseUp(sender,e);// 如果控制点支持鼠标点击调用其 MouseUp 方法if(this._hitHandleisIMouseClickHandlehandle)handle.MouseUp(sender,e);// 清除当前命中的控制点this.ClearHitHande();}️ 鼠标移动事件核心拖拽逻辑// 鼠标移动 publicoverridevoidMouseMove(objectsender,MouseEventArgse){// 调用基类方法base.MouseMove(sender,e);// 如果没有命中的控制点直接返回if(this._hitHandlenull)return;// 获取鼠标当前位置varpositione.GetPosition(this.GetElementView());// 如果控制点支持移动调用其 MoveTo 方法if(this._hitHandleisIMoveToHandlehandle){handle.MoveTo(position);// 移动控制点会更新形状this.OnHitHandleMoved();// 触发移动后的处理}} 控制点移动后的处理// 控制点移动后处理 // 虚方法子类可重写protectedvirtualvoidOnHitHandleMoved(){// 默认空实现子类可在此执行移动后的逻辑// 例如刷新视图、更新坐标显示等} 清除控制点// 清除命中的控制点 protectedvirtualvoidClearHitHande(){// 恢复原始光标if(this._hitHandle?.Cursor!null)Mouse.OverrideCursor_originalCursor;// 清空控制点引用this._hitHandlenull;}// 重写清除方法 protectedoverridevoidClear(){base.Clear();this.ClearHitHande();// 确保清除控制点} 命中检测抽象方法// 命中检测 // 抽象方法子类必须实现// 根据鼠标位置返回命中的控制点publicvirtualIHandleHitHandle(Pointpoint){returnnull;// 默认返回 null子类需要重写}} 设计目的这个状态基类的作用HandleShapeStateBase为需要处理控制点交互的状态如选择状态、移动状态提供了完整框架// 使用示例选择状态支持控制点拖拽publicclassSelectState:HandleShapeStateBase{privateIShape_selectedShape;publicoverrideIHandleHitHandle(Pointpoint){// 查找被点击的控制点foreach(varshapeinthis.GetShapeView().Shapes){if(shapeisIHandleShapehandleShape){varhandlehandleShape.HitIHandle(this.View,point);if(handle!null)returnhandle;}}returnnull;}protectedoverridevoidOnHitHandleMoved(){// 控制点移动后刷新视图this.RefreshShapeView();}} 完整子类实现示例示例1选择状态支持控制点拖拽publicclassSelectState:HandleShapeStateBase{privateIShape_selectedShape;privatePoint_dragStart;publicoverridevoidEnter(){base.Enter();this.SetCursor(Cursors.Arrow);}// 命中检测查找控制点publicoverrideIHandleHitHandle(Pointpoint){varshapeViewthis.GetShapeView();if(shapeViewnull)returnnull;// 从后往前遍历优先选择上层形状的控制点for(intishapeView.Shapes.Count-1;i0;i--){varshapeshapeView.Shapes[i];if(shapeisIHandleShapehandleShape){varhandlehandleShape.HitIHandle(this.View,point);if(handle!null)returnhandle;}}returnnull;}publicoverridevoidMouseDown(objectsender,MouseButtonEventArgse){base.MouseDown(sender,e);// 如果没有点击控制点检查是否点击了形状本身if(this.CurrentHitHandlenull){varpointe.GetPosition(this.GetElementView());SelectShapeAtPoint(point);}}privatevoidSelectShapeAtPoint(Pointpoint){varshapeViewthis.GetShapeView();foreach(varshapeinshapeView.Shapes){if(shapeisIHitableShapehitablehitable.Hit(this.View,point)){_selectedShapeshape;// 更新选中状态if(shapeViewisISelectShapeBoxselectBox){selectBox.SelectShapes(shapeasISelectableShape);}break;}}}protectedoverridevoidOnHitHandleMoved(){// 控制点移动后刷新视图this.RefreshShapeView();}}示例2删除控制点处理publicclassEditState:HandleShapeStateBase{protectedoverridevoidOnClickDeleteHandle(IDeleteHandledeleteHandle){// 弹出确认对话框varresultMessageBox.Show(确定要删除这个形状吗,确认删除,MessageBoxButton.YesNo,MessageBoxImage.Question);if(resultMessageBoxResult.Yes){// 获取被删除的形状varshapedeleteHandle.Owner;// 从视图中移除this.GetShapeView()?.Shapes.Remove(shape);// 刷新视图this.RefreshShapeView();// 清除选中状态if(this.ViewisISelectShapeBoxselectBox){selectBox.SelectShapes();}}}publicoverrideIHandleHitHandle(Pointpoint){// 查找控制点包括删除按钮varshapeViewthis.GetShapeView();foreach(varshapeinshapeView.Shapes){if(shapeisIHandleShapehandleShape){varhandlehandleShape.HitIHandle(this.View,point);if(handle!null)returnhandle;}}returnnull;}}示例3带光标变化的移动状态publicclassMoveShapeState:HandleShapeStateBase{privateVector_originalOffset;publicoverrideIHandleHitHandle(Pointpoint){varshapeViewthis.GetShapeView();// 只查找移动控制点中心点foreach(varshapeinshapeView.Shapes){if(shapeisIHandleShapehandleShape){varhandlehandleShape.HitIHandle(this.View,point);if(handleisMoveHandle)// 只处理移动控制点returnhandle;}}returnnull;}protectedoverridevoidOnHitHandleMoved(){// 移动后刷新视图this.RefreshShapeView();// 更新坐标显示UpdateCoordinateDisplay();}privatevoidUpdateCoordinateDisplay(){varshapeViewthis.GetShapeView();varselected(shapeViewasISelectShapeBox)?.SelectedShapes?.FirstOrDefault();if(selectedisRectShaperect){Console.WriteLine($矩形位置: ({rect.Rect.X},{rect.Rect.Y}));}}} 完整交互流程图用户鼠标移动 ↓ MouseMove 触发 ↓ 检测是否已命中控制点 (_hitHandle ! null) ↓ ├─ 是拖拽中 │ ↓ │ 调用 handle.MoveTo(新位置) │ ↓ │ 形状被更新 │ ↓ │ 调用 OnHitHandleMoved() │ ↓ │ 刷新视图 │ └─ 否正常移动基类处理预览 用户鼠标按下 ↓ MouseDown 触发 ↓ 调用 HitHandle(位置) 检测控制点 ↓ ├─ 命中控制点 │ ↓ │ 设置光标 │ ↓ │ 调用 handle.MouseDown() │ ↓ │ 如果是删除控制点调用 OnClickDeleteHandle() │ └─ 未命中正常选择逻辑 用户鼠标释放 ↓ MouseUp 触发 ↓ 调用 handle.MouseUp() ↓ 清除控制点 (_hitHandle null) ↓ 恢复光标设计模式分析1. 状态模式不同状态有不同的控制点交互行为。2. 策略模式通过HitHandle方法实现不同的控制点查找策略。3. 模板方法模式基类定义了控制点交互的完整流程子类只需实现HitHandle和必要的回调。4. 观察者模式鼠标事件触发控制点的方法调用。与其他状态基类的关系StateBase状态基类 ↓ ShapeStyleSettingStateBase样式设置 ↓ ShowEditStateBase显示编辑 ↓ PreviewShapeStateBase预览形状 ↓ HandleShapeStateBase控制点交互← 当前类 ↓ 具体状态 ├── SelectState选择状态 ├── MoveState移动状态 ├── EditState编辑状态 └── ... 更多总结成员类型用途CurrentHitHandle保护属性当前命中的控制点MouseDown()重写检测控制点、设置光标、触发点击MouseMove()重写拖拽控制点移动MouseUp()重写释放控制点、恢复光标MouseLeave()重写清除控制点HitHandle()抽象方法子类实现控制点命中检测OnClickDeleteHandle()虚方法删除控制点处理OnHitHandleMoved()虚方法移动后处理ClearHitHande()保护方法清除控制点核心价值完整交互支持控制点的命中检测、拖拽移动、点击事件光标管理自动切换和恢复控制点光标删除支持内置删除控制点的处理框架可扩展子类只需实现HitHandle方法典型应用✅ 选择状态拖拽控制点缩放/移动形状✅ 编辑状态显示删除按钮✅ 移动状态只处理移动控制点这个基类是控制点交互的完整解决方案为所有需要编辑形状的状态提供了强大支持

更多文章