您的位置:首页 > 产品设计 > UI/UE

【转】Symbian UI 架构

2009-12-23 11:29 204 查看
原文:http://wiki.forum.nokia.com/index.php/Symbian_UI_%E6%9E%B6%E6%9E%84

Symbian UI 架构

From Forum Nokia Wiki

Symbian OS的UI架构主要分成三种:

1. 传统的Symbian系统架构

2. 基于对话框的架构

3. 视图架构

下面将分开讨论三种架构的特点和优缺点:

1.传统的Symbian系统架构



如图所示程序中框架类主要继承自Avkon Framework的CAknApplication, CAknDocument和CAknAppui,另外容器类继承自CONE的CCoeControl。
使用Carbide C++建立一个包含UI的工程,默认的配置中所使用的架构就是这个传统的Symbian系统架构。
其中,CAknApplication是S60应用程序的基类,主要存储应用程序的属性,比如,可以通过重写OpenIniFileLC()的方式存储.ini配置文件等。
CAknDocument为文档类的基类。
CAknAppUi负责处理各种事件,比如HandleCommandL()。
在CMyContainer中可以包含一个或多个控制控件,实现界面的交互,并负责窗体描画事件。

优点是:比较简单和清楚的框架,并且可以加入自定义的控制和交互,比较灵活。
缺点是:没有系统提供的视图的管理方式。

在UIQ中与上述类对应的类是:
CQikApplication,CQikDocument,CQikAppUi

2. 基于对话框的架构



这种架构和第一种架构的区别是,使用了一个非模式窗体类CAknDialog来作为主窗体,窗体的设计可以在资源文件中定义,并且可以在不重新编译C++程序的前提下,通过改变资源文件的定义的方式,重新设计窗体。在实践中,这种架构的应用并不多。

3. 视图架构



这种架构的应用最为广泛,在SDK中也有一个叫MyView的例子程序,结合上图仔细读懂这个例子,应该就会清楚很多。

与前两种架构所不同的是,视图类继承自CAknView,并且可以在运行时生成和添加多个视图,并由系统所提供的ViewServer进行
管理,在制作稍微复杂一些,尤其是画面比较多的应用程序时,非常有用。但是在Carbide
C++中并没有提供默认的工程向导模板,不过可以自己制作一个以方便将来使用。

需要注意的是,与前两种架构不同的是,CMyViewAppUi继承自CAknViewAppUi,他的功能同样是负责接收各种事件,并
进行处理,而且可以在这个类中进行各种View的切换和更新激活视图。每个View有自己独立的ID,CAknViewAppUi利用这个ID在
ViewServer中注册相关的窗体,并调用不同的窗体,这种架构更面向对象,并且每个视图中封装了属于自己的数据和方法,实现了更灵活的应用。

symbian ui框架设计

所谓“应用程序架构”是指应用程序框架类的集合。基于所需的UI设计,应用程序可以具有稍微不同的架构,但是每种架构都有一些公共部分,称为“核心应用程序类”
  一、先看一下基础部分,具体架构在第二部分介绍

  (1)核心应用程序类.

  所有的S60 UI应用程序都具有一些基本功能:

  提供一个用户界面,用于显示信息并允许用户进行交互

  响应各种用户启动的事件,比如用户选择一个菜单项

  响应系统启动的不同事件,比如导致屏幕重绘的window服务器事件

  能够保存和恢复应用程序数据

  可以唯一性的向框架标志自身

  向框架提供有关应用程序的描述性信息,比如图标和标题等

  这些类是:视图(View)、文档(Document)、应用程序(Application)、应用程序UI(Application
UI)。

  一个程序只能有一个文档,可以有多个视图。

  (2)应用程序初始化

  必须创建下面的每个方法,才能提供最小的S60应用程序:

  a、所有S60
UI都实现一个全局函数E32DLL(),当应用程序启动时,框架将首先调用该函数,该函数也称为DLL入口点,应用程序必须存在该函数。每个S60
UI 应用程序都是一个多态DLL。

  b、让框架调用NewApplication(),该函数是由DLL导出的唯一函数。

  c、创建应用程序类的一个实例,并返回它的指针,以后框架使用该指针完成应用程序的创建。

  d、由框架调用AppDllUid()返回应用程序的UID。该函数必须返回在.mmp文件中指定的值,并且可用于确定应用程序的实例是否正在运行。

  e、框架获取指向新创建Document类的指针,CreateDocumentL()。

  f、NewL()具体去创建

  g、矿见获取AppUi类的指针,CreateAppUiL()。

  h、由new (Eleave)CappUi()具体创建。

  这样一个最简短直观的框架就创建完毕。

  (3)重要的AppUi方法:

  AppUi提供了许多方法,框架可以调用这些方法通知每个应用程序各种事件。

  HandKeyEvent()用于处理用户按键

  HandleForegroundEventL()当应用程序切换到前台或从前台切换到后台时调用该函数,默认的实现可以处理键盘焦点的改变。

  HandleSystemEventL()传递由窗口服务器生成的事件

  HandleApplicationSpecificEventL()可以自己定义的自定义事件的通知。默认的实现可以处理颜色方案改变的通知。

  HandleCommandL()用于处理用户选择的菜单项

  (4)设计应用程序UI

  关于术语“视图(view)”:

  “视图”是概念性的术语,含义是“数据模型在屏幕上的表示”,实际上由一个或多个从
