《holon 教程三,控件》

来源:互联网 发布:单片机脉冲计数程序 编辑:程序博客网 时间:2024/06/05 14:55

前头语:界面的相关开发,无非是定义控制件之间来往的路径,Windows系统以及很多系统的界面都是基于“消息”运作的。只要弄清楚控件之间是怎么样传递消息的就便可以开始做东西了。Holon 是专门针对“事务性数据系统”开发的一套语言,其所使用的框架是MFC的再封装,因此它的很多机制跟mfc完全相同,或者干脆说,它就是穿了马甲的mfc。接下来让我们先了解一下“消息”是怎么样传递的。

Message Tree ・  消息的传递路径

 

 

为能更好 的理解“消息”的传递,请把上图看作成一颗单纯的“树”,先不要去管holon中是怎么实现的。

当一个控件被选中的时候,它会发送一个“消息”给某个“事件处理模块”,这个处理模块可以是某个控件本身(假设每个控件都有一个对应的模块)。上图的传递过程是这样的,当控件(1)被选中的时候它会把“消息”会送给“事件处理模块”,如果我们把事件处理模块放到控件(1)中,这时“消息”停止传递,因为它已经处理了。如下图:

 
如果我们把“处理模块”放到“form”中,消息的传递路径如下图:


 
如果把消息想象成一个“小偷”,把处理模块想象成一个“警察”,很明显,哪里有警察小偷跑到哪里就会被抓住,然后小偷会被定罪(处理)。如上图所示,如果form也没有警察,警察在root中会怎么样?“小偷”的逃跑的路线(路径)会是什么样子?下图便是此路线:

 

很明显,这是一个后续遍历过程,至于“消息”会在哪个节点被“处理”,换句话说,小偷会在哪里被警察抓住,要看警察在哪里,即消息在哪里被处理要根据处理模块的位置。

警察放在哪里最好?在哪里把小偷抓住最好?我们先看看把警察放到上图“控件(1)”的位置效果如何,很明显我们需要在1~n个地点安排警力,这样带来的坏处也很显然了,这会很难管理分散在全国各地的警察。再来看另一种方案,假如事先我们已经知道了小偷的逃跑路线,他们都路过一个叫作“form”的地方,如上图所示,我们把警力安排在这里,下达给警察的命令只需要发送到一个地点就行,方便了管理。把这警察抓小偷的故事转换成“处理模块抓消息”来理解,我们把处理模块放到form中统一处理可以简化系统的接口复杂度,可以在一个地方管理所有处理模块。如果用先前警察抓小偷的方案一,如果有100个控件,它们会发送100个消息,100个消息需要在100个地方管理。

具体要把处理模块放到哪里要看开发要求,本人做过的一个项目要求在上图root节点初处理消息。这样做得好处前面已经介绍过了。

至于为什么消息经过的路径是一个后续遍历过程,这关系到了具体的实现细节,上图是从holon中类的基础关系抽象出的一个图,想一下,在面向对象语言中的多态,它的执行方式是不是跟上图一样的。

上面这些东西弄清楚后,再看看holon中是如何实现的,Holon中与界面有关的部件在工具中画好之后,必须用一个叫作prgen的工具生成其对应的代码。Prgen会为每个控件都生成一个对应的类,并自动指定他们的基类。本文档只关注信息怎么样传递的,具体工具的用法请看《PD部品制作方式》。
 
Prgen生成的代码其结构如上图所表示,每个控件都多重继承了两个类,在名为“Mediator”的类中对于控件的基本功能都实现了,例如从“输入框”中获得一串字符等等。控件同时还继承自form,它继承自root。如果取一个Lable中的值。一个控件被选中,消息被送出,处理结束的全过程见下图:


 

看这三个控件,“IgVMdEditText”、 “IgVMdButton”、 “IgVMdShowLabel”,当按钮被按下,因为它这里并没有“警察”,所以它发送了一个消息“ButtonClicked”(这个消息要自己定义)给了“IgVMdFmBaseForm”,最后消息送到了“IgVMdRt業務画面”处,在这个地方我放上了一个“警察”,消息“ButtonClicked”被逮住后,接着“IgVMdRt業務画面”对“IgVMdFmBaseForm”说“GetText”,它受到此消息后,接着给“IgVMdEditText”发了一条消息“GLC_iActWcGetText”,“ IgVMdEditText”并没有处理这条消息,而是将它直接抛向了父类“IxEditMediator”,这个类作了处理之后将结果返回给了“IgVMdRt業務画面”,蓝色的路径就是其返回结果。


 

 

“IgVMdRt業務画面”收到返回结果后,紧接着发了一条消息“ShowText”给“IgVMdFmBaseForm”,收到消息后,“IgVMdFmBaseForm”向“IgVMdShowLabel”发出了“GLC_iActWcStText”,最后“IxLabelMediator”处理了它,到此整个过程结束。

 


控件IgVMdButton类源代码:
method IgVMdButton::UtClick(callData : IfMediator) : boolean;
begin
    .parent.UtDoAction(ButtonClicked,callData);
    return callSuper(callData);
end UtClick;

IgVMdFmBaseForm源代码:
method IgVMdFmBaseForm::UtDoAction(InMsg : integer, callData : IfMediator) : boolean;
  begin
     select InMsg do
     case GetText =>
self.Child[.IgVMdEditText_Index].UtDoAction(GLC_iActWcGetText,callData);
     case ShowText =>
self.Child[.IgVMdShowLabel_Index].UtDoAction(GLC_iActWcSetText,callData);
      end select;
     return callSuper(InMsg, callData);
 end UtDoAction;

IgVMdRt業務画面源代码:
method IgVMdRt業務画面::UtDoAction(InMsg : integer, callData : IfMediator) : boolean;
  begin
      select InMsg do
      case ButtonClicked =>
self.Child[.IgVMdFmBaseForm_Index].UtDoAction(GetText,callData); self.Child[.IgVMdFmBaseForm_Index].UtDoAction(ShowText,callData);
      end select;
     return callSuper(InMsg, callData);
  end UtDoAction;