Symbian的应用程序一般分为引擎和UI,其中引擎负责描述算法、数据结构等逻辑问题,UI则处理画图,用户界面等外在属性。
Series 60 SDK借鉴了MS VC的一些思想,例如App-Document-View的结构,不过Main Frame 被省略掉了,这应该是基于移动终端的特点而作出的合理取舍。写过VC的人对Document-View这个结构应该有很透彻的理解,概括来说,就是Document负责数据,View负责UI,也就是数据显示、画图等功能。 View通过GetDocument取得Document并依赖其完成用户动作和数据的同步。如果你写过kjava,那么不妨将view理解成Canvas,虽然它们有本质的不同。
在用VC Project wizard建立新的Series 60项目时,可以在EIKON Control 和Dialog Based两个模板中选择一个,同时还有一个是否用View 架构的复选项。
EIKON是基于所有EPOC设备的UI库调用,它大致分为两类,一类是有关数据存取的调用(和Document有关的调用),另一类是各种UI的控制。如果你选择EIKON这个模板,则应用程序的Main View(可以理解为主窗口)会从CCoeControl 类继承,如果选择Dialog Based,则Main View会从CEikDialog. 继承。
View架构是一个新的框架类型,如果采用这种框架,则应用由一系列的view组成,其中每一个view都具有普通UI的性能,例如有自己的UI栈。
CCoeControl实际上是所有控制类的基类,S60 SDK中所有控制类均由它派生而来,查查它的成员函数,就知道这个类是什么的干活:CapturesPointer(),、ActivateGc()、IsFocused(),再查查它的类继承树,看看,这些都是从它继承下来的:CEikAlignedControl、CEikBorderedControl 、CEikButtonGroupContainer 、CEikLabeledButton ……HOHO,是不是和Windows的CWnd极其类似??再看看它的父类,直接就是Cbase了。很明显,如果选EIKON Control,则意味着你要从基层做起,一步一个脚印,慢慢修练,实现各种各样的逻辑,最后弄出一个hello world,还累得一身臭汗。
CeikDialog在哪儿呢?Class Index里面找它不到,查找eikdialog.h,看看它的定义吧:
class CEikDialog : public CEikBorderedControl,public MCoeControlObserver, public MEikDialogPageObserver,public MCoeControlContext, public MaknFadedComponent
够烦的,这么多接口,这里就不一个个去研究了,有兴趣的不妨自己翻翻看这些接口都实现了什么功能。不过就从这个声明应该看出来, CeikDialog这个类实际上是封装了Dialog的一些功能,如果说用EIKON是用Windows SDK,那么用CeikDialog似乎就是用MFC,呵呵,不好意思老拿MS来乱比一气,大家不要扁偶! 此外,经常看到AVKON,AVKON是什么呢?SDK定义为:在UIKON上的扩展。我想应该是类似于以上这类扩展API吧?请达人指点……
下面来看看SDK Help的说法:
传统的应用程序框架(选择EIKON的框架):
Symbian应用一般使用从CCoeControl继承下来的自己编写的控件作为应用程序的view,也就是可以看得见的东东,这些控件都扔在应用控制栈中,可以根据应用程序的要求来创建、销毁、显示或者隐藏。
这种方式非常适合AVKON应用,也是最灵活的构建应用程序的方法,如果采用view体系,其明显的不足是它未能使用系统提供的view管理体系,不过这也是它的最大优势,因为它不受限于系统提供的view管理限制。
有许多现成的应用框架,如果你发现其中有的非常类似你的需求,那么你就可以借用一把……
呵呵,明白了,如果EIKON的框架,你能做的很多,系统替你做的很少,如果你有足够变态的需求或者想利用底层来做一些出类拔萃的事,那么相信它,没错的。不过,为了提高开发效率,最好还是先看看有没有现成的东西可以借用一下,如果修修补补能用,那就快多了。
再来看看基于对话框的框架:
对话框框架适用于那些大部分显示模式都是对话框形式的应用,例如主视图就是一个对话框。使用对话框的一个好处是:其内容和布局都可以通过修改资源文件来完成,而不用动任何c++代码,不过需要注意的是,嵌套的对话框很容易占用大量的栈空间,所以一定要小心小心再小心。
HOHO,文档建议如果用一个对话框作主视图(窗口)的话,最好是当一个非模态的对话框来运行。为什么呢?估计是因为各种切换需要。
说到对话框,偶又不得不说MS了,大家不会浪费银子去买鸡蛋吧?在VC里面,代码和资源是分开的,S60也借鉴了这个思想,它把诸如对话框的client区域,标题,以及所含的控件等都定义到了资源文件里面,资源文件名后缀为rhr,rss,还有个.loc,内容和VC的String Table差不多。例如用基于对话框的框架建立一个项目后,资源文件就会出现类似定义:
RESOURCE DIALOG r_test4_dialog { flags=EEikDialogFlagNoDrag | EEikDialogFlagNoTitleBar | EEikDialogFlagFillAppClientRect | EEikDialogFlagCbaButtons | EEikDialogFlagModeless; buttons=R_AVKON_SOFTKEYS_OPTIONS_BACK; items= { DLG_LINE { id=ETest4Dlg1Label;type=EEikCtLabel; control= LABEL { txt = ""; }; } }; }
flag这项太熟悉了,和Windows里PreCreateWindow(CREATESTRUCT& cs)简直有点雷同。这个flag相当重要,它设定了很多属性,例如,模态非模态可以通过EeikDialogFlagModeless来设置。所有这些标志可以在avkon.hrh里查到,其含义可以通过名字来理解。
View框架是 Symbian V6 DFRDs(DFRD:Device Family Reference Design. All products from the same DFRD are able to run the same thrid party software, content and services.)开始支持的,为了更适合S60应用的特点,AVKON在这上在作了一些优化和扩展。此框架允许应用注册各种各样的View,所谓View呢其实和窗口啊Canvas啊差不多,可以创建、销毁、激活、隐藏。每个应用每一时该只能有一个激活的View.这个激活了,那个就一定得隐藏,当View隐藏的时候,其所属的所有菜单,对话框或嵌入这个view的其它应用会统统close掉,当然,应用也可以让终端用户来控制各个view间的切换(激活或隐藏),需要注意的是,如个一个切换可能会中止应用程序,那么这个切换必须要能保护现场,此外,如果从应用程序A切换到应用程序B,然后再从B回到A,此时A不会自动激活他的View,而需要程序自己处理,这点是和Windows程序有很大区别的。
View在管理系统中是通过一个UID来标识的,View管理系统通过该UID来唯一标识某个View并实现对它们的调度,在通过VC App wizard实现的应用中,主View从CAknView继承而来,CAknView中有一个纯虚函数Id(),这是必须重载的,用于得到该View的标识。该ID可以自己定义,只要不重复就行了。
View的另一用途是作为消息传递中介,相信大家对消息传递这个机制可能比较清楚了,偶就不再废话。为什么View要能处理消息?因为在使用传统框架编写的应用中,view并不能直接控制显示页,和windows类似,如果你想让一个window干点什么事,最恰当的方法就是扔一个消息给它。
下面来看看CAknView中和消息传递相关的函数:
public:·IMPORT_C void ActivateViewL (const TVwsViewId &aViewId) ·IMPORT_C void ActivateViewL (const TVwsViewId &aViewId, TUid aCustomMessageId, const TDesC8 &aCustomMessage) ·virtual IMPORT_C void HandleStatusPaneSizeChange () ·virtual IMPORT_C void ProcessCommandL (TInt aCommand) ·virtual IMPORT_C void HandleCommandL (TInt aCommand) ·virtual IMPORT_C void AknViewActivatedL (const TVwsViewId &aPrevViewId, TUid aCustomMessageId, const TDesC8 &aCustomMessage) protected:·virtual IMPORT_C void DoActivateL (const TVwsViewId &aPrevViewId, TUid aCustomMessageId, const TDesC8 &aCustomMessage)=0 ·virtual IMPORT_C void DoDeactivate ()=0 ·IMPORT_C void ViewActivatedL (const TVwsViewId &aPrevViewId, TUid aCustomMessageId, const TDesC8 &aCustomMessage) ·IMPORT_C void ViewDeactivated () ·IMPORT_C TVwsViewIdAndMessage ViewScreenDeviceChangedL () ·virtual IMPORT_C void HandleForegroundEventL (TBool aForeground)
可以看出来,消息大都在View激活或隐藏时产生,头痛的是SDK Help对以上参数没有作任何解释,不知道哪位达人能详细解释一下??需要注意的是,DoActivateL这个调用可能在本View已经激活的情况下触发,所以这个函数必须能自我判断自己的状态并作出相应的处理,不然可能会产生一些意想不到的情况。最简单的处理方法是:当发现自己已经Activate时,就简单地return完事。