CcoeControl派生而来的UI控件实现视图,这些控件按层次结构进行组织。父控件通常被称为容器(Container),除了用于实现视图的父控
件,这种控件被称为对话框(Dialog)

  在Avkon视图切换架构中,术语“Avkon视图”指的是系统范围内的View服务器注册的类,它控制视图的实例化和析构。

  二、常见的symbian应用程序架构:

  每种架构都提供了设计应用程序UI的不同方法――所有的架构都提供了提交“视图”或应用程序数据可视化表示的方法,同时提供了一种用户用来与架构进行交互的机制。

  先简单认识一下:基于对话框的架构和传统的基于Symbian
OS的架构虽不相同,但和Avkon视图切换架构相比,这两种架构彼此更为类似。原因是:

  它们的特征是它们用于生成视图的UI控件类型。

  架构上几乎相同。也就是说,在这两种设计中,AppUi类简单地“拥有”视图控件,因此负责直接管理它们。

  而Avkon视图切换架构从根本上不同于这两种方法,它的视图切换由系统范围地View服务器来完成。

  (1)基于控件的传统Symbian OS控件

  这些控件总是从CcoeControl直接继承,用于表示从CcoeControl直接继承的试图类的标准术语是“容器”。

  关于“CcoeControl”:

  可以将CcoeControl认为是一个空的帐篷。通过继承这个类,可以创建各种各样的自定义控件,自定义控件的功能和复杂性只受到程序员能力和想象力的限制。这种灵活性的唯一不利之处是,控件确实类似于一个空帐篷,因为需要进行许多编码工作来提供重要的功能。

  在处理视图切换方面,AppUi负责处理用户发出的视图切换请求。随后,AppUi最终的行为类似于一个巨大的开关,用于根据用户或系统的输入来激活或禁止容器。

  注意:Container类从CcoeControl派生而来,CcoeControl是所有控件的基类。

  在自己的容器类中必须实现从CcoeControl中的四个方法,框架将调用所有这些方法:

  SizeChanged()允许控件响应控件大小的改变

  Draw()绘制控件

  CountComponentControls()返回控件拥有的控件数量

  ComponentControl()对于容器拥有的每一个控件,框架调用该方法获取。

  在AppUi类中按照如下代码构造容器:

  void ChelloWorldAppUi:::Control()

  {

   BaseControlL();

   IAppContainer=ChelloWorldContainer::NewL(ClientRect());

   IAppContainer->SetMopParent(this);
//在控件之间建立父子关系,在容器上调用此方法。

   AddToStackL(iAppContainer); //将Container推入到控件栈顶,例如可以接收键事件

  }

  注意:如果使用这种架构实现带有多个视图的应用程序,则通过使用AddToStackL()和RemoveFromStackL()在不同的容器之间切换。

  (2)基于对话框的架构

  它不同于传统Symbian
OS架构的是,它拥有的控件直接从对话框类家族继承而来。

  对话框的主要优点是:相对于直接从CcoeControl派生而来的控件,它需要较少的开发工作,因为它们自动管理子控件的布局。

  在AppUi类中完成构造和运行:

  void CsimpleDlgAppUi::ConstructL()

  {

   BaseConstructL();

   IAppDialog=new(ELeave) CsimpleDlgDialog;

   IAppDialog->SetMopParent(this);

   IAppDialog->ExecuteLD(R_SIMPLEDLG_DIALOG);

   AddToStackL(iAppDialog);

  }

  因为对话框是无模式的,ExecuteLD()将在调用后立刻返回。必须使用AddToStackL()将对话框添加到控件栈中,因为无模式的对话框无法自己完成这项工作。

  还有,必须在AppUi的析构函数中销毁该对话框:

  CsimpleDlgAppUi::~CsimpleDlgAppUi()

  {

   if(iAppDialog)

   {

    RemoveFromStack(iAppDialog);

    delete iAppDialog;

   }

  }

  (3)Avkon视图切换架构

  比前两种都复杂,引入另一个类作为AppUi和容器之间的媒介。另外,AppUi类从CAknViewAppUi继承,而不是继承于CaknAppUi。

  前两个架构,AppUi直接负责处理视图切换,它必须管理视图提交控件的实例化、删除和显示。但是,基于CaknView的类在这方面可以很明显地减少AppUi地任务。

  AppUi仍然处理视图切换的请求,但现在,并不是删除旧的容器并实例化新的容器,AppUi只
