当前位置:首页 >> 信息与通信 >>

symbian 系统开发培训


Inspur Communication Information Systems Co.,Ltd

Symbian OS 开发培训

1

I.

Symbian OS 概述

1998年6月,诺基亚(NOKIA)、摩托罗拉(MOTOROLA)、爱立信(ERICSSON)、 三菱(MITSUBISHI)和Psion在英国伦敦共同投资成立Symbian公司。这个公 司成立的目的是为了能够设计并开发出一种可以在手机及其他类似的移动 通讯终端产品上运行的开放性操作系统,以此来推动高端智能移动电话及 类似的终端产品尽快进入大众消费领域。之后有西门子(SIEMENS)、三星 (SAMSUNG)、松下(Panasonic)、索尼爱立信(Sony Ericsson)等手机厂商相 继入资,现如今,Symbian操作系统的智能手机已经占据了世界智能手机市 场超过80%的份额。

2

I.

Symbian OS 概述 Symbian是一个实时性、多任务的纯32位操作系统,具有功耗低、内 存占用少等特点,非常适合手机等移动设备使用,经过不断完善,可 以支持GPRS、蓝牙、SyncML、以及3G技术。 Symbian是一个标准化的开放式平台,任何人都可以为支持Symbian的 设备开发软件 。 与微软产品不同的是,Symbian将移动设备的通用技术,也就是操作 系统的内核,与图形用户界面技术分开,能很好的适应不同方式输入 的平台,也可以使厂商可以为自己的产品制作更加友好的操作界面, 符合个性化的潮流

3

I.

Symbian OS 概述

目前Symbian OS手机有三种开发SDK: Nokia Series 80: 主要机型有Nokia9200 系列 Nokia Series 60: 主要机型包括诺基亚7650、 6600、西门子SX1 等 UIQ2、UIQ3: Sony Ericsson P800,P900

Sony Ericsson P900

4

II. 开发平台搭建

安装ActivePerl(x86和x64分别对应32位和64位cpu ) jre (java的应用平台) Symbian OS SDK (建议安装在 盘符根目录下 ) (C++)开发工具

5

II. 开发平台搭建

手机软件开发过程:
第一步:安装开发软件,搭建开发环境(下面主要介绍 series 60 sdk, 其余类似) 第二步:在模拟器上开发调试(以VC环境开发为例) 第三步:生成sis文件,在手机上安装运行

6

II. 开发平台搭建

几种开发环境:
Visual C++ 6.0 Borland C++ Builder 6 Carbide C++

7

II. 开发平台搭建
工程基本目录结构:
Symbian工程

1.aif用来存放程序图标 2.data用来存放运行所需要的资源 文件 .rss。 3.group中比较重要的几个文件: bld.inf、*.mmp。 4.inc 和src 存放工程头文件和源代 码文件。 5.sis 用来存放 程序打包所需要的 pkg文件,打包后生成的安装文件 .sis也存放在此处。

aif data group inc src sis

8

II. 开发平台搭建
1. bld.inf声明build的相关信息 通常只包括这次build会引用到 的mmp文件。 例如:
PRJ_MMPFILES hello.mmp

2..mmp文件保存工程 编译相关信息,主要内容如下
TARGET hello.app //目标名称 TARGETTYPE app //目标类型 UID 0x100039CE 0x07B9DE87 //UID 唯一系统标示符 TARGETPATH \system\apps\hello //目标路径 SOURCEPATH ..\src //源代码存放位置

SOURCE helloApp.cpp //源代码列表 …

9

SOURCEPATH ..\data //资源文件路径 RESOURCE hello.rss //资源文件 LANG SC //默认英语 USERINCLUDE . USERINCLUDE ..\inc //头文件路径 //系统包含文件目录

SYSTEMINCLUDE . \epoc32\include

LIBRARY euser.lib apparc.lib cone.lib eikcore.lib LIBRARY eikcoctl.lib avkon.lib //库文件

3. UID
UID1-第一个UID(类型): UID1用来设定该应用程序是一个执行程序(executable file)还是一个数据文件 (data file). UID value KExecutableImageUid KDaynamicLibraryUid KDirectFileStoreLayoutUid Numeric value (Hex) 0x1000007A 0x10000079 0x10000037 Meaning .exe 可执行文件 .dll .app .ldd, .pdd 文件 direct file store permanent file store

KPermanentFileStoreLayoutUid 0x10000050

10 UID2-第二个UID(子类型): UID2-具体含义取决于UID1的值: 如果UID1是KExecutableImageUid, UID2不使用,所以UID2的值可以随意取。 如果UID1是KDynamicLibraryUid, UID2将会是: UID value KSharedLibraryUid KUidApp KLogicalDeviceDriverUid KPhysicalDeviceDriverUid Numeric value (Hex) 0x1000008D 0x100039CE 0x100000AF 0x100039D0 .dll .app a logical decive driver (.ldd) a physical device driver(.pdd) Meaning

如果UID1是KDirectFileStoreLayoutUid或者KPermanentFileStoreLayoutUid,那 么UID2将是: UID value KUidAppDllDoc KUidAppInfoFile Numeric value (Hex) 0x10003A12 0x10003A38 Meaning indicates this is a file store created by an .app to store user data (i.e, a document) Indicates this is an AIF file (a type of file store)

11

UID3-第三个 第三个UID(子子类型 : 子子类型): 第三个 子子类型 每个独立的应用程序有一个唯一的UID3值,它也被用作安全ID(secure ID),对于 UIKON应用程序而言,用于关联数据文件和程序: 1. 对于dll和exe文件,它辩识特定的二进制(it identified the particular binary)。 2. 对于.app(UIKON应用程序),它辩识特定的应用程序(it identified the particular application program). 3. 对于由.apps创建的文件存储(file stores),它辩识和该文件相关的应用程序(it identifies the application program associated with this file). 4. 对于其他文件存储(file stores), 它没有典型的用途(但是你可以自定义它的用途)

