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 in the Symbian OS Library. The
S60 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 OS 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 Symbian OS, 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); }