需要调用它的其中一个特殊视图激活函数,如ActiveViewL()。这些特殊的CaknViewAppUi函数向View服务器提交一个激活请求,然
后通过基于CaknView的相关类中的激活/禁止成员函数,View服务器显式地协调当前视图地禁止和所请求视图的激活。

  这种架构所需的一般特性如下:

  必须设计应用程序,使每个CAknView派生的Avkon视图拥有一个容器,然后AppUi拥有每个Avkon视图。

  必须从CaknViewAppUi派生应用程序的AppUi,而不是从CAknView派生,这是因为前者提供了注册、激活和禁止Avkon视图的方法。

  必须在View服务器中注册所有的Avkon视图。

  Avkon视图具有激活/禁止成员函数,View服务器可以直接调用这些函数。必须重写这些函数,提供从属容器的正确处理。

  View服务器最主要的原则:确定在任意给定时刻,每个应用程序中只有一个Avkon视图被激活。Avkon视图通过两个UID向View服务器唯一性的标志自己:一个UID用于标志拥有该视图的应用程序,另一个UID用于在该应用程序中唯一标志该视图。

  对于每个基于CAknView的类,需要实现的激活/禁止函数是:DoActiveL()和DoDeactivate(),这些函数负责实例化和显示或者删除Avkon视图拥有的UI控件。

  View服务器将主动调用DeactivateView(),从而强制遵循每个应用程序中只有一个激活视图的规则。

  如何使用Avkon视图切换架构:

  使用这种架构时,必须结合使用CaknViewAppUi和CAknView类。每个Avkon
类都从CAknView派生而来,并且必须包含一个Id()函数,从而系统可以标志这个类。它也必须实现DoActivateL()和
DoDeactivateL()函数。此外,它还必须实现HandleForegroundEventL()、HandleCommandL()和
HandleStatusPaneSizeChange()函数,用于处理各种事件。

  用户请求激活视图时,View服务器将调用DoActivateL()。该函数的目的是实例化并显示提交视图的控件。

  注意:在DoDeactivateL()之前可以多次调用DoActivateL()。

  将要禁止Avkon视图时,则会调用DoDeactivateL(),该函数负责销毁它的控件。当应用程序退出时,或者激活相同应用程序的另一个视图时,将禁止视图。该函数绝对不能异常退出。

  只有在激活Avkon视图时才会调用HandleForegroundEventL(),即在调
用DoActivateL()和DoDeactivateL()之间。当视图到达前台时,接收
HandleForegroundEventL(Etrue),当从前台移除视图时,将接收
HandleForegroundEventL(Efalse)。程序员可能希望使用这种方法来设置焦点或控制屏幕更新。

  视图菜单生成一条命令时,调用HandleCommandL(),因为状态面板改变而使客户矩形大小改变时,则调用HandleStatusPaneSizeChange ()。

  为了让Avkon视图定义它自己的软键和菜单资源,可以在资源文件(.rss)中创建一个AVKON_VIEW资源,然后将资源ID传递到视图的BaseConstructL()函数中。

  通常在AppUi对象的ConstructL()方法中构造应用程序中的所有Avkon视图。使用AddViewL()在View服务器中注册这些Avkon视图,最终通过设置默认的视图来激活初始视图,使用方法SetDefaultViewL()。

  注意:不是由Avkon视图处理的命令被传递到AppUi,在AppUi的HandleCommandL()方法里,只进行视图间切换的命令。本地视图切换或者是应用程序拥有的视图切换,这些工作都通过引用目标Avkon视图的UID来执行。

  为了执行外部视图切换,则需要调用CcoeAppUi::ActivateViewL()函数,提供一个包含目标应用程序UID和目标视图UID的TVWsViewId。如:

  const Tuid KphoneBookUid={0x101f4cce}
;// from PbkUID.h

  const Tuid
kphoneBookContactViewUid={1};

  ActivateViewL(TvwsViewId(KphoneBookUid,KPhoneBookContactViewUid));

  注意:如果自己的程序中的某部分视图能够被其他程序使用,那么我们必须通过导出为头文件来发布应用程序UID和视图UID。

  三、选择适当的应用程序架构

  (1)使用Avkon视图切换架构

  大多数情况下,这种架构是最佳的架构,但它也具有局限性,如:视图切换方案没有任何内置的方法来
保存视图切换的上下文。也就是说,没有提供用于定位到前面激活视图的机制,没有类似于浏览器上后退功能的按钮的功能。但是DoActivateL()确实
收到了前面激活视图的标志符,因此可以自定义后退按钮功能。

  (2)使用基于控件的传统symbian OS架构:

  程序可能只需要一个视图

  应用程序具有UI控件,必须保证这些UI控件的私有性。

  如果是将应用程序从不同的symbian OS平台移植到series
60。

  (3)使用基于对话框的架构

  可以在资源文件中定义控件,让对话框自动处理布局和绘画,这比实现自定义绘画行为更为容易。仅当应用程序的视图之间没有任何循环导航路径时,才可以对这种应用程序使用“基于对话框”的方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: