Symbian编程总结-图形图像篇-使用双缓存进行图形的绘制
本文章由杨芹勍原创,如需转摘请注明出处。谢谢!
所谓“双缓冲”,指的是在绘图时并不是直接绘到屏幕上,而是在内存中开辟一个缓冲区,在这个缓冲区里完成所有的绘图后,直接将其“粘贴”到屏幕上。采用双缓冲技术,由于绘图操作大部分在内存中完成,所以绘图速度没有太大的制约;此外,当进行复杂的绘图操作时,使用双缓冲技术可以有效的防止画面的闪烁。
一、双缓存技术在J2ME中的实现
在J2ME中,实现双缓存绘制图形可以通过以下步骤实现:
- 首先创建一个类成员变量Image对象,此Image对象的图像尺寸为屏幕尺寸大小。
如:如果屏幕大小为240*320,则使用以下代码创建:private Image img;
img = Image.createImage(240, 320); - 创建一个类成员变量Graphics对象,此Graphics对象指向img的Graphics对象:
private Graphics g;
g = img.getGraphics(); - 以上img对象即为内存中的缓冲区,可以使用任何方法在类成员g上绘制任意的图像,而不用在canvas的repaint事件中处理复杂的绘制过程。
- 在canvas的repaint方法,将缓冲区图像绘制在屏幕的gc上:
protected void paint(Graphics g) {
g.drawImage(img, 0, 0, Graphics.LEFT | Graphics.TOP);
}
以上就在J2ME中完成了简单的的双缓存的实现。
二、双缓存技术在Symbian中的实现
在Symbian中实现双缓冲技术有两种方法,我们先从简单的方法入手:
- 第一种方法的实现更贴近于在J2ME中的实现。在此方法中,也得先在内存中建立一个位图缓冲区对象,然后再获取位图对象的设备上下文 dc(Device Context)(类似于J2ME中的Graphics),程序可以在任意的地方对内存缓冲位图的dc绘制图形。在Draw事件(相当于J2ME的 paint事件)内,将缓冲区位图直接绘制在设备的dc上。
首先在头文件中加入如下定义:CWsBitmap* iBufBmp;
CFbsBitmapDevice* iBufDevice;
CBitmapContext* iBufGc;1) iBufBmp为缓冲区位图对象,为CWsBitmap类型。类CWsBitmap继承自类CFbsBitmap,我们在此使用CWsBitmap的原因为因为它比较快,引入SDK中对CWsBitmap类的说明:
This is a bitmap to which the window server already has a handle. Functions
which take a window server bitmap are faster than equivalent functions which
take a CFbsBitmap.2) iBufDevice为CFbsBitmapDevice类型的对象,CFbsBitmapDevice的官方解释可以简单的理解为管理文字和位图的图形设备:
A graphics device to which a bitmap managed by the font and bitmap server can be drawn.3) iBufGc为CBitmapContext类型的对象,即位图对象的设备上下文dc,获取了iBufGc后,可以使用CBitmapContext中的方法对位图进行绘制。
关键部分代码:
/**
* 初始化双缓冲区
*/
void CTestDoubleBufferAppView::InitDoubleBufferL()
{
iBufBmp = new(ELeave)CWsBitmap(CEikonEnv::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); // iDevice, iBufBmp
}/**
* 测试在缓冲区上绘制
*/
void CTestDoubleBufferAppView::DoTestDraw()
{
iBufGc->Clear(Rect());// 在buffer里画方块,而不是在屏幕上
for (int i=0; i<100; i+=2)
{
iBufGc->DrawRect(TRect(TPoint(i, i), TSize(50, 50)));
}}
/**
* View的重绘事件
*/
void CTestDoubleBufferAppView::Draw(const TRect& /*aRect*/) const
{
// 以下代码忽略
// // Get the standard graphics context
// CWindowGc& gc = SystemGc();
//
// // Gets the control's extent
// TRect drawRect(Rect());
//
// // Clears the screen
// gc.Clear(drawRect);SystemGc().BitBlt(TPoint(0, 0), iBufBmp);
}
三、参考文献