The application framework callsCCoeControl::Draw()
when
a control area needs to be updated on the display. Controls may implement CCoeControl::Draw()
or
leave the drawing to their child controls. For more information on control
hierarchies, see The
run-time control hierarchy. The platform calls CCoeControl::Draw()
for
the parent control first, and then recursively for each control.
Controls should override CCoeControl::Draw()
to draw
their content. The override should do nothing else and should be as fast as
possible. For example, it is bad design to create fonts dynamically, and read
any bitmaps or resources while drawing. A good rule of thumb is that there
should not be trap handlers in the method override; any time-consuming functionality
that can be done beforehand should be cached.
In most cases controls are drawn on the display using the screen device
graphics context, accessed with CCoeControl::SystemGc()
.
The graphics context provides a wide set of GDI (Graphics
Device Interface - common Symbian platform graphics API) drawing primitives
that can be used for drawing virtually anything on screen.
An example of a basic override of CCoeControl::Draw()
for
a control that is a top-level window in an application is as follows:
void CMyAppView::Draw( const TRect& /*aRect*/ ) const { // Get the standard graphics context CWindowGc& gc = SystemGc(); gc.SetPenStyle( CGraphicsContext::ENullPen ); gc.SetBrushColor( KRgbWhite); gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); // Gets the control's extent TRect rect( Rect()); { gc.Clear( rect ); } }
, where
CWindowGc& gc = SystemGc();
gets
the graphics context that is used when drawing the control.
CWindowGc::SetPenStyle()
, CWindowGc::SetBrushColor()
,
and CWindowGc::SetBrushStyle()
are used to set the drawing
primatives for the context
TRect
gets the size of the control rectangle
CWindowGc:Clear(rect) clears the control rectangle
For controls that perform intensive drawing operations, the drawing
should be cached: a process also known as double-buffering. Here the drawing
is done to a memory context first and then in the CCoeControl::Draw()
method
only the context's bitmap is passed to screen. In the Symbian platform, the
easiest way to implement a double buffer is to create a CFbsBitmap
and
then bind a graphics context to that - this makes it possible to use the
same GDI interface for drawing as the display context. The drawing is done
to a memory bitmap buffer. Double-buffering is a common paradigm used in games,
but can also be utilized in any application when performance of drawing controls
is important.
The following is a short example of how a double buffer is created and used:
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
is a pointer to CWsBitmap
,
the bitmap memory buffer, that is created with the same width and height as
the top-level window and with the same color bit depth as the display. iGcDevice
is
a pointer to the CBitmapDevice
device class and the context iGc
holds
the CBitmapContext
instance. iGc
is
then used instead of CScreenGc
, obtained from the CCoeControl::SystemGc()
method,
when the control draws itself. The double-buffer drawing should be done outside
of the CCoeControl::Draw()
method and can be called directly
when needed. Only at the end of the off-screen drawing is the memory buffer
flushed to the screen by calling CCoeControl::DrawDeferred()
void CMyDrawingExample::Draw(const TRect& /*aRect*/) const { SystemGc().BitBlt(TPoint(0, 0), iGcBmp); }