赞
踩
示例代码下载:http://download.csdn.net/source/950979
本示例演示如何实现用鼠标移动控件位置,如何用鼠标改变控件的大小,这两种功能分别由两个组件实现,ResizableComponent和MovableComponent
本示例演示效果如下,在窗体中用Panel控件模拟一个浮动窗口,移动到边缘区域时鼠标样式会改变为调整大小状态,按下鼠标进行拖动即可改变大小。移动到标题栏鼠标样式会改变为可移动状态,按下鼠标进行拖动即可移动控件位置。
可移动组件实现原理:
1、鼠标移动到指定控件上,改变鼠标样式为可移动状态
2、按下鼠标时记录鼠标的当前位置
3、鼠标移动时检测是否按下左键,如果按下左键则根据当前位置和之前记录的位置计算位移
4、根据鼠标的位移设置控件的坐标
5、鼠标离开则恢复默认鼠标样式
可移动组件实现要点:
1、被移动控件和响应鼠标操作的控件不一定是同一个,比如示例中列标题响应操作,内容区域不响应,移动的是最外层的那个Panel。需要设置两个属性,一个响应操作,一个被移动,两者可以一致。
2、响应操作的控件内部子控件也要有不同的响应,比如示例中标题栏中的图标和标题文字响应操作,但关闭按钮不响应。这里用扩展属性实现该功能,可以给内部控件添加一个是否响应操作的属性,让设置更加灵活。
可改变大小组件实现原理:
1、这里将控件分成9个区域,上左、上中、上右、中左、中央、中右、下左、下中、下右。中央区域被其他8个区域包围形成一个虚拟的边框。边框的宽度可以自定义,中央区域不响应操作,其他8个区域可以选择性响应操作。
2、鼠标移动过程中检测鼠标坐标。如果处在边缘处,则根据不同的位置设置不同的改变大小的鼠标样式。
3、在鼠标按下事件中记录下当前鼠标坐标
4、鼠标移动过程中,如果鼠标左键按下,则根据当前位置和之前记录的位置计算位移
5、根据鼠标位移和鼠标所处的区域,调整控件的大小和位置
6、鼠标移开时恢复默认鼠标样式
可改变大小组件实现要点:
1、内部控件可能覆盖边缘,内部控件也需要处理鼠标事件。和可移动组件一样通过扩展属性指示内部控件是否允许响应操作。
2、可响应改变大小的位置可以自定义,实现自定义UITypeEditor,可视化设置。
3、向上或向右改变大小需要同时改变控件的位置,非对角线方向改变大小时要忽略垂直方向上的位移。
下面介绍详细的实现过程。
枚举:
DirectionEnum:方向枚举,All-所有方向,Horizontal-水平方向,Vertical-垂直方向。该枚举在移动操作和改变大小操作中都可以用到。
ResizeHandleAreaEnum:改变大小可处理区域枚举,把需要处理改变大小的控件分成3*3的区域,除了Center区域,其他区域都允许响应鼠标操作。该枚举变量用自定义UITypeEditor进行编辑,后面再详细介绍。
MovableComponent组件的类图和类详细信息
MovableComponent组件包含5个属性:
Enable:指示组件是否可用
EnableInnerControl:指示是否允许HandleControl控件的内部控件响应鼠标操作。
HandleControl:响应鼠标操作的控件,可以和被移动的控件不一致,一般是被移动控件内部的控件。
MovableControl:被移动的控件。
MoveableDirection:控件可以被移动的方向,默认为All,不限制移动方向。
该组件需要处理的鼠标事件有鼠标移入、鼠标按下、鼠标移动和鼠标离开,实现代码如下:
另外为了实现扩展属性,必须实现IExtenderProvider接口,关于IExtenderProvider接口的详细介绍请参考MSDN。这里默认允许内部控件响应鼠标操作,只记录不响应操作的内部控件。实现该接口后还要在组件上添加特性,格式为[ProvideProperty("HandleMove", typeof(Control))]。将组件放到窗体上,设置好HandleControl之后,就可以看到HandleControl的内部控件都会增加一个movableComponent1 上的 HandleMove属性,和ToolTip控件类似。
该接口的实现如下:
实现IExtenderProvider接口后,将组件拖放到窗体上,设置相关HandleControl之后,则会为其内部控件增加HandleMove属性,效果如下图:
下面介绍ResizableComponent可改变大小组件的实现。
该组件的类图如下:
ResizableComponent组件的属性有:
Enable:指示组件是否可用
EnableInnerControl:当内部控件覆盖目标可缩放控件的边缘时,是否允许内部控件响应鼠标改变大小操作
MinSize:可缩放控件可以调整的最小尺寸
ResizableControl:目标可改变大小的控件
ResizeBorderWidth:响应改变大小操作的边框宽度,对应可缩放控件的内部虚拟边框,当鼠标移动到这一个虚拟边框中会改变样式
ResizeDirection:可改变大小的方向,水平、垂直和不限制
ResizeHandleAreas:响应改变大小操作的控制区域,用自定义UITypeEditor实现。效果如下图所示:
该组件处理目标控件的三个鼠标事件,MouseMove、MouseLeave和MouseDown。
MouseMove处理方法中,检测鼠标的坐标所处的区域,然后根据区域和允许调整大小的方向设置不同的鼠标样式。
如果鼠标左键按下,则检测鼠标的位移量,再根据所处的区域调整控件的大小和位置。
MouseDown处理方法中,记录下鼠标的位置,供调整大小时计算位移量。
MouseLeave处理方法中,恢复鼠标样式。
其他方法都是辅助检测和调整坐标用的。下面介绍如何实现自定义的UITypeEditor。这里定义了一个枚举ResizeHandleAreaEnum,用来标识调整大小的区域。因为设置的响应操作的区域允许有多个,所以这些枚举值必须都是2的次方数,在二进制中表示则都只有一位是1的,这样就可以通过位操作来解析值了。
枚举定义好之后,在项目中添加一个自定义控件,在其中放置8个CheckBox,设置Appearance属性为Button外观。然后排布为虚拟边框的效果,如下图:
该控件主要是将ResizeHandleAreaEnum枚举值和CheckBox控件的选中状态对应起来,通过位操作来解析和设置响应操作的区域枚举,内部代码如下:
为了让该枚举值在PropertyGrid中编辑时显示自定义的UI界面,需要继承UITypeEditor类,关于UITypeEditor的具体介绍请参考MSDN,这里的实现代码如下:
在该枚举上添加Editor特性[Editor(typeof(ResizeHandleAreaUITypeEditor), typeof(System.Drawing.Design.UITypeEditor))],之后只要使用到该属性,在PropertyGrid中显示的就是UI编辑界面。
另外本组件也用到了扩展属性,和之前的MovableComponent的实现方法类似,这里不再介绍。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。