第四个需求 更好的显示测试项
最后写的那一段测试代码在哪里运行?这要记住放在那个主菜单项下,然后点击这个主菜单才能看到。最好能直接显示出来最后那个菜单项。
这个需求MainMenu就无法做到了,因为没有地方记录那个是最后插入的菜单项。
ActionList可以记录最后插入的Action,让菜单项关联Action,应该就可以显示最后插入的菜单项。获得最后的Action,找到与之关联的菜单项都不难,但怎么才能显示这个菜单项?
看看MainMenu的帮助,没有成员方法可以显示子菜单。但运行程序的时候,鼠标点击一下主菜单,会显示子菜单。追踪一下这段代码,应该有所发现。
很遗憾,TMenu很多行为是Windows控制的,没能找到显示子菜单的代码。上网搜了搜,大富翁论坛的离线数据中也搜了搜,果然也没有发现什么可行方法。
不过既然是Windows控制的,也许可以通过发送消息触发显示子菜单的代码。打开Spy++,看一下鼠标点击菜单时的消息,就是一个左键点击的消息。这个消息要带鼠标的坐标,也就是说要知道菜单项的位置信息。想想就觉得麻烦,还是知难而退,另辟蹊径吧。
有的软件有功能树,用来显示全部功能,用TreeView结合ActionList也许可以满足需求。TreeView不能在设计时与Action关联,需要在运行时遍历ActionList,把每个Action加入到TreeView中,Category作为一级节点,Action作为二级节点,Caption作为节点的Text,指针作为节点的Data。然后在Click事件中把Data转成Action执行。
现在测试代码的步骤变为:打开测试工程,打开相关窗体,打开ActionList编辑器,新建一个Action,双击Action,在Execute事件中添加代码,然后编译运行程序,点击TreeView节点,观看代码的作用。
需求解决了!
索性走的更远一些。1、类似ActionList转TreeView,MainMenu也根据ActionList在运行时自动建立。2、测试窗体显示的时候遍历TreeView,找到最后Action对应的节点,突出显示出来,让测试工作更简化。3、节点样式都一样,看着不方便,根据节点的Index显示过渡色。4、给TreeView增加一个排序功能,方便人工检索。
完美!?
这里还可以总结出一些解决疑问方法:1、看帮助。2、看组件的源代码。3、上网或者在离线数据中搜索解决方案。4、参考类似软件。
第五个需求 代码复用
按照最新的方案改好了一个窗体,再改另一个窗体时又出现了新问题:显示测试项的那些代码是每个窗体都需要,复制到每个窗体中肯定不是好方法。初学Delphi的时候有过惨痛的教训,同样的代码用一次复制一次,占用空间不说,以后要改进代码的时候,工作量那叫大!
公共函数!
把相同的代码做成公共函数,放在公共的单元中,在每个窗体中引用这个单元,调用公共函数。是一种解决方法,但不够好,调用公共函数的代码也是重复的,添加MainMenu和TreeView的工作同样是重复的。
类继承!
把重复使用的代码和组件提取到一个父窗体中,其他实际写测试代码的子窗体都从父窗体继承。窗体也是类,只不过附加了资源文件,也可以使用继承机制。
创建子窗体时节省了大量工作,只需从父窗体继承,上面的组件就放置好了,父窗体的成员方法也可以直接调用。优化或者添加公共功能时只需修改父窗体。编译后的程序尺寸也减少了。真是好处多多!
有一点需要注意,父窗体的imageList中不要放图片,否则子窗体会复制一份图片资源,让子窗体的体积变大。看来继承机制不是那么彻底。解决方法也简单,运行时加载图片就好。
只是,以前创建的窗体不易改造,走捷径就要修改dfm文件。
重复输入代码,重复放置组件,重复设置属性,只要是重复的工作都应该仔细考虑效率问题。重复输入代码,可以考虑公共函数和类继承。重复放置组件可以考虑窗体继承和DataModule、Frame。重复设置属性可以考虑存储到ini文件和注册表。整个程序的复用可以考虑动态链接库、COM+等。代码复用不仅可以一次做功多处使用,还方便日后升级和替换。
还不够?!
这里有一点需要注意:父窗体不用实例化,更不要放在第一个实例化,否则父窗体会成为主窗体。
第六个需求 窗体之间导航
窗体不止一个时,就要考虑窗体之间如何导航。一般程序开始只显示主窗体,需要显示其他的窗体时,再通过一个Action显示该窗体。
在采用继承方式前,每个窗体都要增加显示其他窗体的Action。采用了继承方式后,可以在父窗体中统一添加Action,新增一个窗体就新增一个Action,这样每个子窗体之间都可以相互导航。
工作量不大,可以满足需求。但实际测试过程中,多数情况下需要多次修改代码、编译、测试。每次都先显示主窗体,再打开子窗体,再测试代码,然后再关闭子窗体,再关闭主窗体,才完成一次测试,测试步骤有点繁琐!
当然可以在测试代码后,在IDE中用Ctrl+F2重置程序,但这样会忽略之后的异常,也无法保存窗体信息,还节省不了多少工作。不好!
在每次编译前,在工程选项中把要测试的窗体放在第一位,运行的时候就直接显示该窗体。这实际就是把这个窗体变成主窗体,也有点繁琐,不好,但指明了方向!
每次运行时,直接显示最后修改的窗体,效率最高。这就是目标!
看了看MainForm的帮助,Application对象创建的第一个窗体就是主窗体。根据窗体文件的保存时间,时间最靠后的就是最后修改的窗体,第一个创建这个窗体就能完成任务。但所有窗体创建前是无法遍历的,显然行不通。
主窗体不能改,但是可以不自动显示,而显示其他窗体。Screen对象中保存着所有自动创建的窗体,遍历所有窗体,通过运行时信息(RTTI)获得窗体文件名,找到最后修改的窗体,显示。完成!
等等,高兴早了。关闭窗体的时候无法关闭程序!
再看看MainForm的帮助,关闭主窗体才能结束程序。而现在主窗体并没有显示,无法关闭。所以要在关闭其他窗体的时候,再显示主窗体,然后关闭主窗体。
当然,代码只要写到父窗体中就可以。
完成!
在写遍历所有窗体代码时,联想到也可以通过遍历窗体自动创建显示窗体的Action,这样又省了些工作。删除一个窗体或增加一个窗体,都不用增加工作量。
完美!