一个Form的生命周期

今天ayang问起怎么显示一个Form,是不是用FrmGotoForm就可以的。我想想要说的内容颇多,不如写几篇文章把自己的一些经验浅薄知识介绍给大家,也算是尽自己一分心力。
前些天Hi-pda上已经有人开始声讨我做东西虎头蛇尾啦,这里表示歉意。希望更多开发者加入Palm开发阵营中来,也减小些自己的压力。
OK,言归正传,我想还是需要个例子来说明的。如果用PODS的话,New一个Standard Make 68K C/C++ Project,下一步下一步后选Simple Application;用CW9的话,New一个Palm OS C Application Wizard,在Step2时把About Dialog前打勾,其它都默认就行,工程名都随意,这篇文章里我就不来讲怎么编译,怎么运行,甚至开发环境安装了,只是说下标题中的Form的生命周期。
先说一个Form最简单的显示出来内部过程,那应该就是About Dialog的显示代码了,摘取PODS中的如下,是在主窗口的菜单事件处理中,即对选了显示关于时的处理

static  Boolean MainFormDoCommand(UInt16 command)
{
 Boolean handled 
= false;
 FormType 
* pForm;

 
switch (command) {
  
case MainOptionsAboutStarterApp:
   pForm 
= FrmInitForm(AboutForm);
   FrmDoDialog(pForm);     
// Display the About Box.
   FrmDeleteForm(pForm);
   handled 
= true;
   
break;

 }

 
 
return handled;
}



第8行的FrmInitForm (UInt16 rscID)函数,我想是任何资源窗口显示都需要的第一步,这个函数,传入rscID,然后在本程序的资源里找ID为rscID,类型的tFrm的资源,载入,返回一个FormPtr,即窗口指针,完成的是Form的初始化过程。第9行的FrmDoDialog (FormType *formP)就是把一个窗体显示出来了,但是这个窗体上的事件你没有办法自己处理,就是说你只能用来显示关于对话框一类的东西。第10行的FrmDeleteForm (FormType *formP)就是把当前窗口删除。基本可以理解为,FrmDoDialog时,是弹出一个新窗口盖在旧窗口之上,这时要删掉当前的关于对话框,来重新显示下一层的主界面。不过要执行到这个函数,显然是需要在FrmDoDialog后点击窗口的某按钮的,不然一直在那一步了。
应该说上面就是一个资源Form的创建显示到消失的过程,不过应该不是很常用的东西,我也说了基本上也就只能用来显示个对话框,不能处理操作之类,并且要完成这些,应该会有其它更容易的方法,后面说明。接下来讲一下,大多数正常的form的过程

我们来做一个例子,便于更好的理解,上面是用三个函数完成了About Form 的显示,我们把它改成正常窗口处理过程
1.首先,你会需要为一个窗口写一个EventHandler函数,用来处理这个窗口中的事件。一般来讲,我是直接把MainFormHandleEvent复制一份的:

static  Boolean MainFormHandleEvent(EventType *  pEvent)
{
 Boolean  handled 
= false;
 FormType
*  pForm;

 
switch (pEvent->eType) {
  
case menuEvent:
   
return MainFormDoCommand(pEvent->data.menu.itemID);

  
case frmOpenEvent:
   pForm 
= FrmGetActiveForm();
   FrmDrawForm(pForm);
   handled 
= true;
   
break;
   
  
default:
   
break;
 }

 
 
return handled;
}


 

复制是复制了,可不能直接用吧,至少至少,把函数名改掉对不对?改成AboutFormHandleEvent
然后注释掉这两行:
  case menuEvent:
   return MainFormDoCommand(pEvent->data.menu.itemID);
这两行对于MainForm来说,是指当当前窗口收到菜单事件时,会把这个处理传给mainFormDoCommand函数来处理的,这里我们的AboutForm没有菜单
解释一下,frmOpenEvent的处理,在这里,得到当前窗口的指针,调用FrmDrawForm将其绘制出来,这个处理是必须的,后面还要细表
然后我们还需要加进一个事件的处理

   case  ctlSelectEvent:
  
{
   
if (eventP->data.ctlSelect.controlID == MainClearTextButton)
   
{
    
/* The "Clear" button was hit. Clear the contents of the field. */
    FieldType 
* field = (FieldType*)GetObjectPtr(MainDescriptionField);
    
if (field)
    
{
     FldDelete(field, 
00xFFFF);     
     FldDrawField(field);
    }

    
break;
   }


   
break;
  }


这段是从CW的例子里MainFormEventHandler复制出来的,ctlEvent是一些常用控制组件被点击等时产生的事件,当然button也属于其中。这里一句if (eventP->data.ctlSelect.controlID == MainClearTextButton)是检查本次事件点击的组件是不是主界面的MainClearTextButton按钮,当然这里这么写是因为这个样例程序界面上只有一个按钮,实际上比较标准的写法是:

   case  ctlSelectEvent:
  
{
    
switch (eventP->data.ctlSelect.controlID)
   
{
               
case 组件1:
                                 
//点击组件1的事件处理
                                 break;
                             ...
                             
default:
     
break;
   }


   
break;
  }


