The application framework calls CCoeControl::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 primitives 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); }