12

Symbian 编程规范和基本框架
Symbian 命名约定
Symbian大致分了四种类 C:C前缀表示类从CBase派生并应该基于堆构造。 T:T前缀表示一个简单类,这种类不拥有任何额外的资源。 如Tint、 TReal等基本数据类型。 R:R前缀表示一个资源类,它包含其它位置拥有资源的句柄。 M:M前缀表示一个接口类,它定义了接口但需要派生类实现。 结构(struct)类型作为T类对待,因为它也不拥有任何额外的资源,它的前缀通常是T(但也有一些 以S开头)。 enum TColors { ERed, //尽量用E开头 ,尽量用枚举 EGreen } 成员变量的名字以i开头 ,参数名以a开头 class TMyClass { TInt iMyValue; void MyAddFunc(TInt aArg1,TInt aArg2); void MyAddFunc(TInt aArg1,TInt aArg2); void MyAddFuncL(TInt aArg1,TInt aArg2);-------->后缀L的约定是该 函数可 能产生异常退出; void MyAddFuncLC(TInt aArg1,TInt aArg2); ---------->后缀LC的约定表示 成功完成之后, 返回值会被压入清理栈中; (栈不保存) };

13

Symbian 编程规范和基本框架
Symbian 命名约定
常量应加前缀K const CInt KMyconstant; 宏全部为大写 #define MY_HARDCODED_VALUE (25)

Symbian四个主要的应用软件框架类
针对右图Graphics ,UI程序应该具备 的基本功能类:视图(View)、文档(Document)、 应用程序(Application)、 应用程序UI(Application UI)。 所有的S60 UI应用程序都具有一些基本功能: 提供一个用户界面,用于显示信息并允许用户进行交互。 响应各种用户启动的事件,比如用户选择一个菜单项。 响应系统启动的不同事件,比如导致屏幕重绘的window服务器事件。 能够保存和恢复应用程序数据。 可以唯一性的向框架标志自身。 向框架提供有关应用程序的描述性信息,比如图标和标题等。

14

Symbian 编程规范和基本框架
Symbian四个主要的应用软件框架类
一个程序只能有一个文档,可以有多个视图。 必须创建下面的每个方法,才能提供最小的S60应用程序: 所有S60 UI都实现一个全局函数E32DLL(),当应用程序启动时,框架将首先 调用该函数,该函数也称为DLL入口点 入口点,应用程序必须存在该函数。 框架调 入口点 用NewApplication(),创建Application类,其基类是CAknApplication. 类 Application类创建应用程序类的Document对象 ,并返回它的指针,以 类 后框架使用该指针完成应用程序的创建。 由框架调用AppDllUid()返回应用 程序的UID。该函数必须返回在.mmp文件中指定的值。 Document基类是

CAknDocument. Document对象通过CreateAppUiL创建获取AppUi类的指针。 对象 AppUi类的基类是CAknAppUi 或者 CAknViewAppUi ,它是用来处 理应用程序事件,如操作菜单, 操作视图,切换视图等等。 View 是控制类(c类),在屏幕 上显示数据,用户与界面交互, 传递命令给AppUi。

15

Symbian 编程规范和基本框架
Symbian处理内存泄漏的手段 1.Trap和TrapD 处理异常
TInt err; Trap(err,CreateObject()); //需要先定义err变量 TrapD(err,CreateObject()); //不需要定义err变量

2.CleanupStack
它是处理内存泄漏的又一重要手段
CFoo *p = new (ELeave) CFoo(); CleanupStack::PushL(p) p->SomeFunctionL(); //可能异常退出,使得delete p 得不到调用 CleanupStack::Pop(); delete p;

Symbian二阶段构造
在Symbian中,如果在一个类的构造函数中需要执行某些比如申请内存等操作,那 么有可能会Leave。如果Leave的话,这个时候这个类的析构 函数是不会被调 用,因为还没有初始化完,也就没法把自己加入CleanupStack,那么那些申 请了的内存可能会因为没有变量引用而造成内存泄漏。因此 在Symbian中类 的构造函数中不能有可能会Leave的代码。

16

Symbian 编程规范和基本框架
Symbian二阶段构造 二阶段构造
初始化一个类确实需要执行某些可能会Leave的函数,这就是Symbian中要求 的两阶段初始化了。第一阶段,也就是在构造函数中执行一些不会 Leave的初始化工 作。然后是第二阶段,把这个实例推进CleanupStack,再执行第二阶段的可能会 Leave的代码。当然,在析构函数中,要能 够处理部分初始化的情况,也就是实例没 有初始化成功,也能释放那些已经申请的内存或资源。
CGraphicsAppView::CGraphicsAppView() { } CGraphicsAppView* CGraphicsAppView::NewL( const TRect& aRect ) { CGraphicsAppView* self = NewLC( aRect ); CleanupStack::Pop( self ); return self; } CGraphicsAppView* CGraphicsAppView::NewLC( const TRect& aRect ) { CGraphicsAppView* self = new ( ELeave ) CGraphicsAppView; CleanupStack::PushL( self ); self->ConstructL( aRect ); return self; } void CGraphicsAppView::ConstructL( const TRect& aRect ) { CreateWindowL(); SetRect( aRect ); }

17

Symbian基本语法 Symbian基本语法
描述符
描述符是用来存储文本和二进制的基本类 抽象类(Abstract): ( TDes、TDesC、TDes8、TDesC8),描述符的基类,仅 提供接口和基本功能,不能被实例化,一般只用作函数的参数。 文字常量( Literal):(TlitC、_LIT()),用于存储文字字符串(literal string),即C 中字符串常量,通常使用_LIT()这种方式,也有_L(),_L8()这种方式。 栈类( Buffer):(TBuf、TBufC、 TBuf8、TBufC8),数据存储于栈上,最基本 的描述符变量类型,大小在编译时确定 大小在编译时确定,包含描述符本身数据,使用最为普 大小在编译时确定 遍,具体方法如下 堆类( Heap):(HBufC、HBufC8),数据存储于堆上,大小在运行时确定 , 也就是用来处理动态申请的描述符类。在C/C++中用过动态内存的都知道, 动态内存是啥回事,这里堆类描述符用的时候,也是差不多,由于堆描述符 没有构造函数,所以只能声明为指针类型,通过堆描述符类内静态函数NewL 方法申请内存,具体方法如下 HBufC* errorTitleCode = HBufC::NewLC(50); HbufC* unUseCode = NULL; 指针类(Pointer):(TPtr、TPtrC、TPtr8、TPtrC8),本身不包含描述符数据, 但是包含长度数据,而且还包含一个指向位于描述符之外数据的指针。

18

Symbian基本语法 Symbian基本语法
描述符关系简图

19

Symbian基本语法 Symbian基本语法
描述符的使用
文字描述符常量
_LIT(KMyFile, “c:\System\Apps\MyApp\MyFile.jpg”);它可以在任何使用TDesC&

的地方使用 。
//常用的通知函数 NEikonEnvironment::MessageBox(_L("Error: init file not found!")); //数字转字符串 TBuf16<20> buf;// TInt iNum = 20; buf.Format( _L( "%d" ) , iNum );

栈描述符
栈类描述符声明时必须指定描述符的最大长度,否则无法声明和定义 ,举例如下: // 直接从字符串中构造
_LIT(Ktext, "TestText"); TBufC<10> Buf (Ktext); // 或从字符串赋值 TBufC<10> Buf2; Buf2 = Ktext; // 从已有的对象中生成新的TBufC TBufC<10> Buf3(Buf2);

20

Symbian基本语法 Symbian基本语法
描述符的使用
栈描述符
尽管这里的对象表示数据是不能被修改的(因为有个后缀C代表了常量的意思),但仍然有 两种方式可以用来修改数据内容:这里的数据可以用赋值的方式替换掉;使用Des()函数 构造出一个TPtr对象,这样就可以用它来修改数据。 _LIT(Ktext , "Test Text"); _LIT(Ktext1 , "Test Text”); _LIT(KXtraText , "New:"); TBufC<10> Buf1 ( Ktext ); //Buf1长度为9 内容 “Test Text” TBufC<10> Buf2 ( Ktext1 ); //Buf2长度为10 内容 “Test1 Text” // 通过赋值的方式改变数据 Buf2 = Buf1; //Buf2长度变为9 内容 “Test Text” //通过使用Des()生成指针改变TBufC的数据 TPtr Pointer = Buf1.Des(); // 删除后四个字符 Pointer.Delete(Pointer.Length()-4, 4 ); //Buf1长度变为5 内容“Test ” // 增加新的数据 Pointer.Append(KXtraText); //Buf1长度为9 内容为“Test New:” // 也可以使用下列方式改变数据 TBufC<10> Buf3(NewText); Pointer.Copy(Buf3);//Buf1长度为4,内容为New1 // 或直接从字符串里获得数据 Pointer.Copy(NewText1);//Buf1长度为4,内容为New2

21

Symbian基本语法 Symbian基本语法
描述符的使用
栈描述符
可修改的描述符TBuf, TBuf8就不用通过那么复杂的方法来实现修改,它直接可以用Copy 、Delete等方法,但是无论可修改的还是不可修改的,一旦指定最大的数据长度后,最 大长度就不能进行修改了修改的只是数据内容,而数据内容修改的受限条件是不能超过 声明或定义时的最大长度。

堆描述符
堆描述符HBufC,HbufC8虽然都是不可修改类型的,但是它仍然具有构造和修改,与栈描述符 不同的是:首先对内存需要显示释放,其次是堆描述符没有最大长度的限制,任何时候 都可以用ReAlloc()函数重新申请分配。有两种方式来生成一个堆描述符示例: //第一种方式用New(),NewL(),或NewLC() HBufC * Buf = HBufC::NewL(15); //第二种方式是采用Alloc(),AllocL()或AllcLC()来处理 _LIT (KText , "Test Text"); TBufC<10> CBuf = KText; HBufC * Buf1 = CBuf.AllocL(); CleanupStack::PushL(Buf1); 堆描述符的修改方式: //1.赋值方式改变其数据的方法 _LIT ( KText1 , "Text1"); *Buf1 = KText1;

22

Symbian基本语法 Symbian基本语法
描述符的使用
堆描述符
堆描述符的修改方式: // 2.通过可修改指针来改变数据的方式 TPtr Pointer = Buf1->Des(); Pointer.Delete(Pointer.Length() - 2, 2); //删除数据 _LIT ( KNew, "New:"); Pointer.Append(KNew); //添加数据 重新申请内存 Buf1 = Buf1->ReAllocL(KText().Length() + KNew().Length()); CleanupStack::PushL(Buf1); 释放内存 delete Buf; Buf = NULL;

指针描述符
不可修改的指针TPtrC 可用TBuf和TBufC构造出TPtrC对象 _LIT(KText , "Test Code"); TBufC<10> Buf ( KText ); //或者为 TBuf<10> Buf ( KText ); TPtrC Ptr (Buf); //使用构造函数初始化 TPtrC Ptr1; Ptr1.Set(Buf); //利用set函数初始化

23

Symbian基本语法 Symbian基本语法
描述符的使用
指针描述符
不可修改的指针TPtrC 用TText*构造TPtrC const TText* text = _S("Hello World\n"); TPtrC ptr(text); // 或者 TPtrC Ptr2; Ptr2.Set(text); //如果要存储TText的一部分数据,我们使用下列方法 TPtrC ptr4(text, 5);

从另一个TPtrC中构造TPtrC
const TText * text1 = _S("Hello World\n"); TPtrC Ptr3(text1); // 从一个TPtrC中获得另一个TPtrC TPtrC p1(Ptr3); // 或 TPtrC p2; p2.Set(Ptr3); 可修改的TPtr 同不可修改的指针描述符构造方法基本类似,区别在于,不可修改的指针描述符 TPtrC的函数始终是不可修改的,因此没有Insert,Delete等函数,并且没有Des()函数, 但有Alloc(),Compare(),Find(),Mid(),Size()等函数。

24

Symbian基本语法 Symbian基本语法
动态数组
在传统c/c++中经常会使用数组来存储序列,它是具有相同数据类型的数据元素的集合,通过数 组可以很方便的实现数据元素的访问等相关操作。动态数组是一个类的模板,可以接受各种各样 的数据类型,Symbian OS主要提供了3类动态数组: RArray<class T> , RPointerArray<class T>, CArray<class T>

活动对象
在symbian os 中活动对象是一种非抢先式多任务处理的机制,是symbian os 中一 个十分重要的概念。可用于替代Symbian OS中的多线程 。使用活动对象可获得的好处是:在同 一个线程中运行的活动对象之间进行切换的代价要比线程上下文的切换代价低,这使得对于各种 资源比较紧张的Symbian OS来说,使得活动对象更适合事件驱动多任务。 概念:一个活动对象必须派生自基类CActive class CActive : public CBase { public: enum Tpriority { EPriorityIdle = -100; EPriorityLow = -20; EPriorityStandard = 0; EPriorityUserInput = 10; EPriorityHigh = 20; }

25

Symbian基本语法 Symbian基本语法
活动对象
public: IMPORT_C ~CActive (); IMPORT_C void Cancel ();//删除未完成请求的函数 …… IMPORT_C void SetPriority (TInt aPriority); Inline TBool IsActive () const; …… protected: IMPORT_C CActive (TInt aPriority); IMPORT_C void SetActive (); virtual void DoCancel () = 0;//两个纯虚函数,继承类必须实现它们 virtual void RunL () = 0;//处理函数 IMPORT_C virtual TInt RunError (TInt aError); public: TrequestStatus iStatus;//代表请求状态 ……. private: TBool iActive; ……. } 构造时也会有一个优先级值来决定它们如何被调度 Cancel 和DoCancel用来取消发出的请求,Docancel是一个纯虚函数,需要由派生类实 现。Cancel的功能就是调用DoCancel,如果用户取消当前请求调用Cancel而不是 DoCancel,但在代码中要实现Docancel

26

Symbian基本语法 Symbian基本语法
活动对象
IsActive确定活动对象是否处于活动状态 SetActive 激活活动对象,一般在调用请求后紧接着调用它。 RunL 异步事件处理函数,当一个请求完成时,活动对象调度器会调用这个函数,进行下 一步处理 RunError 当RunL函数出现异常时会出现RunError函数,它也是纯虚函数,需要派生类 实现。 具体例子见文档。

文件管理
symbian系统采用了C/S(客户端/服务器)的架构。对于文件操作,系统有一个文件系统管理的服 务器。程序通过联结这个文件管理服务器来进行文件 。 在symbian os 中,Flash(闪存)通常被定义在c盘,symbian智能手机中还有一个ROM存储器 通常被映射在z盘,用户的许多文件也存放在z盘。其他可移动存储(如存储卡)则映射在d,e等 盘符。 symbian开发环境下各盘符对应的映射关系: 客户机c:盘 对应开发平台中sdk的 \epoc32\wins\c目录 客户机d:盘 对应开发平台中sdk的\epoc32\wins\d目录 客户机z:盘 对应开发平台中sdk的\epoc32\release\wins\urel\z目录或者 \epoc32\release\wins\urel\z 文件命名规则 一个完整的symbian os 文件应该包含以下四个部分 1.驱动器名,即盘符 2. 路径,从根目录到或当前会话目录起到文件经过的所有目录路径 3.文件名,遵循c/c++命名规范 4.文件扩展名 例如:c:\myfile\data.txt就是合法的文件名,一个完整的文件名不能超过255个字符。

27

Symbian基本应用 Symbian基本应用
文件管理
文件访问流程 1.应用程序要进行文件读写之前,必须建立应用程序与文件服务器的连接,这种连接也称会话( session),Sysmbian os中提供RFs类来实现这个功能,该类提供了Connect()和Close()函 数来建立和关闭连接。 RFs fsSession; //建立RFs类的对象 User::LeaveIfError(fsSession.Connect()); //建立连接,为防止出现异常放 User::LeaveIfError中 fsSession.Close(); //用完关闭连接 2.文件服务器可以实现文件的读、写、删、建, 通过 RFile的Open(RFs aFs, const TDesC& aName, TUnit aFileMode) 打开文件 。 通过Write( )和Read( )可以实现文件的写和读。 RFile的Create( )用于建立新文件。 删除文件可以使用RFs的Delete( )。 3.另一种比较重要的文件读写方式 ----流(Stream) 文件输出流 RWriteStream 和文件输入流RReadStream 文件输出六主要使用RWriteStream 的派生类RFileWriteStream 将数据外化为流,它需要先打开 一个文件,打开文件的两种方式: OpenL : 当文件不存在会产生异常,所以必须保证文件存在 Replace: 文件存在删除并重建新的,不存在就创建,因每次都创建文件,会带来额外开销。 例子: RFileWriteStream writer;
writer.PushL(); // writer on cleanup stack User::LeaveIfError(writer.Replace(iCoeEnv->FsSession(), *iFileName, EFileWrite)); writer << *iText; // write the text writer.CommitL(); CleanupStack::PopAndDestroy(); // 释放资源

从存储中读取数据的方法就是将以上的过程反向

28

Symbian基本应用 Symbian基本应用
数据库管理
Symbian系统的DBMS提供了创建与维持数据库的功能,通过本地调用和SQL调用,其可以对数 据库进行安全可靠的数据访问。这种调用支持事务/回滚机制用以保证所有数据被写入或数据为空的情 形获得支持。 DBMS的管理结构和元素 的管理结构和元素 任何Symbian系统的DBMS都采用层次性的结构—最底层是保存数据库的文件仓库。 Symbian操作系统的DBMS是一个功能强大,或为轻量集的数据库关系系统实现。它支持普通的 添加/查找/检索/更新/删除功能,同时它还支持基本的 结构化查询语言(Structured Query Language:SQL),数据定义语言(Data Definition Language:DDL)和数据建模语言(Data Modeling Language:DML)语句处理。 永久文件存储系统和流 Symbian 系统的DBMS依赖于文件服务器提供的资源,Symbian系统所的永久文件存储和流能提 供系统所需要的底层存储功能 。永久文件系统通过使用CPermanentFileStore 来获得,它是一个源自 CFileStore的具体类。这些类在文件存储API中定义,可为DBMS提供组建模块。 创建数据库 (1)RDbStoreDatabase:通过文件存储打开的数据库,提供了进行数据库操作的API,独占使用数 据库,不可共享使用。 (2)RDbNamedDatabase:通过文件名打开的数据库,同样提供API。使用C/S模式,可以共享使用 (3)CDbColSet:数据库字段的集合,可用于在数据库中创建表格。 (4)使用到的库和头文件:ws32.lib edbms.lib d32dbms.h f32file.h s32file.h 创建步骤: (1)数据库类的声明:将RFs和RDbStoreDatabase声明为数据成员。 class CMiapSampleDatabase : public CBase {

29

Symbian基本应用 Symbian基本应用
数据库管理
public: //Some Functions private: RFs iFsSession; RDbStoreDatabase iDb; }; (2)创建数据库: 首先打开一个文件流存储(FileStore),通过调用 RDbStoreDatabase::CreateL(CStreamStore* aStore)来创建数据库。最后将文件流提交。 _LIT( KFileName, "C:\\DataBase.db" ); CFileStore* FileStore = CPermanentFileStore::ReplaceL(iFsSession, KFileName, EFileRead|EFileWrite); CleanupStack::PushL(FileStore); FileStore->SetTypeL(FileStore->Layout()); TStreamId id = iDb.CreateL(FileStore); FileStore->SetRootL(id); FileStore->CommitL(); CleanupStack::PopAndDestroy( FileStore ); iOpen = ETrue; iDb.Close();

30

Symbian基本应用 Symbian基本应用
数据库管理
(3)创建表格: 通过文件流存储打开数据库: _LIT( KFileName, "C:\\DataBase.db" ); CFileStore* FileStore = CPermanentFileStore::OpenLC( iFsSession, KFileName, EFileRead|EFileWrite); FileStore->SetTypeL(FileStore->Layout()); iDb.OpenL( FileStore, FileStore->Root() ); 添加字段: _LIT(KId, "Id"); _LIT(KText, "Text"); _LIT(KTableName, "Table"); TDbCol IdCol( KId, EDbColText ); TDbCol TextCol( KText, EDbColText ); CDbColSet* ColSet = CDbColSet::NewLC(); ColSet->AddL(IdCol); ColSet->AddL(TextCol); 创建表格: User::LeaveIfError( iDb.CreateTable( KTableName, *ColSet ) ); 释放不使用的内存: CleanupStack::PopAndDestroy(ColSet); CleanupStack::PopAndDestroy( FileStore );

31

Symbian基本应用 Symbian基本应用
数据库管理
(4)创建索引: TDbKeyCol IdKey( KId ); CDbKey* key=CDbKey::NewLC(); key->AddL( IdKey ); User::LeaveIfError( iDb.CreateIndex( KTableName, KTableName, *key)); CleanupStack::PopAndDestroy(key); 首 先创建一个索引对象,将其添加到索引集合中,通过调用 RDbStoreDatabase::CreateIndex(const TDesC& aName,const TDesC& aTable,const CDbKey& aKey)创建表格,最后清除不使用的内存。 (5)插入记录: _LIT(KIdText, "100001"); 首先打开数据库。打开表: RDbTable table; CleanupClosePushL(table); User::LeaveIfError( table.Open(iDb, aTableName, table.EUpdatable ) ); 获取字段集合: CDbColSet* ColSet = table.ColSetL(); CleanupStack::PushL(ColSet); 添加记录: table.Reset(); table.InsertL(); table.SetColL( ColSet->ColNo(KId), KIdText ); table.PutL(); CleanupStack::PopAndDestroy(2); //清除内存: 注意:每插入一条记录,就必须调用table.InsertL(),设置完值后,必须调用table.PutL()提交。

32

Symbian基本应用 Symbian基本应用
(6)查询记录: 首先打开数据库和表。 TPtrC ptrc; for( table.FirstL(); table.AtRow(); table.NextL()) { table.GetL(); ptrc.Set( table.ColDes( colSet->ColNo( KId ) ) ); } table.FirstL()将焦点设置为第一条记录,table.AtRow()验证下一条记录是否存在, table.NextL()将焦点移动到下一条记录。 每查询一条记录,必须调用table.GetL(); 使用TPtrC::Set()将查询结果写进描述符。 (7)执行SQL语句: 首先打开数据库。 TBuf<256> SQL; SQL.Append( _L("//Some SQL") ); RDbUpdate DbUpdate; TInt incStat = DbUpdate.Execute(iDb, SQL, EDbCompareNormal); incStat = DbUpdate.Next(); while( incStat == 1 ) { incStat = DbUpdate.Next(); } DbUpdate.Close();

33

GUI编程 Symbian GUI编程
60系列用户界面显示器规范如下: 系列用户界面显示器规范如下: 系列用户界面显示器规范如下 分辨率: 像素(宽 × 像素( 分辨率:176像素 宽)×208像素(高) 像素 像素 正方形像素 物理尺寸: 物理尺寸:约35mm(宽),41mm(高), 宽, 高, 对应约0.2mm的象素点距。 的象素点距。 对应约 的象素点距 颜色数( 色或更多) 颜色数(4096色或更多) 色或更多

34

GUI编程 Symbian GUI编程

35

GUI编程 Symbian GUI编程
显示器按照一定的层次结构进行布局。布局由被称为窗口( 显示器按照一定的层次结构进行布局。布局由被称为窗口(windows)和窗格 ) (panes)的组件构建。 )的组件构建。 屏幕( 屏幕(Screen)是最顶层的显示组件,对应于物理屏幕的整个象素区域。 )是最顶层的显示组件,对应于物理屏幕的整个象素区域。 窗口( 窗口(Window) )
屏幕(screen)是窗口的唯一父组件。一般情况下一个窗口会充满整个屏幕,但有时也存 在一些小窗口(临时性的),它们只占据屏幕的一部分,环绕其周围的部分是可见的。 每个应用程序都在自己的窗口中运行。应用程序也可以调用其它的临时窗口。

窗格( ) 窗格(Pane)
窗格是窗口(window)的子组件。 一个窗口可以包含多个窗格,而每个窗格又可以包含多个子窗格,如此等等。不含有子组 件的底层组件被称为元素(element)。

应用窗口
应用窗口是覆盖整个屏幕的主窗口。通常它并不直接用于显示,而是作为各种窗格的父组 件。 。

一个典型的应用窗口由下几种窗格组成: 一个典型的应用窗口由下几种窗格组成:
- 状态窗格 - 主窗格 - 控制窗格

36

GUI编程 Symbian GUI编程

37

GUI应用程序的基本组成部分 GUI应用程序的基本组成部分

Application 负责启动方面的工作

Model 可选:负责处理数据

Document 负责永久保持的工作

AppUI 负责接受并处理用户的命令

AppView 负责图形显示的工作

38

view架构 view架构
view是一个执行特定任务的一屏 是一个执行特定任务的一屏 同一时刻, 管理系统只允许一个view处于激活状态 同一时刻,view管理系统只允许一个 管理系统只允许一个 处于激活状态 每个view都有一个 都有一个ID 每个 都有一个 每个view必须到 必须到view server上去登记 每个 必须到 上去登记 调用ActiveViewL()还能够激活其它应用程序的 还能够激活其它应用程序的views 调用 还能够激活其它应用程序的 在view之间能够传递消息 之间能够传递消息 class CMyView : public CAknView

39

CCoeControl框架 CCoeControl框架
主要内容 简单控件
CCoeControl概述 控件的初始化 控件的重绘 用户输入处理(按键事件)

复合控件 常用控件 对话框 表格 资源
菜单 软键 热键

40

CCoeControl框架 CCoeControl框架

WINDOWS server

41

CCoeControl框架 CCoeControl框架
WINDOWS server

42

CoeControl
可以作为视图的基类
传统的EIKON视图架构-container dialog

负责应用程序视图区域的显示工作
一个应用程序的界面分为三部分 标题栏 软键区域 应用程序视图区域(右图的黑框部分) 使用CGraphicsContext进行画图 在UI平台能力范围内工作(如:60系列)

系统提供的常用控件有
按钮 编辑器 文本标签 列表框

可以内嵌其它控件(又称定制控件,或者复合控件)

43

CoeControl

所有对屏幕的操作都是在控件上进行
控件从CCoeControl继承而来 控件是屏幕上的一个矩形区域 控件占据窗口的全部或者部分

应用程序的视图使用至少一个控件 控件可以处理用户的输入事件
键盘事件 鼠标事件

44

CoeControl

是所有控件的基类 被派生类直接调用的函数
SetRect() CreateWindowL()

被派生类重载的函数
OfferKeyEventL() Draw()

所拥有的函数可以分为以下三类
初始化 Drawing 用户输入处理

45

初始化

class CAbcContainer : public CCoeControl { public: // Constructors and destructor void ConstructL(const TRect& aRect); ~CAbcContainer(); private: // Functions from base classes void SizeChanged(); void Draw(const TRect& aRect) const; }; void CAbcContainer::ConstructL(const TRect& aRect) { CreateWindowL(); SetRect(aRect); ActivateL(); }

46

初始化

class CAbcContainer : public CCoeControl { public: // Constructors and destructor void ConstructL(const TRect& aRect); ~CAbcContainer(); private: // Functions from base classes void SizeChanged(); void Draw(const TRect& aRect) const; }; void CAbcContainer::ConstructL(const TRect& aRect) { CreateWindowL(); SetRect(aRect); ActivateL(); }

47

Drawing

virtual void Draw(const TRect& aRect) const; 负责产生控件的图形化外观 重要提示
基类中的该函数为空,在派生类中如果不实现该函数的话控件将不可见 该方法由应用程序框架调用,不要自己调用该函数 方法是const,意味着你在Draw()中不能更改任何成员变量,或者调用任 何不是const的函数。 该函数不允许leave,因此你必须用TRAP封装可能leave的函数

48

Draw()

void CAbcContainer::Draw(const TRect& aRect) const { CWindowGc& gc = SystemGc(); gc.SetPenStyle( CGraphicsContext::ENullPen ); gc.SetBrushColor( KRgbDarkBlue ); gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); gc.DrawRect( aRect ); //gc.Clear() }

49

图形设备接口GDI 图形设备接口GDI
抽象类CGraphicsContext(图形上下文)定义了一致的接口 派生类CWindowGc和CFbsBitGc具体实现了这些接口 可以直接使用CFbsBitGc绘图,但不推荐:

Application

Screen

CFbsBitGc

DrawArc()

50

推荐的绘图方式

建议在程序中使用CWindowGc提供的接口

51

图形上下文

CWindowGc& SystemGc() const用来获取当前的图形上 下文 提供了许多有用的绘图函数
画点、线、椭圆、矩形、位图等等 改变画笔/画刷的颜色和风格 改变字体 设置裁剪区域,原点

在某一时刻CWindowGc只能由一个窗口激活
void Activate(RDrawableWindow& aWindow) void Deactivate()

52

控件的重绘(redraw) 控件的重绘(redraw)

更新在屏幕上的显示 两种类型
系统发起的 window server 我们“必须”重绘控件 应用程序发起的 内部状态改变 我们“想要”重绘控件

53

系统发起的重绘

1. 当window server检测到可能使一个区域无效的事件
对话框/菜单不再需要时 启动一个GUI程序时

2. 发送redraw消息给拥有窗口的应用程序 3. 应用程序通过CONE发送消息给相关的控件 4. 调用控件的Draw()函数

54

应用发起的重绘

通常是某个内部状态改变的结果 实现方法有以下几种:
Invalidate控件窗口的某部分,让window server发送一个 redraw消息 请求CONE立即重绘整个控件 立即重绘控件的某个部分

所有的实现方法最终都是调用Draw()函数

55

redraw的类型 redraw的类型
立即重绘整个控件 CCoeControl::DrawNow() 在程序初始化时采用 一旦有机会就重绘 整个窗口: void CCoeControl::DrawDeferred() const 部分窗口: void RWindow::Invalidate(const TRect&) 立即重绘已知无效的部分 void CSemView::DrawSunNow() const { Window().Invalidate(iSunArea); ActivateGc(); Window().BeginRedraw(iSunArea); DrawSun(); Window().EndRedraw(); DeactivateGc(); }

56

更多Draw()的信息 更多Draw()的信息 Draw()

参数aRect
指定重绘的区域 相对于控件的原点(左上角)

对于简单控件,通常重绘整个控件 对于复合控件,只重绘部分控件 防止屏幕闪烁
只重绘位于无效区域的部分 不要短时间内多次重绘某个区域 尽量避免大面积的重绘

57

处理按键事件

控件能够检测并处理按键事件 按键事件的处理是独立于资源文件定义的热键处理之外 的 UI框架已经实现了大部分的按键处理 典型应用
导航键 选择键

58

CONE控件堆栈 CONE控件堆栈

按键事件由系统通告给对其感兴趣的控件
在一个特殊的数据结构(CONE控件堆栈)中登记感兴趣的控件 系统给控件发送OfferKeyEventL事件

CONE控件堆栈中的控件被一一通告事件的发生,直至某 个控件宣称接收了该事件
控件按优先级被通告事件的发生 控件必须告知系统是否接收了该事件

如果没有任何控件宣称接收一个事件,则最后将由AppUi 在它的CMyAppUi::HandleKeyEventL()中处理该事件

59

AppUi对按键事件的处理 AppUi对按键事件的处理
在CONE控件堆栈中登记控件 void CtestAppUi::ConstructL() { BaseConstructL(); iAppContainer = new (ELeave) CtestContainer; iAppContainer->SetMopParent( this ); iAppContainer->ConstructL( ClientRect() ); AddToStackL( iAppContainer ); iAppContainer2 = new (ELeave) CtestContainer2; iAppContainer2->SetMopParent( this ); iAppContainer2->ConstructL( ClientRect() ); AddToStackL( iAppContainer2 ); } 在析构的时候将控件从CONE控件堆栈中注销 CtestAppUi::~CtestAppUi() { if (iAppContainer) { RemoveFromStack( iAppContainer );

60

CCoeControl对按键事件的处理 CCoeControl对按键事件的处理
TKeyResponse OfferKeyEventL(const TKeyEvent& aEvent, TEventCode aType) TKeyResponse CMyGameView::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) { switch(aType) { case EEventKey: if(aKeyEvent.iScanCode == EStdKeyNkp5 || aKeyEvent.iScanCode == EStdKeyDevice3) { iMyGameEngine->Fire(); return EKeyWasConsumed; } break; case EEventKeyDown: case EEventKeyUp: } return EKeyWasNotConsumed; } … …

61

点击事件的处理

60系列并不支持笔写输入 但模拟器支持笔的点击
void HandlePointerEventL(const TPointerEvent&)

62

复合控件

compound control 包含其它控件的控件 有时也称container,容器 为什么要用复合控件
共享主控件的现有窗口 重用控件 系统控件(CEikLabel) 自己的控件(CMyInfoControl) 可以选择性地重绘子控件

63

容器(主控件) 容器(主控件)的责任

创建窗口
只为主控件创建窗口 子控件重用该窗口

创建和删除子控件
在主控件中定义成员变量 在析构函数中删除子控件

摆放子控件
设置自己的大小 摆放子控件

64

CCoeControl & Windows

创建一个新窗口
CreateWindowL() 为主控件所拥有 为子控件所共享

重用现有的窗口
SetContainerWindowL(const CCoeControl &aContainer) 子控件调用该函数 减少与window server的c/s交互}

65

创建子控件
在容器的第二阶段构造函数中创建子控件,并让它们重用容器的窗口 void CtestContainer::ConstructL(const TRect& aRect) { CreateWindowL();//创建主窗口 iLabel = new (ELeave) CEikLabel; iLabel->SetContainerWindowL( *this ); iLabel->SetTextL( _L("Example View") ); iToDoLabel = new (ELeave) CEikLabel; iToDoLabel->SetContainerWindowL( *this ); iToDoLabel->SetTextL( _L("Add Your controls\n here") ); SetRect(aRect); ActivateL(); }

66

通告给CONE相应的信息 通告给CONE相应的信息 CONE

告诉CONE拥有的子控件的数目
TInt CtestContainer::CountComponentControls() const 缺省的实现返回0

返回子控件的指针
CCoeControl* CtestContainer::ComponentControl(TInt aIndex) const 用来依次对所有的子控件执行操作 第一个控件的index为0,顺序通常不是很重要

如果忘记重载上述两个函数,则子控件依然存在, 但无法显示,因为CONE不知道我们的容器有几个子 控件

67

复合控件的绘图
重绘容器时也重绘了子控件 首先调用容器的Draw() 然后调用子控件的Draw() CONE利用CountComponentControls() 和ComponentControl(TInt aIndex) 依次调 用自控件的Draw() 防止闪烁 如果子控件覆盖了整个容器的区域,则无须为容器提供Draw(),否则会重绘两次同一区 域,产生闪烁 只重绘没有被子控件覆盖的区域 设置裁剪区域 void SetClippingRect(const TRect&aRect) Tint SetClippingRegion(const TRegion& aClippingRegion) TRegionFix<10> clippingRegion; clippingRegion.Clear(); clippingRegion.AddRect(Rect()); clippingRegion.SubRect(iSubControl1);//裁剪掉该子控件占用的区域 clippingRegion.SubRect(iSubControl2);

68

转发按键事件

只有容器被压入CONE控件堆栈
由AppUi来将其压栈 必须转发按键事件给子控件

具体实现
TKeyResponse CMainControl::OfferKeyEvent(..) { if (aType!=EEventKey) return; return iSubControl->OfferkeyEventL(..) }

69

Symbian 构建工程
构建工程的工具:bldmake和 构建工程的工具:bldmake和abld

70

Symbian 构建工程
VC6
bldmake bldfiles abld build vc6

WINS (WINdows Single Process)
bldmake bldfiles abld build wins udeb

ARMI
bldmake bldfiles abld build armi urel

THUMB
bldmake bldfiles abld build thumb urel 必须在\myproject\group下面执行

71

Symbian 构建工程
abld clean
删除由对应的abld 命令创建的所有文件 编译时产生的所有中间文件 由linker产生的所有可执行文件和导入库

abld reallyclean
做 abld clean 要做的事情 还删除由abld export 导出的文件 以及由abld makefile 或 abld test 对应命令产生的makefile文件

72

Symbian安装应用程序到手机硬件上 Symbian安装应用程序到手机硬件上
将代码部署到手机硬件的唯一方法
是由软件安装器从安装包即SIS文件(后缀为.sis)中读入

为了创建一个SIS 文件
要使用打包文件 (.pkg) 来指定应用程序关联的文件和原数据 打包文件会传递给SIS 文件创建工具 (MakeSIS)

打包文件包括
应用程序需要的一组文件、规则、选项和依赖关系的列表

73

Symbian 安装应用程序到手机硬件上
下面是应用程序MOBILE 的安装包例子
在.pkg 文件中,有分号开始的行是注释行,并且空行会被忽略
; Installation file for $$Root$$ application ; ;Languages

&EN
; ; UID is the app's UID

#{"手机新闻 手机新闻"},(0x04E7E141),1,0,0 手机新闻
; ;Supports Series 60 v 2.0 ;This line indicates that this installation is for the Series 60 platform v2.0 ;This line must appear _exactly_ as shown below in the sis file ;If this line is missing or incorrect, the sis file will not be able ;to be installed on Series 60 v2.0 platforms

(0x101F7960), 0, 0, 0, {"Series60ProductID"}

74

Symbian 安装应用程序到手机硬件上
; Four files to install ; "C:\Symbian\8.0a\S60_2nd_FP2_SC\Epoc32\release\thumb\urel\MOBILE.ap p" -"!:\system\apps\MOBILE\MOBILE.app" "C:\Symbian\8.0a\S60_2nd_FP2_SC\Epoc32\data\z\system\apps\MOBILE\MO BILE.rsc" -"!:\system\apps\MOBILE\MOBILE.rsc" "C:\Symbian\8.0a\S60_2nd_FP2_SC\Epoc32\data\z\system\apps\MOBILE\MO BILE_caption.rsc" -"!:\system\apps\MOBILE\MOBILE_caption.rsc" "C:\Symbian\8.0a\S60_2nd_FP2_SC\Epoc32\data\z\system\apps\MOBILE\MO BILE.aif" -"!:\system\apps\MOBILE\MOBILE.aif" "C:\Symbian\8.0a\S60_2nd_FP2_SC\Epoc32\data\z\system\apps\MOBILE\MO BILE.MBM" -"!:\system\apps\MOBILE\MOBILE.MBM"

75

Symbian 安装应用程序到手机硬件上
以& 开始的行是语言部分 它列出应用程序所支持的所有语言 使用两个字母的代码, 如同Symbian OS Library 中语言列表描述的那样 本例中 MOBILE 应用程序支持英语(EN) 的部分: 由% 的部分 是厂商本地化和非本地化的名称 本地化名称被用于对话框中,显示给用户 而非本地化厂商名称则由软件安装器内部使用 以一个包含在中括号中十六进制UID 开头的行是必需的 以一个包含在中括号中十六进制 它用于确保只有为特定手机硬件设计和测试的应用程序才能安装 重要的是值是十六进制的UID [0x101F7960] 以及引号中的串 (Series60ProductID) 本例中 限制ASDExample.exe 只能安装到S60 2.0 的手机上 只能安装到S60 2.0平台的的对应描述是 [0x101F7960], 0, 0, 0, {"Series60ProductID"}

76

谢谢大家! 谢谢大家!


相关文章:
更多相关标签: