Symbian OS: 创建自定义控件

SYMBIAN OS
Symbian OS: 创建自定义控件
版本1.0
2005年9月28日
Symbian OS:创建自定义控件 | 2
法律声明
版权.诺基亚公司 20055。版权所有。
Nokia和Nokia Connecting People是诺基亚公司的注册商标。Java以及基于Java的商标是 Sun Microsystems 公司的注册商标。本文中提到的其它产品和公司名称可能是其相应公司的商标或商号。
否认声明:
本文内容按“现状”(as is) 提供,即没有任何形式的保证,包括对产品可销售、适合特定目的以及其它由本文任何建议、规范和范例衍生出来的任何保证。另外,本文提供的信息是初级的,因此在最终版本确定之前其可能有很大改动。本文目的仅是提供信息参考。
诺基亚公司不承诺承担任何责任,包括对任何所有权的侵害责任,尽管这些所有权与实施本文给出的内容有关。诺基亚公司不保证或声称使用本文内容不会侵害上述所有权。
诺基亚保留对本文,在未经事先通知的情况下,随时进行变更的权力。
许可声明:
允许对本文进行仅用于个人使用目的的下载和打印。在此没有许可任何其它知识产权。 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 3
目录
1. 简介.......................................................................................................................5
2. 为Symbian OS手机创建自定义控件.......................................................................6
2.1 复合控件..........................................................................................................................6
2.2 窗口................................................................................................................................6
2.3 输入事件..........................................................................................................................8
3. CBlinkText范例..................................................................................................10
4. 控件类型..............................................................................................................13
4.1 顶层控件........................................................................................................................13
4.2 视图控件........................................................................................................................13
4.3 绘制控件........................................................................................................................14
5. 自定义控件..........................................................................................................16
5.1 资源...............................................................................................................................16
6. 总结.....................................................................................................................18
7. 术语与缩写..........................................................................................................19
8. 参考.....................................................................................................................20
9. 文档评价..............................................................................................................21
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 4
修订记录
2005年9月28日
版本1.0
初始文档版本
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 5
1. 简介
本文介绍了自定义控件的设计、使用以及与这些控件有关的设计问题。 虽然本文的重点是自定义控件的设计,但同时也介绍了控件结构体系的基础知识;另外本文对控件的派生与复合控件也进行了简要的介绍。 文中未包括接口描述;它们可以在相关的SDK文档中找到。 本文通过范例重点阐述了如何设计自定义控件。 本文最后介绍了如何在视图中使用自定义控件以及如何在资源中定义自定义控件。 文中所涉及的问题可以应用于任何Symbian OS平台,因为它们都具有类似的UI框架。
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 6
2. 为Symbian OS手机创建自定义控件
Symbian OS库提供了大量的UI标准控件。 此外,它允许开发者创建自己的控件。 当标准控件无法支持应用程序的UI时,则需要设计自定义控件。 大多数Symbian OS UI控件派生自CCoeControl类,CCoeControl类提供了一个控件框架并同时提供丰富的功能。 CcoeControl通过将窗口服务器及其事件封装为公共Symbian OS应用框架的―部分,即控件环境,而隐藏了相关的复杂性。
CCoeControl是控件的基类,直接由它派生自定义控件可能比较繁琐;幸运的是,一些标准控件也可以用作自定义控件的基类。 例如,CEikEdwin是单一文本编辑器(CEikSecretEditor除外)的基类,CEikListBox是所有列表框控件的基类。 一些标准控件派生自CEikAlignedControl、CEikBorderedControl、CEikMfne和CEikButtonBase这些控件抽象类: 它们的纯虚方法需要在派生类实例化前实现。
在大多数情况下,专用控件通过继承创建。 例如,一般来说,对话框是由CEikDialog派生的控件。 CEikDialog类实现了对话框的标准框架,相关特定函数需要派生类实现,如在设置控件大小之前调用的CEikDialog::PreDynLayoutInitL。 此函数的缺省实现为空,但派生的对话框可以覆盖它来设置子控件的属性,并且正确计算它的大小。
一个控件可以包括其它控件,形成所谓的复合控件,它可以包含一个或多个子控件。 复合结构通常可以递归,它可以使用子控件实现复杂的功能。 值得注意的一点是,复合控件不在屏幕上绘制任何内容,因为通过子控件在UI上绘制。 (复合控件可以绘制其子控件的背景。 Series 60 SDK包含解释此方法的范例。)
2.1 复合控件
小组件的聚合是面向对象编程的核心,其设计思想在复合控件的设计中得以体现,而复合控件正是由子控件组成的。创建复合控件的主要原因是多个控件可以作为一个控件处理。 由于复合控件也是由CCoeControl继承而来,因此它们可以和所有其它控件是一样的。 例如,子控件的位置与父控件的位置有关,这样父控件的调整也会为所有子控件设置新的绝对位置。
复合控件实现的函数允许控件框架在初始化和绘制控件时访问子控件。CCoeControl::CountComponentControls可以返回子控件的数目,CCoeControl::ComponentControl方法可以返回一个指向子控件的指针。 任何时候,所有子控件都可以通过CCoeControl::ComponentControl被访问,无论它们是否可见。 应该通过CCoeControl::MakeVisible方法调整控件的可视性。 复合控件拥有子控件,因此它负责子控件的创建与销毁。 复合控件还应该设置其子控件的位置和大小;必须确保所有子控件都位于复合控件矩形内,并且可视的子控件矩形不能互相重叠。
2.2 窗口
RWindow类代表设备屏幕上窗口服务器支持的区域。 控件能够被绘制到窗口中,并且在窗口具有焦点时从窗口服务器接收事件。 所有控件都通过使用一个窗口访问屏幕很重要。 控件可以拥有它们自己的窗口或使用其它控件的窗口。 一种常用的设计方法是顶层复合控件创建一个窗口,然后它的所有子控件共享该窗口。
在控件之间共享窗口可以节约资源,因此Symbian建议控件不创建它们自己的窗口。 出于性能考虑,窗口应尽可能少,因为它们需要消耗资源。 窗口作为窗口服务器的一个客户端,窗口越少越意味着上下文切换和进程间通信的减少。 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 7
控件窗口通过CCoeControl::CreateWindowL方法创建。 它有一些重载方法,但最常用的是没有参数的重载方法,它基于控件的内存地址创建主窗口及其句柄。 另一个有用的重载方法是使用CCoeControl作为参数,从而为控件的窗口创建子窗口,例如控件使用窗口滚动或剪切时需要操作子窗口——作为一些特例,为子控件创建窗口而不是使用父控件的窗口是需要的
如果一个控件没有自己的窗口,则应该通过调用CCoeControl::SetContainerWindowL方法设置它需要使用的窗口。 该方法有一些重载,但对于复合控件,使用CCoeControl作为参数的重载最为有用。 该参数可以是拥有窗口的控件,也可以是与其它控件共享窗口的控件。
当一个控件在另一个控件的窗口中绘制时,其位置与窗口相对。 如果一个控件拥有的是一个子窗口,该控件的位置与父窗口相对;然而,如果该控件是复合控件,则其子控件的坐标与其父控件窗口是相对的。 顶层窗口所拥有的控件的显示位置与屏幕相对,即使用显示屏的物理坐标。
为了解释以上内容,假设有三个控件,A、B和C(如图1所示)。 A是顶层控件,它拥有一个主窗口。 在第一个范例中,子控件B和C不创建它们自己的窗口。
A的子控件B不创建窗口,它拥有一个子控件C,B的窗口通过调用CCoeControl::SetContainerWindowL(A)方法设置,C的窗口通过调用CCoeControl::SetContainerWindowL(B)方法设置。 C的位置(p)与A是相对的,因为它是真正的窗口所有者。 A的位置(m)与屏幕位置是相对的。 ScreenABCWindownpm
图1: 顶层父控件拥有窗口时,三个控件的相对位置
然而,如果B是A的一个子控件,但它有自己的窗口,即A窗口的子窗口(如图2所示)。 如果C是B的子控件,并且通过调用CCoeControl::SetContainerWindowL(B)设置它的窗口,C的位置(p’)是与B的窗口相对的。 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 8
ScreenABCWindownpmWindowp’
图2: 子控件拥有窗口时,三个控件的相对位置
如本例所述,控件位置取决于绘制该控件的窗口;因此,设计者需要知道各个控件的绘制窗口。 在设计UI布局时,这是一个重要问题。一些标准控件拥有自己的窗口,如菜单、对话框和滚动条等浮动控件。 这些控件动态地调整它们的绘制,且坐标调整对设计者透明。 CCoeControl::OwnsWindow调用可以检测控件是否拥有窗口。
各控件拥有自己的区域或边界矩形;通常所期望的行为是控件在边界矩形内绘制。 控件在边界矩形之外绘制时会发生剪切。 剪切使一些绘制效果易于实现,例如,移动控件位置的滚动,任何时候只有一部分控件内容可见。
如果控件需要剪切,它必须拥有一个窗口,因为控件本身不具备剪切功能——剪切在控件的窗口中执行。 非拥有窗口的控件拥有一个边界矩形,它可以在边界矩形以外的位置上绘制,只要该位置在它正使用的窗口中。 因此,控件的CCoeControl::Draw方法应该只绘制它自己的边界矩形,任何子控件应该在它们的复合控件边界框内绘制。 否则,重新绘制可能导致混乱,例如对于非拥有窗口的控件调用CCoeControl::DrawDeferred的情况,复合控件边界框的重绘使控件窗口的边界矩形部分失效,边界矩形以外的象素将不重新绘制-它们将被剪切; 但是如果整个窗口被重新绘制,控件边界框以外的象素则被绘制-不会被剪切。 由于控件绘制方式不同,因此依赖于绘制发起方式会导致画面错误。
2.3 输入事件
控件可以接收按键或指针事件。 窗口服务器产生事件,应用框架使用活动调度器循环侦听事件。 当发生事件时,它将被发送到具有焦点的控件,框架然后根据事件类型调用控件的处理方法;例如,为按键事件调用CCoeControl::OfferKeyEventL ,为指针事件调用CCoeControl::HandlePointerEventL。
应用框架仅向压入事件堆栈中的控件提供按键输入事件。 通过CCoeAppUi::AddToStackL方法向事件堆栈压入输入接收控件。 事件堆栈中可以有多个控件。在发生事件时,按照压入到堆栈中的顺序为控件调用CCoeControl::OfferKeyEventL方法,即首先提供事件给最后压入的控件。 事件被依次传给堆栈中的各个控件,直到控件返回
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 9
TKeyResponse::EKeyWasConsumed。 TKeyResponse的一种常用策略是,如果控件使用事件执行某些内容,则该事件将被消耗掉。 通常一个顶层复合控件被压入到堆栈中,顶层控件将事件分配给它的子控件。 然而,无论父控件是否在事件堆栈中,事件都不会自动提供给子控件。 如果子控件需要事件,复合控件应执行OfferKeyEventL,将按键事件传递给子控件。 该方法使事件流程的实现更加准确、清晰,而且更不容易出现错误。
按一次按钮可产生三个事件: EEventKeyDown、EEventKey和EventKeyUp,因此CCoeControl::OfferKeyEventL将被调用三次,在按下、保持和释放按钮时各调用一次。 在大多数情况下,控件只需要EEventKey ,无需处理其它事件;然而,需要更准确输入的游戏和其它应用可能使用所有按键事件。 TKeyEvent保存真正的事件,其iCode 成员中定义为TKeyCode 枚举值或UNICODE 字符编码值。 例如,如果应用需要检测按钮‘a’是否按下,则可以通过确定iCode 是否等于值‘a’(UNICODE映射中为97)来实现。 一些标准按键是在uikon.hrh中定义的。应用框架本身也拥有一个内嵌的键事件捕捉方法,相关键事件直接会被应用程序捕捉,如keylock,而不提供给控件堆栈中的控件。
如果控件需要指针事件,则需要实现CCoeControl::HandlePointerEventL方法。 窗口服务器仅向拥有窗口的控件提供指针事件。 在缺省情况下,当指针事件坐标位于边界矩形内时,控件才获得事件。 如果控件不拥有自己的窗口,则通过控件框架提供事件。 这里,CCoeControl::HandlePointerEventL的缺省实现将检查各子控件,如果坐标位于子控件的边界矩形内,则调用其HandlePointerEventL 方法。 当复合控件覆盖HandlePointerEventL 方法时,它应该调用缺省的实现,因为子控件也会消耗指针事件。 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 10
3. CBlinkText范例
为了说明第2章所讨论的复合控件功能,本章将给出一个简单的范例,CBlinkText ——一个闪烁文本(blinker)的基本范例。 闪烁文本是被设定为周期性可见和不可见的文本行。 阅读闪烁文本比较困难,但它是强调消息重要性的一种有用方法。
CBlinkText说明了通过组合标准控件创建新功能的简便性。 本例中,复杂的文本绘制由CEikLabel 组件处理,而CBlinkText 用作一个容器,设置周期可见性来绘制CEikLabel 。
CBlinkText 类由CCoeControl公有派生,以适用控件框架。 公有方法包括闪烁文本特有API,用于设置和获取控件特定属性的公有CCoeControl API。
class CBlinkText : public CCoeControl
{
public:
void ConstructL(CCoeControl& aParent);
CEikLabel& Label() const;
void Start(TTimeIntervalMicroSeconds32 aInterval);
void Stop();
~CBlinkText();
TSize MinimumSize();
private:
TInt CountComponentControls() const;
CCoeControl* ComponentControl(TInt aIndex) const;
void SizeChanged();
static TInt Tick(TAny* aThis);
void DoTick();
private:
CEikLabel* iLabel;
CPeriodic* iTicker;
};
void CBlinkText::ConstructL(CCoeControl& aParent)
{
SetContainerWindowL(aParent);
iLabel = new (ELeave) CEikLabel();
iLabel->SetContainerWindowL(*this);
iTicker = CPeriodic::NewL(CActive::EPriorityIdle);
Start();
}
ConstructL是Symbian OS编程中的第二阶段构造函数。 构造函数创建CEikLabel 与CPeriodic 实例。 CPeriodic 是一个简单的定时器,用于触发周期性函数调用。 定时器使用最低优先级创建,因为该控件没有实时要求。 构造函数同时为本身和标签控件设置窗口,因为闪烁文本控件没有自己的窗口。 一些控件(类似CBlinkText 所做的)自动设置它们的容器窗口,但另一些控件像CEikLabel 需要显式设置。 如果构造函数使用父控件作为参数,则很可能有此设置要求,因为它也需要设置容器窗口,但通常了解要求的唯一方法是检查API文档。
CEikLabel& CBlinkText::Label() const
{
return *iLabel;
}
Label 方法返回CEikLabel 引用,它可以用于设置文本及其属性。 提供这些访问函数并非最佳的面向对象设计,但在此例中它使得程序较为简单。
void CBlinkText::Start(TTimeIntervalMicroSeconds32 aInterval)
{
iTicker->Start(aInterval, aInterval, TCallBack(Tick, this));
}
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 11
Start启动绘制。 与桌面PC相比,Symbian OS中的绘制相对较慢。 一个TTimeIntervalMicroSeconds32非常短,比实际系统的定时器短得多。 在大多数设备中,硬件定时器的准确性为几毫秒,软件中定义的值无法更精确;因此当aInternal 的值比1000微秒小时,实际定时器周期通常比1000微秒大。
void CBlinkText::Stop()
{
iTicker->Cancel();
}
Stop 终止绘制。 在移动设备中,可用的电能有限,因此开发者应该避免使用长时间运行、快速跳动的定时器。 在控件不可见或系统进入空闲模式时,Stop应该被调用。 跳动的定时器使系统无法进入节能模式,从而快速消耗电能。
CBlinkText::~CBlinkText()
{
if(iTicker)
iTicker->Cancel();
delete iTicker;
delete iLabel;
}
析构函数清除实例。 定时器必须在被删除前停止,并且应该进行检查以确保它不为NULL,例如,第二阶段构造函数可能由于内存不足错误而失败。
TInt CBlinkText::CountComponentControls() const
{
return 1;
}
CountComponentControls 返回复合控件中的子控件数。 在递归遍历控件树时,需要子控件数;例如,当初始化应用时、在顶层控件调用ActivateL 方法后、或在进行绘制操作时均需要子控件数。
CCoeControl* CBlinkText::ComponentControl(TInt /*aIndex*/) const
{
return iLabel;
}
控件框架使用ComponentControl方法访问子控件,通过CountComponentControls返回的子控件数以确定需要进行多少次访问。
void CBlinkText::SizeChanged()
{
iLabel->SetExtent(Position(), Size());
}
当SetRect、SetSize或SetExtent方法被调用时,SizeChanged 将被调用。 SetSize方法是复合控件调整布局的便利之处。 闪烁文本中只存在一个填充了整个复合控件的子控件。
TSize CBlinkText::MinimumSize()
{
return iLabel->MinimumSize();
}
MinimumSize 提供了控件边界框所需的最小面积。 在没有任何更多有关控件内容信息的情况下,复合控件需要此最小面积信息。
TInt CBlinkText::Tick(TAny* aThis)
{
static_cast<CScrollText*>(aThis)->DoTick();
return 0;
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 12
}
Tick 是一个静态回调函数,定时器在到期时调用它。 Timer 是一个活动对象,并且从它的RunL 方法调用回调函数。 由于活动对象为非抢先式,因此回调函数应该快速返回——其它回调函数(包括输入)直到它返回后才进行处理。
void CBlinkText::DoTick()
{
iLabel->MakeVisible(!iLabel->IsVisible());
}
DoTick 仅仅设置标签的可见性。 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 13
4. 控件类型
4.1 顶层控件
大多数Symbian OS应用都有一个状态面板,一个命令面板和一个应用视图。 应用视图是应用的主窗口,它被实现为一个拥有窗口的控件——顶层控件。 顶层控件可能是文本编辑应用的一个文本控件,或者仅仅是为图像浏览应用绘制位图。 顶层控件从CCoeControl派生,在对话框体系结构中,顶层控件从CEikDialog 派生。 如果顶层控件处理事件,则通过CCoeAppUi::AddToStackL方法将其添加到事件堆栈中。 控件被销毁之前,必须使用CCoeAppUi::RemoveFromStack方法将其从事件堆栈中删除。 在顶层控件的生命周期中,可以根据应用设计者的需要,向事件堆栈添加控件或从事件堆栈删除控件。
创建顶层控件不同于创建其它控件。 以下是创建顺序的一个基本范例:
.. CreateWindowL();
顶层控件必须创建一个窗口,用于该控件及其子控件的绘制。
.. Window().SetShadowDisabled(ETrue);
一个应用顶层控件没有阴影。 对话框可以有阴影;该阴影具有三维效果,它使得对话框看起来像置于应用之上。
子控件同时在这一步创建-即窗口创建之后,窗口矩形设置之前。
.. SetRect(iEikonEnv->EikAppUi()->ClientRect());
顶层控件矩形被设置为框架为应用指定的区域。 调用SetRect 将会调用SizeChanged 方法,这里应该设置所有子控件的位置和大小,从而调整UI的控件布局。
.. SetBlank();
如果设置了空白标志,缺省的CCoeControl::Draw 方法则使用缺省的单色填充应用程序区域。 由于复合控件的CCoeControl::Draw方法先于子控件的CCoeControl::Draw方法被调用,因此如果背景被设为空白,即使子控件未实现Draw 方法,子控件也无须为防止控件之下的应用程序可见而覆盖整个应用程序区域,。
.. ActivateL();
对于一些控件,一些初始化操作可能无法在此阶段之前执行。 因此,ActivateL 为所有子控件的实际初始化提供了最后的地方。 缺省实现为控件的绘制做准备,如果对此方法进行覆盖,需要调用缺省实现。
.. iEikonEnv->EikAppUi()->AddToStackL(this);
如果应用控件需要处理事件,它应该将自身加入到应用事件堆栈。
4.2 视图控件
从Symbian OS v6.1及更高版本开始,应用框架可以充分利用视图体系结构的优势。 任何应用都可以提供视图,这些视图可以从应用内部或外部被调用。 视图通常被实现为一个从
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 14
MCoeView 接口派生的顶层控件。 CCoeAppUi::RegisterViewL向视图服务器注册视图。 应用可以实现并注册多个顶层控件,这些控件通过视图服务器激活和去活。
每个视图控件具有一个ID。当激活视图时,需要提供应用UID(唯一标识符,任何应用或库都必须包含的32位受控值)和一个视图UID。 视图服务器启动与UID匹配的应用(如果已经运行,则将其送到前台);在创建期间,应用的所有视图都被注册到视图服务器,视图服务器寻找正确的视图ID并将其送到前台。
快速的视图激活很重要;提供视图的任何应用必须快速响应,启动要快。 这是由于视图服务器是单线程服务器,同一时刻只能处理一个激活请求;因此,如果存在其它请求,它们必须等待,直到第一个激活请求完成。 一个行为较差的视图提供者可能会使整个设备停止工作,直到此行为完成或视图服务器强行关闭应用。 如果发生设备工作停止,显示屏将不会更新,应用也不会响应输入。
4.3 绘制控件
当更新屏幕上的控件区域时,控件框架调用CCoeControl::Draw方法。 缺省实现在控件设置空白标志时,会使用背景颜色填充区域;否则不执行任何动作。 复合控件本身通常不实现Draw ,而是由子控件完成所有绘制。 控件框架首先调用父控件的Draw 方法,然后递归调用各子控件的Draw 方法。
在大多数情况下,控件通过屏幕设备图形上下文在屏幕上绘制,并且通过CCoeControl::SystemGc() 方法访问图形上下文。 图形上下文提供一系列GDI(图形设备接口—通用Symbian OS图形API)绘制接口,用于屏幕上的实际绘制。 GDI API的速度不是特别快,通常性能问题会影响软件体系结构设计。
永远不要直接调用Draw 方法。 它是一个屏幕更新时调用的回调函数。在 CCoeControl::ActivateL方法被调用后,任何时候都可以调用Draw。 窗口服务器可以确定何时更新屏幕区域,或者何时通过调用CCoeControl::DrawDeferred或 CCoeControl::DrawNow函数进行绘制。
CCoeControl::DrawNow能够直接启动绘制,并且CCoeControl::Draw 方法会在DrawNow 方法返回前被调用。 CCoeControl::DrawDeferred能够发起异步操作;它能够立即返回,但实际绘制会在优先级较低的空闲对象运行时执行——这样,更急迫的任务,如输入处理将首先被执行。 绘制始终是一项繁重的操作;它给设备带来压力,频繁的屏幕更新通常会影响性能。 因此应该避免不必要的绘制。 在大多数情况下,DrawDeferred是推荐的绘制方法: 在屏幕缓存区中,控件矩形区域被标识为无效,用于随后的更新。 在屏幕缓存区被更新前,调用CCoeControl::DrawDeferred,或者由于其它原因标识区域失效,则重叠更新的绘制无效。
所有绘制应该在控件的Draw 方法内中执行,除此之外不应执行其它工作。 Draw 方法应该尽可能快。 例如,动态创建字体并在绘制时读取位图或资源是较差的设计。 根据经验,好的设计在Draw 方法不应该有一个陷阱处理程序;任何可以预先执行的费时功能应该进行缓存。
对于执行大量绘制操作的控件,应该对绘制操作进行缓存,即双缓存操作。 双缓存操作首先对内存上下文执行绘制,接着在Draw 方法中,仅将上下文的位图传送给屏幕。 在Symbian OS中,实现双缓存最简便的方法是创建一个CFbsBitmap ,然后和图形上下文绑定—这样就可以使用屏幕上下文的GDI接口。 在内存位图缓存中执行绘制,当窗口服务器更新失效屏幕区域时,内存缓存将被拷贝到其中。 游戏中经常使用双缓存,但也可以用于绘制控件性能非常重要的任何应用中。
以下是有关如何创建和使用双缓存的一个简短的范例: 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 15
iGcBmp = new (ELeave) CWsBitmap(iEikonEnv->WsSession());
User::LeaveIfError(iGcBmp->Create(aClientRect.Size(), iEikonEnv->ScreenDevice()->DisplayMode()));
iGcDevice = CFbsBitmapDevice::NewL(iGcBmp);
User::LeaveIfError(iGcDevice->CreateBitmapContext(iGc));
iGcBmp 是一个CWsBitmap指针,指向位图内存缓存区,它被创建为具有与顶层控件相同的宽度和高度以及与相同的显示色位深度。iGcDevice 是一个指向CBitmapDevice 设备的指针,而上下文iGc指向CbitmapContext的 实例。当控件绘制自身时,使用的是iGc 而非从CCoeControl::SystemGc()方法获得的CScreenGc, 双缓存绘制应该在CCoeControl::Draw方法之外执行,需要时可以直接调用。 只有在离屏绘制的结束时,内存缓存才通过调用CCoeControl::DrawDeferred()传到屏幕。
void CMyDrawingExample::Draw(const TRect& /*aRect*/) const
{
SystemGc().BitBlt(TPoint(0, 0), iGcBmp);
}
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 16
5. 自定义控件
5.1 资源
如果对话框重用控件,那么创建资源文件更方便,这样可以通过资源来创建控件。
这里给出了一个非常简单的范例,它介绍了如何扩展CBlinkText以便从资源文件定义它。 通过Symbian OS的资源编译器rcomp,可以将资源文件编译成二进制资源。 资源文件和C语言的语法相似。
资源必须在使用前引入。通常资源定义在*.rh 文件中,与C++文件共享的常量定义在 *.hrh 文件中。 对于CBlinkText,只有一个常量: 类型标识符;这是一个唯一的整数值,不能与其它控件的类型标识符冲突。 如需了解更多信息,参见平台的.hrh文件。
常量按如下方式在*.hrh文件中定义:
enum {KBlinkTextType = KAknCtLastControlId };
在*.rh文件中有一个对资源声明的定义:
STRUCT BLINKTEXT
{
LTEXT txt;
LONG period = 2000000;
}
STRUCT 关键字定义了闪烁文本的资源参数结构。一些内置的类型可以被使用。 LTEXT 保存UNICODE 文本,LONG 保存32位数值。 给参数赋值时,它们成为缺省值。
在资源文件中定义自定义控件与任何普通控件相似;下列是从资源文件中摘取的一个简短范例,说明了如何在对话框中使用闪烁文本:
RESOURCE DIALOG r_blinker_dialog
{
flags = EEikDialogFlagWait;
title = "Blinker";
buttons = R_EIK_BUTTONS_CANCEL_OK;
items =
{
DLG_LINE
{
type = KBlinkTextType ;
control = BLINKTEXT
{
txt="hello world";
period=1000000;
};
}
};
}
控件框架仅识别普通控件,控件工厂(factory)方法通过标识符创建它们。 由于自定义控件具有它们自己的标识符,因此这些控件需要通过对话框代码创建。
CEikDialog::CreateCustomControlL是一个类工厂方法,闪烁文本对话框的最小实现包含以下内容:
class CBlinkDialog : public CEikDialog
{
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 17
SEikControlInfo CreateCustomControlL(TInt aControlType);
};
SEikControlInfo CBlinkDialog::CreateCustomControlL(TInt aControlType)
{
if(aControlType == KBlinkTextType )
{
SEikControlInfo sinfo;
sinfo.iControl = new (ELeave) CBlinkText();
return sinfo;
}
else
return CEikDialog::CreateCustomControlL(aControlType);
}
CBlinkText 必须覆盖ConstructFromResourceL 方法以便能够由资源创建;对话框框架能够在构造其间调用它。 CBlinkText::ConstructFromResourceL采用与ConstructL 方法相同的方式创建控件,但使用TresourceReader作为参数。 资源读取器是一个工具类,它从资源文件流中读取字节;因此,读取顺序和数据长度必须与资源结构的声明相匹配。 此控件的窗口上下文由对话框框架设置,但它仍需调整子控件的窗口上下文。
void CBlinkText::ConstructFromResourceL(TResourceReader& aReader)
{
iLabel = new (ELeave) CEikLabel();
iLabel->SetContainerWindowL(*this);
iTicker = CPeriodic::NewL(CActive::EPriorityIdle);
TPtrC label = aReader.ReadTPtrC16();
iLabel->SetTextL(label);
const TInt interval = aReader.ReadInt32();
Start(interval);
}
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 18
6. 总结
Symbian OS手机上的所有用户界面都是通过控件创建。 鼓励开发者在界面设计中使用普通标准控件,因为它们为应用提供一致的外观感受。 标准控件可以自动与框架交互,从而为应用开发者排除了布局设计的问题。 如果需要为用户提供更好的用户体验,可以利用自定义控件来实现。 通常,新控件应该与平台总体的UI风格一致。 但也可以通过自定义控件创建不同于标准UI风格但与特殊UI风格相匹配的接口。例如,采用仿效物理CD播放器上的控件为音乐播放器应用提供一个界面,可以使用户快速学习如何使用。 这意味可以使用其它平台或物理世界中用户理解熟悉的界面。 然而,UI设计者应该注意避免过度使用自定义控件,因为它们可能会给用户带来困惑。在使用自定义控件时,建议整个应用、整个屏幕保持一致且有针对性。 应该特别谨慎地处理自定义控件与标准控件的混合使用。 此外,自定义控件可能需要与UI风格进行适配。 一些UI风格包括主题支持。
本文讨论了控件体系结构,给出了对所有UI控件运行环境的概述。 然后详细介绍了如何创建复合控件,接着给出了一个简单的闪烁控件的范例。 在讨论如何绘制控件,如何从资源文件和对话框资源创建自定义控件之前,介绍了顶层控件和视图。
Symbian OS控件框架允许开发者在UI控件设计中百花齐放。 虽然灵活性会明显带来一些复杂度,但是基于对常用复合控件概念的理解,任何开发者都很容易创建自定义控件。 在阅读完本文档后,开发者应该能够设计自定义控件,并将它们与应用引擎相集成。 版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 19
7. 术语与缩写
术语与缩写
含义
边界矩形
控件的边界矩形是一个定义控件所控制的可显示区域的大小和位置的矩形。
控件
屏幕的一个矩形区域,可以响应用户输入事件。
子控件
构成复合控件的控件。 子控件通常由复合控件创建和销毁。
复合控件
封装了一个或多个子控件的控件,因此用户界面是这些子控件的集合,并且与子控件的编程接口也是通过复合控件实现的。
自定义控件
应用开发者所写的控件,而非SDK所提供的控件。
控件环境
为窗口服务器的异步服务提供活动对象接口,并且为控件和应用UI提供框架。
工厂(Factory)模式
工厂(Factory)是一个接口类,其派生类能够创建对象。 此模式在类(创建器)预先不知道它要创建的所有子类时使用。 相反,由各子类(具体创建器)创建实际对象实例。
窗口服务器
管理用户输入和绘制屏幕的Symbian OS线程。
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 20
8. 参考
Series 60 Developer Platform: Application UI Customization, http://www.forum.nokia.com/documents
版本 1.0 | 2005 年 5 月 24 日
Symbian OS:创建自定义控件 | 21
9. 文档评价
In order to improve the quality of documentation, we kindly ask you to fill in the document survey.
为了提高文档质量,我们衷心邀请您填写文档调查。 版本 1.0 | 2005 年 5 月 24 日
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值