Symbian UI程序基本框架

 以下转自Nokia Symbian手册汇编:

资源文件

指定了应用程序的相关信息,包含要显示的控件定义(如菜单,对话框等),是所有应用程序所必须的。
资源文件的后缀名为<application name>.rss。最多可以包含4095个资源。
一个应用程序可以包含多个资源文件,并在运行时动态加载其他资源文件。
Uikon预先定义了许多在资源文件中可以使用的结构体。
资源文件需要编译成二进制文件,在C++代码中需要include编译产生的.rsg文件。
具体的文件及解释如下:

// 4 letter ID 该字段必须每个应用程序唯一

NAME S60R   

//  INCLUDES  包含已经定义的资源结构

#include <eikon.rh>

#include <avkon.rh>

#include <avkon.rsg>

#include <appinfo.rh>

//hrh用于包含枚举常量,如菜单项;rls定义了在UI中使用的字符串

#include "S60ResourceLab.hrh"

#include "S60ResourceLab.rls"

//允许应用程序指定版本号,可选

RESOURCE RSS_SIGNATURE

    {

    }

//为该应用程序的默认文件指定一个名字

RESOURCE TBUF r_default_document_name

    {

    buf="HEWB";

    }

//指定了所要显示的菜单和soft keys

RESOURCE EIK_APP_INFO

    {

    menubar=r_s60resourcelab_menubar;

    cba=R_AVKON_SOFTKEYS_OPTIONS_BACK;

    }

菜单相关:

//定义了需要显示的menu pane,txt字段为空(S80中才有位置显示菜单的title,S60没有)

RESOURCE MENU_BAR r_s60resourcelab_menubar

    {

    titles=

        {

        MENU_TITLE { menu_pane=r_s60resourcelab_menu; txt=""; }

        };

    }

//menu pane定义了一系列menu items,command就是HandleCommandL中接收的命令参数,txt显示给用户。

RESOURCE MENU_PANE r_s60resourcelab_menu

    {

    items=

        {

        MENU_ITEM { command=EAknCmdExit; txt="Exit"; },

        MENU_ITEM { command=ES60ResourceLabCmdAppTest; txt="Test"; }

        };

    }

字符串相关:字符串的内容真正定义的位置是在本地化文件中,见后。

RESOURCE TBUF r_s60resourcelab_text_goodbye

    {

    buf = qtn_s60resourcelab_text_goodbye;

    }

RESOURCE TBUF r_s60resourcelab_text_everyone

    {

    buf = qtn_s60resourcelab_text_everyone;

    }

Localisation Files    每种显示给用于的语言都有一个本地化文件,在该文件中包含所有需要翻译的语言。

可以在rss文件中被条件包含,如下所示:

#ifdef LANGUAGE_01

    #include "HelloWorld01.rls"

#elif defined LANGUAGE_02

    #include "HelloWorld02.rls"

#endif

    示例:keyword symbolic_identifier the_string

rls_string qtn_caption_string "S60 Resource Lab"

rls_string qtn_s60resourcelab_text_goodbye "Goodbye"

Resource Compilation    资源编译器将rss文件编译为rsc文件,中间产生一个rsg的头文件。

    C++代码中使用resource需要包含rsg头文件,使用方法如下:

HBufC* textResource = StringLoader::LoadLC( R_COMMAND1_TEXT );

iLabel->SetTextL(*textResource);

CleanupStack::PopAndDestroy( textResource );

读后感Symbian的资源对于初学者来说也是一个很棘手的问题。

往往添加一个menu item需要同时改很多地方,稍不小心就N多错误,让人摸不着头脑。

但是熟悉之后,一切都显得那么自然,也许这就叫熟能生巧吧,呵呵。

 

peter (2007-11-04 16:07:01)

Basic Application Structure    一般应用程序都分为UI和Engine两部分。


UI负责显示和接受用户命令
Engine负责处理数据,可以被其他应用程序重用
Basic Application Classes    下图展示了一个最基本的应用程序类图,其中每部分的作用如下:

Application:返回UID3,创建Document类
Document:主要创建Application UI,也可以从文件中读写状态数据
App UI:主要的用户界面,本身不可见,但是拥有可见控件,主要处理菜单命令和按键事件
View/Container: 包含用户可见的控件,一个应用程序中可能有多个view或container
Model:根据应用程序情况的不同,可能被Document,AppUI或者View所拥有
Class Derivations    下图展示了一个CMyApp应用程序的类继承关系,总共有四层:

 

 

 

最上层:CMyApp类,用户应用程序相关类
Avkon层:CAkn类与S60应用程序框架相关的类
Uikon层:CEik类勾勒出应用程序框架,在所有的UI设计中(如S60,UIQ,FOMA等)都存在
AppArc层:CApa类定义了最基本的应用程序接口
CONE层:CCoe类定义了最基本的可见控件(CCoeControl),底层的异步事件处理(其他两个)。
Startup Sequence    下图解释了应用程序框架类的创建顺序,当应用程序开始时,首先调用的是E32Main()函数,由它调用应用程序框架来产生应用程序对象。具体过程如图所示,可以对照一个HelloWorld GUI程序看看:

 需要注意的地方:最后一步,只有当CCoeControl::ActivateL()被调用并且控制返回到系统的Active Scheduler(应用程序事件循环),Container的Draw()才会被调用,即控件才会显示出来。

Appcliation Entry Point    Symbian中的每个应用程序都运行在其自己的进程中,必须实现以下两个全局函数(通常向导已经帮你生成了):


