复杂界面的模块划分
界面的模块划分
对于比较复杂的程序框图,最好把它划分为多个子 VI。这样,每个子 VI 都不会太复杂,可以大大提高程序的可读性和可维护性。对于界面来说,也是如此。如果一个界面过于复杂,最好也把它划分为多个模块。这不仅利于程序本身的编写维护,还可以方便用户使用和操作界面。
有些程 序要求用户输入的信息非常多,比如,LabVIEW 的 "选项" 窗口就是如此:

这个窗口提供了 LabVIEW 中各种各样的设置信息,若是完全平铺在界面上,一个大屏幕也放置不下。而且,界面上的控件若是太多,用户也很难找到他所需的内容。因此,LabVIEW 选项界面把不同的设置按照功能的相似性,分成了若干组,每次只显示其中一组的设置信息。用户可以通过界面左侧的 "类别" 列表来选择显示哪一组的设置。
再另举一个例子。比如 LabVIEW 中的导入共享库工具,用于把 DLL 文件中的函数都包装成 LabVIEW 的 VI。这一过程会要求用户提供比较多的信息,如 DLL 的文件名、生成 VI 的名字等。它与前面的例子面临相同的问题。若一次把这些设置都显示给用户,用户就无从下手了。导入共享库工具采用了与 LabVIEW 选项窗口稍有不同的解决方案。它使用了向导型界面来帮助用户操作。向导型界面与 LabVIEW 选项界面的区别在于,它通过 "上一步"、"下一步" 按钮来切换当前显示的配置。如果程序所需的各种信息或设置之间有先后依赖关系,那么采用向导型界面更为合适。

前面介绍的两种类型的界面都有一个共同点,即把为数众多的控件按照相关性,分成多个组,每次只显示一组给用户,从而使程序界面变得清晰而且易于操作。
这两种界面在编程实现时,采用的也是类似的机制。唯一不同点是控制显示页面(即显示哪一组控件)切换的方式不同。一个可以显示任意一个页面;另一个只能按顺序切换页面。
下面以向导型的程序为例,说明如何实现这类有多个页面的界面程序。
选项卡控件
向导型的程序有多个页面,每个页面上有表示不同含义的各种控件,这正适合于使用选项卡控件。选项卡控件是一种在应用程序的设置对话框中非常常见的控件。它有多个卡片页组成,用户点击某一页对应的标签,控件就会把这一页的内容显示出来,而隐藏其它的卡片页。
在设计向导型程序的时候,可以利用选项卡控件的这一特征,使向导程序各页与选项卡上各页一一对应。把选项卡页面的标签隐藏起来,在程序中切换需要显示的页。

上图是一个向导型程序在编辑状态时的界面。若拉大 VI 前面板的显示区域,就可以清楚地看出,这个 VI 前面板上首先放置的是一个大尺寸的选项卡控件。其它用于程序运行时的控件都被放置在了选项卡的相应页上。
如果用户点击了 "下一步" 按钮,则在程序框图中通过设置选项卡的值,使其显示下一页面:
选项卡控件大大简化了程序界面的设计和编写,也方便了用户的使用。但是,它并不能显著地简化程序框图和改善程序的可读性和可维护性。这是因为即便使用了选项卡控件,用户所需要的所有控件还是全部被放置在了这个主界面 VI 上。对于这些控件的处理、包括对页面显示的控制代码全部都要在主 VI 上完成。对于比较复杂的界面,也许需要有十来个页面,那么前面板上所有的控件可能就会多达几十个。如果 VI 程序框图采用循环事件结构,也至少需要相应地处理几十个事件。
这样做的致命缺点有两个:
- 代码灾难: 所有数十个甚至上百个控件的处理逻辑(事件结构)全挤在一个程序框图中,代码将变得不可读、不可维护。
- 内存与性能瓶颈: 当主 VI 被加载时,所有选项卡页面中的控件、图片和子 VI 都会被一次性全部载入内存,即使有些页面用户根本没点开。这会严重拖慢程序启动速度并浪费内存。
下图中,也只显示了这个程序的一部分事件:

对于这样的程序框图,别说读懂它的程序逻辑,就算是要找到某一个事件,也要一条一条查看一阵子才能找到。假如你打算在原有的向导中增加一个步骤,其工作量会大大超出你的预想。因此,若想提高程序的可读性、可维护性,除了把界面分页之外,处理它们的程序代码也必须分成模块才行。