CCoeControl是所有控件的基类,它封装了一个控件的基本属性和功能。编写简单控件涉及到的函数主要有以下三类:初始化、绘图及用户输入处理。下面是一个简单控件的声明。
class CSimpleControl : public CCoeControl
{
public:
void ConstuctL(const TRect& aRect);
~CSimpleControl();
private:
void Draw(const TRect& aRect) const;
TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType);
};
初始化:控件的初始化包括三个主要内容:创建控件窗口,设置控件大小及激活控件。控件的默认大小为0 x 0,因此必须设置大小,否则将不可见。因此这三个步骤必不可少。初始化一般在第二阶段构造函数ConstructL()完成。
void CSimpleControl::ContructL(const TRect& aRect)
{
CreateWindowL();
SetRect(aRect);
ActivateL();
}
绘图:直接决定控件外观的函数是Draw()函数。
void CSimpleControl::Draw(const TRect& aRect) const
{
CWindowGc& gc = SystemGc();
gc.SetPenStyle(CGraphicsContext::ENullPen);
gc.SetPenColor(KRgbRed);
gc.SetBrushColor(KRgbDarkBlue);
gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
gc.DrawRect(aRect);
}
在这段代码中,首先调用SystemGc()获取图形上下文,SystemGc()是CCoeControl的一个成员函数;然后设置相应的图形上下文项;最后调用绘图函数DrawRect()画一个矩形。
所有的绘图都是通过图形上下文(graphics context,GC)来完成的。在Symbian OS中,定义了一个抽象类CGraphicsContext来统一图形上下文的接口,为设备无关的绘图提供了丰富的API。派生类CWindowGc和CFbsBitGc则具体实现了这些API。我们可以直接使用CFbsBitGc来绘图,但不推荐使用这种方式。在实际编程时,应用程序应该使用CWindowGc通过窗口服务器来进行绘图。CWindowGc的绘图请求在窗口服务器的客户端缓冲区上进行缓存,这样可以一次性向窗口服务器提交多个绘图请求以提高绘图效率。CONE为每个GUI应用程序提供一个CWindowGc实例作为控件的缺省图形上下文,它由CConEnv创建,并且可以 使用CCoeControl::SystemGc()来进行访问。
http://hiphotos.baidu.com/richiechyi/pic/item/6afe80de68041e52cdbf1aed.jpg
基类CCoeControl的Draw()为空,因此在编写控件时必须实现该函数,否则控件将不可见。Draw()是由应用程序框架来调用,一般不应在应用程序中直接调用Draw()。控件不只是在初始化绘制它们的外观,而且在它发生变化时或者系统要求重绘(redraw)时进行重绘。按照重绘的触发源来划分,控件的重绘分为两种:系统发起的重绘和应用程序发起的重绘。系统发起的重绘处理从窗口服务器开始,它检测并判断何时需要重绘哪部分窗口。实际上,它维护窗口上的一个无效区域,并向拥有窗口的应用程序发送一个重绘事件,要求它重绘无效区域。应用程序发起的重绘处理由应用程序触发,它可以根据需要采用如下方法来实现(这些函数最终都是通过调用Draw()来实现的):void CCoeControl::DrawNow();立即重绘整个控件;void CCoeControl::DrawDeferred()const;一旦有机会就重绘整个控件;void RWindow::Invalidate(const TRect&);一旦有机会就重绘由参数指定的矩形区域。然而通过将重绘活动限制在矩形中,几乎不会节省很多开销,因此,编写大多数控件时,一般忽略传递限制矩形参数。
用户输入处理:
Symbian OS中处理用户输入的两个基本函数是OfferKeyEventL()和HandlePointerEventL()。由于Series60平台不支持笔写输入,所以主要使用OfferKeyEventL()。下面是一个简单控件处理按键事件的代码:
TKeyResponse CSimpleControl::OfferKeyEventL(const TKenEvent& aKeyEvent, TEventCode aType)
{
switch(aType)
{
case: EEventKey:
if (aKeyEvent.iScanCode == EStdKeyNkp5 || aKeyEvent.iScanCode == EStdKeyEnter)
iMyGameEngine->Fire();
break;
case: EEventKeyDown:
//....
case: EEventKeyUp:
//....
}
return EKeyWasNotConsumed;
}