E32Main():应用程序主入口,调用系统框架函数EikStart::RunApplication()来初始化和运行应用程序
NewApplication():应用程序进程创建一个应用程序实例,该实例必须继承自CApaApplication
以上信息专门针对Symbian 9.x,在以前的版本中,应用程序是作为一个多态的Dll实现的。


下面详细介绍一个应用程序框架中各个主要的类

Application Class     当应用程序启动后第一个产生的类,继承自CAknApplication,它定义了一个应用程序最基本的行为。

class CMyAppApplication : public CAknApplication

    {

    public: // Functions from base classes

        TUid AppDllUid() const;

    protected: // Functions from base classes

        CApaDocument* CreateDocumentL();

    };

该类主要有两个功能:


首先返回每个应用程序唯一的UID3


然后产生一个具体的document对象
Document


    Document类一般用来将应用程序的数据保存到文件中,保持程序持久性。但是默认情况下Symbian不使用文件。

class CMyAppDocument : public CAknDocument

    {

    public: // Constructors and destructor

        static CMyAppDocument* NewL( CEikApplication& aApp );

        static CMyAppDocument* NewLC( CEikApplication& aApp );

        virtual ~CMyAppDocument();

    public: // Functions from base classes

        CEikAppUi* CreateAppUiL();

    private: // Constructors

        void ConstructL();

        CMyAppDocument( CEikApplication& aApp );

    };

不使用文件,该类主要有两个功能:


二阶段构造,创建一个Document对象:外部接口为NewL,默认构造函数和二阶段构造函数都为private。
创建一个AppUi
App UI    作为应用程序用户接口,它创建并拥有用于显示用户数据的控件,但是本身不负责显示,主要用来处理菜单命令和按键事件。通过实现以下虚函数,可以处理相应事件:


HandleKeyEventL():按键事件

HandleForgroundEventL():应用程序被切换到前台

HandleSwitchOnEventL():手机开机事件

HandleSystemEventL():系统事件

HandleWsEvent():窗口服务器事件

HandleApplicationSpecificEventL():应用程序相关的事件

HandleCommandL():处理定义在文件中的命令

class CMyAppAppUi : public CAknAppUi

    {

    public: // Constructors and destructor

        void ConstructL();

        CMyAppAppUi();

        virtual ~CMyAppAppUi();

    private:  // Functions from base classes

        void DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane);

        void TKeyResponse HandleKeyEventL(const TKeyEvent& aKeyEvent, TEventCode& a Type); 

        void HandleCommandL( TInt aCommand );

        void HandleStatusPaneSizeChange();

    private: // Data

        CMyAppAppView* iAppView;  

    };

    从定义中可以看到这里并没有二阶段构造(NewL,NewLC) ,因为第一阶段构造和第二阶段构造都是应用程序框架调用的:CMyAppDocument::CreateAppUiL(),CEikAppUi::ConstructL()。

 

CMyAppAppUi::DynInitMenuPaneL() 显示菜单之前由应用程序框架调用,以便动态控制菜单显示的内容。


CMyAppAppUi::HandleKeyEventL() 当有按键事件发生并没有被其他控件处理时,系统调用此函数。

 

CMyAppAppUi::HandleCommandL() 当用户按下菜单命令时调用,如何定义一个菜单命令在下一讲中详述。


    AppUi生成Container:根据S60的惯例,所有控件都成为container,至少有一个container在AppUi的第二阶段构造中生成。其中有以下几个主要函数:

 

SetMopParent() 使得container可以访问AppUi,以便显示滚动条等
AddToStack() 将container添加到App UI的控制堆栈,以便接收按键事件
Container Class    一个container可以包含任意多个控件。


class CMyAppAppView : public CCoeControl

    {

    public: // New methods

        static CMyAppAppView* NewL( const TRect& aRect );

        static CMyAppAppView* NewLC( const TRect& aRect );

        virtual ~CMyAppAppView();

    public:  // Functions from base classes

        void Draw( const TRect& aRect ) const;

        virtual void SizeChanged();

        TInt CountComponentControls() const;

        CCoeControl* ComponentControl(TInt aIndex) const;

    private: // Constructors

        void ConstructL(const TRect& aRect);

        CMyAppAppView();

    private: //data

        CEikLabel* iLabel; 

    };

    主要函数解释:


SizeChanged() 当container被创建或者大小发生变化时调用
CountComponentControls() 返回该container所包含的控件数量
ComponentControl() 返回该container所包含的控件的指针
Draw() 执行一些该container相关的显示操作
    所有container的初始化操作在第二阶段构造函数ConstructL()中完成。


    void CMyAppAppView::ConstructL( const TRect& aRect )

    {

    CreateWindowL();

    iLabel = new (ELeave) CEikLabel;

    iLabel->SetContainerWindowL(*this);

    iLabel->SetTextL( _L("Hello World") );  

    SetRect(aRect);

    ActivateL();

    }

    CreateWindowL() 创建该container的一个窗口,以便这个container和它的控件都能显示出来。

    Lable通过三个步骤创建:首先调用默认构造函数、添加到当前window中、设置要显示的字符串。

    SetRect() 设置container的返回,如果Label超出此范围,会被裁减掉

    ActivateL() 最后container发出已经准备好显示的信号,可以执行Draw操作

读后感初学者可以大体浏览一下,因为这是每个应用程序都具备的

当出现应用程序一开始就死掉或者想对应用程序有更好的控制时,须仔细阅读

当熟练掌握本章内容时,当需要添加一个功能时,可以很快找到需要添加的位置

你可能感兴趣的:(UI,框架,application,Symbian,menu,destructor)