CDiagramEditor - DIY 矢量和对话框编辑器






4.96/5 (155投票s)
一个功能丰富的矢量图编辑器骨架。
- 下载源代码文件 - 63.9 Kb
- 下载 DialogEditorDemo 演示项目 - 116 Kb
- 下载 DiagramEditorDemo 演示项目 - 80.6 Kb
- 下载 CDiagramEditor 文档 - 67.1 Kb
- 下载演示 DialogEditorDemo 的 EXE 文件 - 40.3 Kb
- 下载演示 DiagramEditorDemo 的 EXE 文件 - 27.2 Kb
DialogEditorDemo 应用
DiagramEditorDemo 应用
引言
所以你想为你的应用程序添加一个窗体编辑器?一个对话框编辑器?一个允许绘制 HTML <div>
s 的东西?这里有一个功能丰富的骨架(!)可以帮助你入门。CDiagramEditor
是一个提供基础视觉编辑器(用于矢量对象)的包。虽然可能不足以创建 CAD 应用程序,但你确实能够创建一个对话框编辑器。编辑器本身派生自 CWnd
,有一个单独的类处理数据,因此你可以将其用于对话框或文档/视图应用程序。
一些内置功能
- 完整的鼠标处理。绘制和拖动多个对象,拖动绘制,以及调整单个对象的大小。
- 纸张大小、边距和网格可轻松配置。
- 吸附到网格,将移动和调整大小限制在边距或纸张内。或者,如果你愿意,也可以在纸张外绘制。
- 可配置的键盘界面。
- 编辑器的插件弹出菜单。
- 无限缩放。
- 无限撤销。
- 支持保存和加载到
CString
/CStringArray
。 - 对于编程爱好者来说,编辑器中的不同绘图函数是虚拟的,所以如果你对外观不满意,可以派生一个类自己来实现。
- 矩形和线条的基础对象,你可以从中派生出你需要的绘图对象。
- 支持特定对象的弹出菜单。
- 支持特定对象的属性对话框。
还有更多。当然,这个包的使用起来会非常困难?不,只需将 CDiagramEditor
的一个实例添加到你的应用程序中,派生出你需要的绘图类,你就拥有了一个编辑器。
我添加了两个演示应用程序。较小的 DiagramEditorDemo 显示了基础知识,在一个对话框应用程序中添加了一个编辑器。
DialogEditorDemo 是一个 SDI 文档/视图应用程序,展示了如何使用独立的数据容器类,如何插入文档加载和保存,以及如何使用工厂创建绘图对象,如何添加打印和打印预览、自定义背景重绘、导出等等。
该包由以下类组成
CDiagramEditor
- 编辑器本身。CDiagramEntityContainer
- 编辑器数据的容器类。CDiagramEntity
- 绘图对象的基础类。CDiagramLine
- 一个CDiagramEntity
派生类,可用作线条对象的基础类。CDiagramMenu
- 弹出式编辑器菜单。CDiagramPropertyDlg
- 对象属性对话框的纯虚基类。
以及一些小型辅助类。
由于代码量很大,我添加了 HTML 文档,其中包含类的概述,以及一个关于大型类如何使用和类详细信息的页面。代码也进行了注释。
历史
时间的开始
最初发布。
1/5 2004
在密集地处理 CDiagramEditor
时,我对该包进行了一些增强,主要集中在
- 方便从
CDiagramEntityContainer
派生。 - 使多个编辑器可以使用同一个内部剪贴板。
第二个修改是为了能够在 MDI 应用程序中使用 CDiagramEditor
,你可能希望在编辑器之间复制和粘贴对象。这是通过将复制/粘贴功能从 CDiagramEntityContainer
中分离出来,并将其放入一个单独的类 CDiagramClipboardHandler
来实现的。
尤其令人恼火的是,在进行这些修改时,以 MDI 应用程序作为宿主,尽管属性对话框是以编辑器为父窗口创建的,但在 OnOK
处理程序中调用 GetParent
时,父窗口却返回了错误的值。因此,当对象发生更改时,编辑器无法正确更新。我不得不通过为 CDiagramPropertyDlg
添加一个显式的重绘父窗口来解决这个问题,并添加一个新的成员 Redraw
,在 MDI 应用程序中,派生类应该使用它而不是 GetParent()->RedrawWindow()
。
除此之外,我必须承认,在 MSVC++ 6.0 中重构(refactoring)确实是一件非常麻烦的事情,我以前以为只有软弱的人才会抱怨(我生命中至今为止所需的重构量非常少,难道是我运气好吗?)。
文档已相应更新,更改包括
CDiagramEditor
SendMessageToObjects
设置 selected-flag 为TRUE
- 仅将消息发送给选定的对象。- 使一些消息映射函数成为虚拟函数,以允许在派生类中进行增强。
- 添加了状态访问器,以允许派生类访问。
- Ctrl+单击项后将交互模式设置为
MODE_NONE
(以避免线条的非预期移动)。 - 在
Clear
中将滚动条位置设置为零。之前,在加载文档时,滚动条没有重置为 0,0。 - 将此窗口作为属性对话框的父窗口传递。这是为了在 MDI 应用程序中,在对话框发生更改后正确重绘编辑器。
- 将 C 风格的类型转换更改为
static_cast
。 - 移除了
ShowProperties
的const
属性。
CDiagramEntityContainer
- 使
RemoveAt
成为虚拟函数。 - 使几个撤销和复制/粘贴函数成为虚拟函数。为派生类添加了数组访问器。将成员函数
Find
移动到protected
部分。所有这些都是为了简化从CDiagramEntityContainer
派生。 - 复制/粘贴处理已移至一个单独的类(
CDiagramClipboardHandler
),以便多个容器可以共享同一个剪贴板。 - 将 C 风格的类型转换更改为
static_cast
。
CDiagramEntity
- 将
m_type
的访问器 -SetType
和GetType
- 更改为public
。 - 在
FromString
和GetString
中添加了冒号作为替换字符,用于保存。之前,包含冒号的名称或标题将无效。 - 在
ShowProperties
中为属性对话框添加了一个重绘父窗口。
CDiagramPropertyDlg
- 添加了一个重绘父窗口
m_redrawWnd
,用于在 MDI 应用程序中重绘正确的窗口。派生类现在可以使用Redraw
来更新编辑器。
如果您正在现有项目中 O使用 CDiagramEditor
,受影响的将是上面提到的“*设置交互模式...*”、“*设置滚动条位置...*”和“*添加冒号作为替换字符...*”。要使用新包,请重新下载源代码并用新文件覆盖现有文件,然后将 CDiagramClipboardHandler.cpp 和 CDiagramClipboardHandler.h 添加到您的项目中。
15/5 2004
对话框编辑器演示中的错误修复
演示中的 CDiagramEntity
派生对象的 Export
函数没有更新为 const
,因此未被导出机制调用。
13/6 2004
这肯定不是一个关键的更新。主要是我正在更新框架,因为即将有一个 UML 编辑器,其中一些东西已经被设为 virtual
或 const
,以便于派生编辑器。总之,继续列表
滚动时的虚拟大小检查
Graham 建议了这一点(见下文)。虽然滚动位置功能应该报告正确的值,但为了安全起见,我在 VScrool
和 HScroll
例程中加入了页面检查 - 不会不必要地尝试滚动一个没有滚动条的编辑器窗口。
为派生编辑器进行的修改
CDiagramEditor
- 在
SetInteractMode
中添加了对m_subMode
的访问。 - 使
OnObjectCommand
成为虚拟函数,以便在派生类中进行拦截。 - 使
GetBackgroundColor
成为 const。 - 使
SelectAll
成为虚拟函数。
- 在
CDiagramEntityContainer
- 使
GetAt
成为虚拟函数。 RemoveAll
,添加检查以查看对象数组中是否有任何项。- 使
RemoveAll
直接访问数据容器对象,以避免在派生类中发生连锁删除。适用于delete
是否应自动删除其他项。
- 使
谁应该更新编辑器代码?任何人尝试滚动到纸张区域之外时遇到问题?
8/7 2004
又到了更新的时候了!我添加了一些错误修正,一些增强功能以进一步帮助派生编辑器,并添加了一些新功能。修正包括
- 修正了
SetZoom
中的一个错误,该错误没有遵循最小尺寸(pgrohs)。 - 在
SetDiagramEntityContainer
的delete
后将m_internalData
置零,以避免崩溃(pgrohs)。 - 修正了
LeftAlignSelected
等中的对齐处理错误 - 原来是所有项目,而不仅仅是选定的项目被对齐了。 - 修正了
VirtualToScreen
中的错误,不再扣除滚动条位置(Wolfgang Busch)。 - 在保存/加载时,为了允许在标题和名称中使用换行符,添加了 `\\newline` 作为替换字符(Unruled Boy)。
增强功能
- 使
AddObject
成为虚拟函数,并添加了虚拟MoveObject
函数。这是为了允许在派生类中捕获编辑器中添加或移动的对象(sunmoon9898)。 - 使剪贴板函数和
DeleteAllSelected
成为虚拟函数。 - 添加了一个虚拟的
GetCursor
函数,以简化自定义光标的添加。 - 坐标转换函数已设为 public(Wolfgang Busch)。
- 使容器中的
Add
和Remove
成为虚拟函数。 - 为容器添加了
GetSelectCount
。
新功能
组
由 Unruled Boy 建议
现在可以通过右键单击编辑器并选择“组合”来组合选定的对象。组合的对象可以作为一个单元进行移动、复制和粘贴。通过右键单击并选择“取消组合”,可以移除选定项目的所有组合。
编程上,这可以通过调用 public 函数 CDiagramEditor::Group
和 CDiagramEditor::Ungroup
来实现。CDiagramEditor::UpdateGroup( CCmdUI* pCmdUI )
和 CDiagramEditor::UpdateUngroup( CCmdUI* pCmdUI )
可以作为命令启用器从例如视图中调用。
组合被实现为 CDiagramEntity
中的一个新属性。
注意事项
基于 CDiagramEditor
的演示应用程序的旧数据文件由于新的基本属性而不再与框架兼容。我认为这是一个可接受的权衡,希望不会造成不便。派生工作将需要更新以加载/保存此属性,并且我在 CDiagramEntity
中添加了简化此操作的功能:LoadFromString
、GetDefaultGetString
、GetHeaderFromString
和 GetDefaultFromString
。
一个典型的 FromString
在一个假设的 CDiagramEntity
派生类 CSomeEntity
中,带有一个额外的 CString
属性。m_someattribute
现在可以这样写
BOOL CSomeEntity::FromString( const CString& str ) { BOOL result = FALSE; CString data( str ); if( LoadFromString( data ) ) { CTokenizer tok( data ); CString someattribute; tok.GetAt( 0, someattribute); SetSomeAttribute( someattribute ); result = TRUE; } return result; }
其中 CDiagramEntity::LoadFromString
用于设置基类属性,其余属性从修改后的输入字符串中解析。
GetString
可以这样写
CString CSomeEntity::GetString() const { str.Format( _T( ",%s;" ), // Note the starting comma GetSomeAttribute() ); str = GetDefaultGetString() + str; return str; }
鼠标滚轮支持
由 John A. Johnson 建议。
通过在 CDiagramEditor
中处理 WM_MOUSEWHEEL
,现在可以使用鼠标滚轮滚动纸张。我曾考虑过使其更灵活。可配置的滚动步长和缩放功能浮现在脑海中,但这将不得不等到以后。OnMouseWheel
已设为虚拟函数,以便在此方向上进行个人尝试 :-)
平移
由 John A. Johnson 建议。
实现了平移。通过按下鼠标中键,会在光标处显示一个平移标记。如果移动鼠标,编辑器将朝着光标方向滚动。滚动量与标记和当前光标之间的距离成比例。光标会改变以指示当前的光标方向。我使用了内置光标来实现这一点,以避免对资源的依赖。
我检查了 P J Arends 的优秀类 CWindowScroller
,并确实有可能将其直接插入编辑器,但由于我希望 CDiagramEditor
拥有完全免费的许可证,我而是基于 MSDN(Visual Programmer 文章关于 George Shepherd 和 Scot Wingo 的平移)进行了工作。
这方面的主要函数是 OnMButtonDown
、SetPanning
和 DrawPanning
。
缩放到适合
由 John A. Johnson 建议。
此函数将设置缩放级别,以便当前图中的所有对象都可见。要调用的函数是 public 函数 ZoomToFitScreen
。
最后,非常感谢所有提供反馈的人(特别是上面归功于的 - 但欢迎所有反馈)关于这个框架。
4/8 2004
这次进行了一些小修复和添加。
- 添加了滚轮模式。通过调用
SetScrollWheelMode(WHEEL_SCROLL/WHEEL_ZOOM)
,滚轮将滚动或缩放。 - 为更多消息处理程序添加了虚拟函数,包括滚动条处理程序。
- 为
SetZoom
添加了虚拟函数。 - 添加了虚拟函数来设置滚动条位置,以便有一个统一的地方进行此操作。
- 错误:在
OnLButtonDown
中放置项目时,检查光标是否在约束之外。 - 添加了
ScrollIntoView
命令。该函数将当前选定的对象滚动到视图中。 - 错误:修复了选定标记的错误 - 鼠标坐标的虚拟化与选定标记矩形不一致(Marc G)。
- 向容器添加了
SelectAll
和UnselectAll
。
28/8 2004
虽然为时过早,但又一次的错误修正。再一次,非常感谢大家提供的反馈!
CDiagramEditor
:在OnLButtonDown
的命中测试中添加了对非规范化矩形的检查,因为线条有它们。CDiagramEntity
:在ctor
中将m_parent
设置为NULL
(Marc G)。CTokenizer
:将一个char
更改为TCHAR
以允许 UNICODE 构建(Enrico Detoma)。
25/3 2005
一次维护更新,并添加了一些内容
- 使
UnselectAll
成为虚拟函数(Grisha Vinevich)。 - 在
OnKeyDown
中添加了最小步长一像素,以避免箭头键的 0 像素移动(Graham G Pearson)。 - 使
UnselectAll
成为虚拟函数(Grisha Vinevich)。 - 添加了
PopUndo
函数,从堆栈中弹出最新的撤销项。 - 使
IsUndoPossible
成为 const。 - 使
SetParent
/GetParent
成为 public。
以及对线条选择机制的修正(Graham G Pearson)。
15/5 2005
又一次维护更新
- 通过一个虚拟成员函数路由所有对象选择,以允许自定义选择(Janiv Ratson)。
- 添加了一个重做命令。该命令将撤销最后一次撤销。处理程序和启用器与撤销一样,但消息处理的是
ID_EDIT_REDO
。键盘映射到 Ctrl+Y(Janiv Ratson)。 - 为
ID_EDIT_UNDO
添加了消息映射(Graham G Pearson)。 - 为
ID_EDIT_REDO
添加了消息映射。
注意:我只更新了 下载源代码文件 链接的源代码 - 没有更新演示项目。因此,请务必在使用代码到您自己的项目时下载此文件!
23/6 2006
迟来很久的又一次更新
- 添加了
PasteToPosition
函数(Janiv Ratson) - 错误:修正了
ZoomToFit
中的错误(DanMoshe) - 错误:修正了用鼠标调整多个组合对象大小时的错误(obeea)
- 错误:向
SendMessageToObjects
添加了 dirty 参数用于 dirty 处理 - 并非所有命令都应将文档标记为已更改(Janiv Ratson) - 错误:修正了
CDiagramEntityContainer
撤销堆栈处理,使其能考虑堆栈大小为 0 的情况(David Hoos) - 错误:在
CDiagramEntity::Copy
中添加了组到复制的数据(JeffBean) - 小的布局更改,并移除了冗余的滚动条处理(Alexey Shalnov)
注意:再次提醒,我只更新了 下载源代码文件 链接的源代码 - 没有更新演示项目。因此,请务必在使用代码到您自己的项目时下载此文件!