Symbian的UI Framework

  • Post author:
  • Post category:其他

应用程序类(CAknApplication->CEikApplication->CApaApplication)

文档类(CAknDocument->CEikDocument->CApaDocument)

应用程序UI类(CAknViewAppUi->CAknAppUi->CEikAppUi->CCoeAppUi)

视图类(CAknView)

1、实现全局函数E32Main(),该函数也称为应用程序入口点,当应用程序启动时,UI Framework将首先调用该函数。

GLDEF_C TInt E32Main( )

    {

   return EikStart::RunApplication( NewApplication );

    }

 

2、实现NewApplication()函数,该函数是由DLL导出的唯一函数。在NewApplication( )函数中创建应用程序类(CAknApplication)的一个实例,并返回它的指针,以后UI Framework使用该指针完成应用程序的创建。

LOCAL_C CApaApplication* NewApplication( )

    {

   return new CMyApplication;

}

这里应用程序类的实例是在堆上创建的,使用的是”new”方法,而非new (ELeave)方法,是因为TRAP harness还没有创立。

 

3、CMyApplication必须Override基类虚函数:

     TUid CAknApplication::AppDllUid( )

     返回应用程序的UID。该函数可用于确定应用程序的实例是否正在运行。

TUid CIRApplication::AppDllUid( ) const

    {

   return KMyAppUid;

}

 

4、CMyApplication必须Override基类虚函数:

     CApaDocument* CAknApplication::CreateDocumentL( )。

     UI Framework通过该函数获取新创建文档类(CAknDocument)的指针。

CApaDocument* CMyApplication::CreateDocumentL()

   { 

   return CMyDocument::NewL( *this ); // 必须传递应用程序类(CAknApplication)的实例给文档类

}

 

5、CMyDocument必须Override基类虚函数:

     CEikAppUi*CIRDocument::CreateAppUiL( )

    UI Framework通过该函数获取应用程序UI类(CAknViewAppUi)的指针。

CEikAppUi* CIRDocument::CreateAppUiL( )

    {

    returnnew (ELeave) CMyAppUi;

}

此处,AppUi实例创建时,使用的是c++默 认的构造函数,并返回该实例的指针,之后,框架通过该指针调用AppUi实例的ConstructL()函数来完成构造。

 

6、由CMyAppUi::ConstructL()具体创建整个应用程序。

ConstructL()首先调用BaseConstructL()载入程序相关的资源,然后创建需要加载的View类的实例,如果需要创 建多个view类的实例,需要调用AddViewL( )将新建的View实例加载进来,最后,如果是多个View时,通过 SetDefaultViewL( )函数设置缺省的视图。

 

voidCCoeAppUi::HandleWsEventL( const TWsEvent &aEvent,

                                                              CCoeControl *aDestination )

Handles events sent to the application bythe window server. This function is called whenever the window server sends keyor pointer events or some other special events to the application. It calls oneof a number of functions, according to the type of event.

 

For key events, it calls CCoeControl::OfferKeyEventL()for each control on the control stack, beginning with the control at the top(position 0) until a control consumes it. If no control on the stack consumesthe key event, CCoeAppUi::HandleKeyEventL()is called.

For pointer events, CCoeControl::ProcessPointerEventL() is called on the control specified in aDestination.

 

For other events, this function calls oneof the following CCoeAppUi private virtual functions:

·        HandleForegroundEventL()

·        HandleSwitchOnEventL()

·        HandleSystemEventL()

·        HandleScreenDeviceChangedL()

·        HandleApplicationSpecificEventL().

常见的symbian应用程序架构

1、基于控件CcoeControl。在自己的容器类中必须实现CcoeControl中的四个方法,框架将调用所有这些方法:

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

  Draw( ),绘制控件。 窗口服务器(window server)响应系统事件调用Draw( )函数,这里的系统事件指的是程序启动、应用程序获得焦点或者窗口刷新等。程序员不能直接调用Draw( )函数,如果希望进行屏幕重绘,则只能调用DrawNow()。此外Draw( )函数不能异常退出,因为该函数被直接调用,而框 架不知道如何处理异常。

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

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

 

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

  void CMyAppUi:::ConstructL( )

    {

    BaseConstructL();

    iAppContainer=CMyAppContainer::NewL( ClientRect() );

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

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

    }

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

2、基于对话框的架构。控件直接从对话框类家族继承而来。

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

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

  void CMyDlgAppUi::ConstructL()

    {

    BaseConstructL();

    iAppDialog=new (ELeave) CMyDlgDialog;

    iAppDialog->SetMopParent( this );

    iAppDialog->ExecuteLD( R_MYDLG_DIALOG );

    AddToStackL( iAppDialog );

    }

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

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

  CMyDlgAppUi::~CMyDlgAppUi( )

    {

    if( iAppDialog )

      {

      RemoveFromStack( iAppDialog );

      delete iAppDialog;

      }

    }

3、Avkon视图切换架构

CAknAppUi和CAknViewAppUi不是决定单视图和多视图的因素。CAknViewAppUi确实是为多视图设计的,与CAknAppUi相比,里面增加了多个视图的管理,相互切换以及一些事件回调,是S60的新多视图结构。但使用CAknAppUi也同样能实现多视图,因为其还是具备控件栈,可以容纳多个视图,但此时各个视图间的切换激活等机制需要自己实现,代码复杂些。

不过,这里的“视图”很容易让人产生误解。一般我们说MVC:模型-视图-控制器,但是这里的View其实对应的控制器,而Container对应的则是视图。

 

View类的一些重要函数

1)Id( )

3)DoActivateL()

4)DoDeactivate()

2)HandleCommandL()

5)iContainer:CXXXContainer* 指向容器对象的指针。

 

在激活时,需要创建视图对应的Container类(派生于CCoeControl,并实现接口MCoeControlObserver),并且调用Container的SetMopParent为自己,还要将这个Container加入到AppUi的控件堆栈(constrol stack)中。一般代码如下:

   iContainer = new (ELeave) CMyViewContainer;

   iContainer->SetMopParent(this);

   iContainer->ConstructL( AppUi()->ApplicationRect() );

   AppUi()->AddToStackL( *this, iContainer );

 

失活时则正好相反,需要

if ( iContainer )

    {

    AppUi()->RemoveFromViewStack(*this, iContainer );

    }

delete iContainer;

iContainer = NULL;

 

可以在资源文件(.rss)中创建一个AVKON_VIEW资源,分别指明hotkeys、menubar和cba等,然后将资源ID传递到视图的BaseConstructL()函数中。

 

AppUi和CAknView通过重载ProcessCommandL()实现了MEikMenuObserver接口,是菜单事件的观察者。它们对ProcessCommandL()的实现是通过各自的HandleCommandL()函数来完成的。

不同之处在于,AppUi的ProcessCommandL()会调用CAknView的ProcessCommandL()来处理菜单命令。所以,菜单命令首先由CAknView的HandleCommandL()处理,如果CAknView不处理,才会调用AppUi类的HandleCommand()进行处理。

 

如果要程序的view实例希望相应用户的按键,则必须将view实例通过AppUi的AddToStackL()函数加入到AppUi的控件堆栈(constrol stack)中。具体的流程如下:


版权声明:本文为edisonlg原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。