Drawing in traditional architecture

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

Double buffering

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