CursorDialog


使用过ORDOpen Roads Designer)的读者应该对ORD中交互式工具随光标浮动的窗体有特别深的印象,如下图所示:

启动交互式工具以后,当光标在视图中移动时,光标右下方有一个小对话框会随着光标来回移动,而且当光标离开视图窗口时这个对话框会消失,再次回到视图窗口时又会显示出来。而且ORD SDK也封装了相应的编程接口来实现这个浮动窗体,其实我们也可以基于Mstn SDK的接口来达到同样的效果。在Mstn SDK中有一个名为“ViewCallback”的类型,此类型下有一个名为“SetMotionFunction“的函数,通过此函数可以设置一个回调函数。当光标在视图中移动时,我们设置的回调函数就会被不停地调用。我们在这个函数中可以获取到光标当前的坐标,然后将我们的窗体移动到光标处即可。如下是示例项目下载链接:

communities.bentley.com/.../CursorDialog.7z

编译后,启动Mstn打开任意dgn文件以后,执行keyin命令“mdl load CursorDialog;cursordialog active“可启动示例代码中的交互式工具,启动后我们在视图中移动光标时可以看到在光标右下方有一个随光标移动的窗体,如下图所示:

在这个窗体中显示了窗体当前的位置。接下来我们看一下代码中是如何实现的。

我们的这个示例项目是通过C++/CLI语言实现的,这是因为我们前面说的“ViewCallback”以及后面我们要用到的“IViewManager”等类型,目前Mstn SDK还没有提供C#的封装,所以我们不能直接通过C#语言来实现。但是我们的窗体又希望使用.Net的WinForm(WPF也可以)来实现,所以不得不采用C++/CLI混合语言来实现了。在“CursorDialog.keyins”文件中我们定义了插件包含的keyin命令,这里只有一个keyin命令“CursorDialog Active”,此命令对应的命令函数在“CursorDialog.cpp”文件里的“KeyinCommands“托管类型下,如下所示:

public ref class KeyinCommands
	{

	public:

		static void Test(System::String^ unparsed)
		{
			MyTool::InstallNewInstance();
		}
	};

命令函数中我们直接调用我们的工具类“MyTool”下的静态成员函数“InstallNewInstance()”来启动我们的工具(有关交互式工具的开发请参考:学习Microstation交互式工具开发)。工具类启动后我们重写的“_OnPostInstall”函数会被立即调用到,如下所示:

void MyTool::_OnPostInstall()
{ 
	m_form = gcnew FormShowCoor(this);
	IViewManager::GetManager().AddViewMonitor(m_viewMonitor);
	m_form->AttachAsTopLevelForm(CursorDialog::CursorDialogAddin::MyAddin, false);
	ViewCallback::SetMotionFunction(MyViewFunc_Motion);
}

在工具类的“_OnPostInstall”成员函数中我们对成员变量“m_form”做了初始化,然后添加了一个视图监视器“m_viewMonitor”。在这个视图监视器的类型中我们只重写了基类“IViewMonitor”的一个虚函数_OnViewEnterOrExit,这个函数会在光标移出或者进入某个视图时被系统回调。这样我们就可以保证我们的窗体只有当光标在视图中时才会显示,光标移出视图时就隐藏起来。“_OnPostInstall”函数的最后我们设置了光标在视图中移动时的回调函数“MyViewFunc_Motion”,在这个函数中我们去更新窗体的位置。最后我们在工具类的“_OnCleanup”函数中去关闭掉窗体,这样工具退出时窗体就会自动关闭了。

大家可能会有疑问,我们为什么不重写一下“DgnTool”类的“_OnModelMotion”或者“_OnDynamicFrame”函数去更新窗体位置呢?这是因为交互式工具类在使用过程中,会被视图类工具(例如平移,旋转视图)悬停执行,视图类工具退出后被悬停的工具类会恢复执行。如果在“_OnModelMotion”或者“_OnDynamicFrame”函数中去更新窗体位置的话,那么在视图类工具执行时,我们的窗体就会停止跟随光标移动。