这样就可以加很多了。对于我们这里的例子,我希望的是在About Form上点任意按钮就返回,所以直接加到default里的处理中,加一个FrmGotoForm(MainForm)

以上完成了一个事件处理的函数
然后是需要把这个函数和窗口“关联”起来,这个是在static Boolean AppHandleEvent(EventType* pEvent)这个函数中改的,对着MainForm那个改一下就成,我想你们会明白的
这里其实基本就已经完成了主要过程了,然后就是在需要的地方调用显示窗口的过程。比如你可以把程序中FrmGotoForm(MainForm)改成FrmGotoForm(AboutForm)试试,程序一运行就先显示AboutForm啦
或者我们应该把菜单处理中的刚才那三行删掉,改成FrmGotoForm(AboutForm),这样功能就和上面几乎一样了。

还是讲的乱了一些,主要是放进代码了,整理下思路,直接从原理上讲一下:
FrmGotoForm本身做不到显示这些功能,本身只完成一件事情,向事件队列里加入frmLoadEvent和frmOpenEvent。然后看系统的AppEventLoop函数(这是程序主循环,后面单独写文章说明下),里面会先调用AppHandleEvent,如果没处理才交给FrmDispatchEvent来做
那么在我们用了FrmGotoForm时,第一个事件是frmLoadEvent,这个事件会被AppHandleEvent处理掉,不得不讲,事实上这个函数唯一的作用就是处理所有frmLoadEvent,因为所有窗体事件在FrmDispatchEvent时被发送到各个窗口关联的事件处理函数去处理了,但是在一个新窗口创建时,不知道哪个是窗口关联的处理函数,所以先由AppHandleEvent来做下关联。AppHandleEvent里首先会把这个窗口从资源中载入,然后将其激活成当前窗口,此时窗口还没有绘制,比如你把AboutFormEventHandler里只写一句return true;那就会发现出现白屏了,下面一段switch就是将窗体和处理函数做关联了。
完成这一步后,窗体已经有自己的处理函数了,所以大多数事件其实都是在FrmDispatchEvent这步发回给处理函数自己处理的。前面FrmGotoForm产生两个事件,已经处理了frmLoadEvent了,frmOpenEvent这时会已经会被AboutFormEventHandler处理了,对于这个事件的处理一般就是FrmDrawForm把窗体画出来。不过还是建议看CW产生的代码,因为还有步比较重要的代码,会在这个事件处理中加入一个自定义函数MainFormInit()或者你直接把内容写在这里面也行。因为大多情况下,不是把原来做好的窗体显示出来就行了,比如一个记事本,打开一条记录的显示,或者比如一个程序的设置窗口,要显示原来设置好的值吧,即需要载入一些动态数据,这一般都是在frmOpenEvent中处理的。
基本上就是这样了,然后把相关的东西一并说下:
1.关于前面说了对内容的显示用什么东西好,应该说可选的其实只有两种方式,alert和form,对于alert显示非常方便,不用initform这些,一次调用就行,缺点是不能用其它组件(除了可以加一个field,并且是系统自动加的,来提供最简便的输入字符串方式),而form就需要init,draw这些必要步骤不可少。那么为什么AboutForm不像我们改的那么复杂,只用了三行呢?因为它只有一个按钮,不需要加其它组件,那为什么不用alert?因为alert只能显示字符串,不能自定义字符串的位置,字体等等。
顺便提一下,还有一种很特殊的显示需要,即比如显示help这种大段的纯文字内容,可以用FrmHelp这个函数,这个和上面讲的方法都不同
2.上面说的都是FrmGotoForm,那么还有个FrmPopupForm是什么?也是显示窗口的,区别在于,用FrmGotoForm时会先关掉当前窗口,然后打开新窗口,用PopupForm时只是把新窗口开在上层。所以对于Popup出来的窗口,要回原窗口时一般是用FrmReturnToForm的。
3.frmCloseEvent: 这个事件上面忘提了,一般你也应该在窗口事件处理函数中对这个事件进行处理,窗口关闭时会触发这事件,一般在这事件中保存当前窗口中的内容,比如memo中虽然你没点ok,退出程序时还是会保存,你可以理解为在这个事件中处理了
4.frmUpdateEvent:这个也是CW产生代码中自带的处理,虽然没有实际内容。看帮助吧,以后会用到的
5.一些非正常方式的窗口过程:上面讲的FrmInitForm是从资源里载入原先设计好的form,但是如果要自己动态创建一个form呢?用FrmNewForm,参数很多,自己慢慢研究。我想说的是,除了想把程序做复杂点,防止破解外,基本没有必要自己创建窗口。当然对于比如输入法提示框,可能动态创建会更好用些,不过即使是这样,连巨硬都是先设计好输入框再载入的。说到输入法,要提一个和上面不一样的form过程。至少巨硬和我的Treo五笔是的,即那个Form基本上在init后,不是用FrmDrawForm画出来的,而是完全自己画边框这样一步步出来的,那为什么还要用form?为了FrmSetActiveForm这步,把当前的活动区域变成自己的,即事件要给当前活动窗口来处理啊。

先讲这些吧,有问题回复本文 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值