Symbian绘图编程
Symbian OS中,在可显示窗体上画图是通过图形设备(graphics device)和图形上下文(graphics context)来实现。
一、图形设备
图形设备是对呈现图形的设备(屏幕、打印机等)的抽象。它提供了一组独立于设备的接口,应用程序使用这些接口,通过图形上下文(graphics context)来画图。图形设备是画图的中介,图形上下文在画图时画在这些图形设备上。在Symbian中图形设备通过图形设备类来体系,其继承结构如下:
CgraphicsDevice 图形设备的基类
CbitmapDevice 位图化图形设备的基类
CFbsDevice 使用字体位图服务器的图形设备基类
CPrinterDevice 具有打印功能的设备基类
CWsScreenDevice 使用窗口服务器的屏幕设备,View中默认采用的图形设备
CFbsBitmapDevice 针对内存的图形设备,可用于双缓存
CFbsScreenDevice 使用直接屏幕访问(DSA),而不通过窗口服务器,比较快
二、图形上下文
图形上下文为图形设备提供了上下文,也就是画图环境。包括画笔、画刷的颜色格式设置以及字体字形等设置,这些设置都是设备无关的。
图形上下文还定义了画图区域,通常情况下不能将图形画在定义的区域外;它同时还包括了很多主要的画图操作。大部分操作都在抽象类CGraphicsContext中定义。这些画图操作包括绘画和填充各种图形如点、直线、曲线、弧形、矩形、多边形、圆形及椭圆形、字体及位图等。
其继承结构如下:
CwindowGc:窗口图形上下文,View中默认提供
CfbsBitGc:位图图形上下文,可绘画和填充各种图形,及其对位图的操作。
CanimGc:与动画相关的图形上下文。
三、位图
Symbian中通过CFbsBitmap来操作位图,包括创建和加载等,同时提供按位操作位中信息的功能。为了提高位图的描画速度,窗口服务器提供自己的位图类CWsBitmap。它通过取得位图处理的所有权来除去窗口服务器和FBS之间多余的上下文转换。CWsBitmap继承自CFbsBitmap类,
四、描画方法
1、View默认描画
在view类中,我们可以通过调用SystemGc获取应用程序框架为我们创建好的窗口图形上下文,并通过该类完成图形的描画以及位图的显示。其采用的图形设备类为CWsScreenDevice,图形设备上下文为CWindowGc。
/* 创建位图 */
iwsBitmap = new (ELeave)CFbsBitmap();
CleanupStack::PushL(iwsBitmap);
iwsBitmap->Create(TSize(aRect.Width(), aRect.Height()),
iCoeEnv->ScreenDevice()->DisplayMode());
CleanupStack::Pop(iwsBitmap);
/* 填充位图 */
iwsBitmap->LockHeap(); // 必须锁住位图内存,否则产生内存异常
TUint32 * bitMapAddr = iwsBitmap->DataAddress();
TSize bitMapSize = iwsBitmap->SizeInPixels();
Mem::Fill(bitMapAddr,
bitMapSize.iHeight * iwsBitmap->ScanLineLength(bitMapSize.iWidth, iwsBitmap->DisplayMode()),
170);
iwsBitmap->UnlockHeap();
/* 描画位图 */
CWindowGc& gc = SystemGc(); //获取图形上下文
TRect drawRect(Rect());
gc.BitBlt(TPoint(0, 0), iwsBitmap);
2、双缓冲描画
view默认描画环境(CWsScreenDevice与CWindowGc)数据在客户端窗口服务器缓冲区上进行缓冲,当描画多个运动的对象时,窗口服务器的客户端缓冲可能被充满并且有可能在所有对象都更新的时候溢出,从而倒是屏幕闪烁等现象,可通过双缓冲来解决该问题。
所谓双缓冲是指先在内存中创建位图空间,并在该空间中完成描画,之后整体切换到屏幕上显示。屏外位图可以使用位图化的图形上下文和内存图形设备类来创建:CFbsBitGc和CFbsBitmapDevice。
iBufBmp = new(ELeave)CWsBitmap(CCoeEnv::Static()->WsSession());
CleanupStack::PushL(iBufBmp);
User::LeaveIfError(iBufBmp->Create(Rect().Size(),
CeikonEnv::Static()->ScreenDevice()->DisplayMode()));
iBufDevice = CfbsBitmapDevice::NewL(iBufBmp);
CleanupStack::PushL(iBufDevice);
User::LeaveIfError(iBufDevice->CreateBitmapContext(iBufGc)); CleanupStack::Pop(2);
3、直接屏幕绘图
直接屏幕绘图是指采用 CfbsScreenDevice图形设备进行绘图,不经过窗口服务器,节省了设备驱动与窗口服务器间的上下文切换,提高了速度。创建直接屏幕图形设备及其相关的位图图形上下文的代码如下:
CFbsScreenDevice* iFbsScreenDevice; /* 直接屏幕设备 */
CFbsBitGc* iFbsBitGc; /* 位图图形上下文 */
iFbsScreenDevice = CfbsScreenDevice::NewL(0,
CCoeEnv::Static()->ScreenDevice()->DisplayMode());
iFbsScreenDevice->CreateContext((CGraphicsContext*&) iFbsBitGc);
iFbsBitGc->SetUserDisplayMode(
CcoeEnv::Static()->ScreenDevice()->DisplayMode());
4、直接访问屏幕内存
我们可以获取屏幕相关的内存地址(尚不确定是否为显存),并通过操作该地址完成图形描画,(照此看来,Symbian并不支持在显存中申请地址)。获取屏幕相关内存地址代码如下:
TPckgBuf<TScreenInfoV01> infoPckg;
TScreenInfoV01& screenInfo = infoPckg();
UserSvr::ScreenInfo(infoPckg);
TUint16* screenMemory = (Tuint16*)(
(int)screenInfo.iScreenAddress + 16);
5、DSA绘图
由于屏幕直接绘图和直接访问屏幕相关内存的方法绕过了窗口服务器,因此它不能通知应用程序是否出现另一个窗口或者窗口组。即使当应用程序失去焦点的时候得到一个事件,它们也不能停止直接描画,从而导致屏幕内容有可能被弄乱。尤其在突然有电话打进来的情况下。
为了解决该问题,Symbian退出了CDirectScreenAccess访问方式,该方式也采用CfbsScreenDevice直接访问屏幕,但是需要view类继承MDirectScreenAccess,重写Restart和AbortNow虚方法,当产生需要切换屏幕的事件时窗口服务器回调相应虚方法,解决了上述两种直接绘图方法中存在的问题。创建代码如下:
CCoeEnv* env = CCoeEnv::Static();
iDirectScreenAccess = CdirectScreenAccess::NewL(
env->WsSession(), *(env->ScreenDevice()),
this->Window(), *this);
iDirectScreenAccess->StartL();