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); }