扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
绘制文档相关接口
大部分文档元素需要在文档视图中绘制内容,因此它们需要重载绘制文档的接口,这类接口主要有两个函数,一个是计算元素大小的函数,一般命名为 RefreshSize , 一个是绘制元素的函数,一般命名为RefreshView。
一般设计者指定元素的大小,元素本身不需要计算其大小,但某些元素可能是根据其内容自动设置大小,因此需要重载计算元素大小的函数RefreshSize来自动设置大小。自动设置大小可能只是设置元素的宽度或高度,也可能是同时设置其宽度和高度。同一个元素,可能在一种状态下不会自动设置大小,而在另外一种状态下需要自动设置大小。所有的这些操作都需要在RefreshSize函数中完成。
一般的设计元素都需要在文档视图中绘制内容,这时需要重载RefreshView函数,这个函数参数包含了一个System.Drawing.Graphics对象,元素需要使用这个Graphics对象来绘制自己特定的内容,可能是绘制文本,图片或其他图形。
当所有的文档元素都实现了绘制文档相当的接口,则在设计器的调度下,一个完整的设计文档视图就绘制出来了。而扩展设计器时,若需要指定新显示样式的元素时,需要重载RefreshView和RefreshSize函数来实现新的显示样式,此时扩展的设计器就能显示新样式的文档视图。
处理鼠标键盘事件相关接口
设计器中主要处理鼠标事件,文档基础元素可以定义一些处理鼠标事件的虚函数,名称可以为 HandleMouseDown , HandleMouseMove 和 HandleMouseUp 。
为了方便文档元素处理鼠标坐标,设计器在调用文档元素的HandleMouse函数时,首先将鼠标光标坐标进行转换,要将鼠标光标在视图区域中的坐标转换为文档元素内部的相对坐标,即相对于元素左上角的相对坐标。
设计器要依靠鼠标事件来实现设计元素的拖拽操作以实现互换式设计体验。关于鼠标拖拽操作典型的应用就是使用8个控制点来编辑元素边界。当一个元素边界是矩形时,会在元素的边界矩形的四个角和四个边的中点上分布8个控制点,当鼠标移动到这8个点时会修改鼠标光标样式,当鼠标光标在某个控制点上时,用户按下鼠标按键则开始进行鼠标拖拽操作,拖拽时会显示一个虚线绘制的边框,当松开鼠标按键则拖拽操作结束,此时设计器修改拖拽的元素的矩形边界。
某些文档元素并不进行标准的鼠标拖拽操作,例如对于容器元素,其内部的鼠标拖拽不移动对象而是画出一个选择矩形来选择若干个子对象;对于表格元素,它的表格线上的鼠标拖拽操作是修改表格行的高度和表格列的宽度;而对于线段则是修改端点位置。
当用户不小心按下鼠标按键,或只是选择某个元素而并不想进行鼠标拖拽操作,此时可以使用一个参数 System.Windows.Forms.SystemInformation.DragSize 来判断是否进行鼠标拖拽。当鼠标按键按下时,设计器就锁定鼠标,若鼠标按键按下后鼠标移动距离超出了 DragSize 的范围时,则表示用户是想进行鼠标拖拽操作的,此时开始真正的鼠标拖拽操作。若鼠标按键从按下到松开时鼠标移动距离始终没超出 DragSize 的范围,则表示用户没有进行鼠标拖拽操作的意图。这样的判断可以让设计器容忍用户的一些误操作。
设计器还要处理鼠标双击事件处理,对于某些包含文本的元素,用户双击该元素,则在设计视图中显示个文本输入框来直接编辑对象的文本内容。可以定义一个接口 ILabelEditable , 当用户双击某个元素,设计器发现该元素实现了 ILabelEditable 接口,则在设计视图中动态的显示一个文本输入框,然后调用该接口的成员来直接编辑对象文本内容。
维护文档对象树
文档基础元素要定义不少接口来用于维护文档对象树。要定义 OwnerDocument 属性来指定元素所在的文档对象,要定义 Parent 属性来指明元素的父节点,定义 Items 属性来指明该元素的子元素列表。对于容器元素,还要维护它的子元素列表。
设计文档对象作为文档树的根节点,担负着维护整个对象树的重任,包括文档整体的加载保存,文档整体的绘制,遍历整个对象树结构入口,还要为脚本提供接口。它是访问文档对象树的入口点。
一些比较基础的文档元素类型
可以从文档基础元素上派生一些比较基础的文档元素类型。这些比较基础的文档元素类型可以包括:
◆矩形元素基础类型,类型名称为DesignRectangleElement , 设计文档中大部分元素的边界是矩形,因此定义矩形元素基础类型作为这些矩形类型的元素的共同基础。矩形元素基础类型实现了使用8个点的控制点来修改元素位置和大小的能力,鼠标在对象边界只那的鼠标拖拽操作就可移动元素位置。此外还定义了内容和边界之间的边距信息。
◆线段类型,类型名称为DesignLineElement, 设计文档某些元素是以线段方式显示的,因此定义线段类型作为这些元素类型的基础类,线段类型定义了两个端点的位置,线段的显示样式,标签文档等信息。此外还重载了鼠标事件,使得用户可以使用鼠标拖拽线段的两个端点来修改线段端点的坐标。此外还要重载命中操作,用于判断某个坐标是否命中线段对象,若指定点距离线段的垂直距离小于某个参数,和点在线段某个端点上的拖拽点中则命中线段,否则没命中。
◆容器元素类型,类型名称为DesignElementContainer , 该元素可以包含若干个子元素,它是从DesignRectangleElement 派生的,因此它的边界是矩形。鼠标在容器中的拖拽操作不是移动容器,而是动态绘制一个选择矩形,当完成拖拽操作时,就根据这个选择矩形来设置子元素的选中状态。根据选择矩形来选择子元素有两种方式,一种是,若子元素边界和选择矩形粘边就被选中,另一种是,若子元素完全在选择矩形内部时才被选中。容器元素在绘制子元素时就执行矩形覆盖操作后再调用子元素的RefreshView成员。
◆带标题容器元素,类型名称为 DesignCaptionContainer , 该元素派生自容器元素,可以包含若干个子元素,但它顶端有个标题栏,可以显示文本,用户使用鼠标拖拽这个标题栏可以修改元素的位置。此外它还实现了 ILabelEditable 接口,当用户双击标题栏时可以直接编辑标题栏文本。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者