Week 23 contribution of PDK documentation content. See release notes for details. Fixes bugs Bug 2714, Bug 462.
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License
"Eclipse Public License v1.0" which accompanies this distribution,
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
Nokia Corporation - initial contribution.
Contributors:
-->
<!DOCTYPE concept
PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-A3BCC33F-D11B-4F98-BCC3-9A06381A02E7" xml:lang="en"><title>Constructing
the view controller in the view architecture</title><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>Each view controller acts like a small UI controller.</p>
<p>The call on the first phase constructor of the view controller occurs
in the<xref href="GUID-FD2CDEB8-0784-4BE5-A775-170F57D71BBC.dita"> UI controller</xref>.</p>
<p>The methods you need to implement in your <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita"><apiname>CAknView</apiname></xref>-derived
class are as follows:</p>
<ul>
<li><p>C++ default constructor, which cannot contain any code that
might leave. A common implementation is:</p>
<itemgroup>
<codeblock id="GUID-CA1A42F0-2B6F-4520-B408-1B46037B6E29" xml:space="preserve">
CMyViewAppView::CMyViewAppView()
{
}</codeblock>
<p>The class declaration for this constructor in the class header file
needs to be public to support the construction method required.</p>
</itemgroup>
</li>
<li><p>two-phase constructor, a common implementation is:</p>
<itemgroup>
<codeblock id="GUID-A98C61E4-8C11-4F7D-9782-C440B8FAE374" xml:space="preserve">CMyViewAppView* CMyViewAppView::NewL( const TRect& aRect )
{
CMyViewAppView* self = CMyViewAppView::NewLC( aRect );
CleanupStack::Pop( self );
return self;
}
CMyViewAppView* CMyViewAppView::NewLC( const TRect& aRect )
{
CMyViewAppView* self = new ( ELeave ) CMyViewAppView;
CleanupStack::PushL( self );
self->ConstructL( aRect );
return self;
}
</codeblock>
<p>The declarations for <parmname>CMyViewAppView::NewL()</parmname> and <parmname>CMyViewAppView::NewLC()</parmname> in
the class header file needs to be public to support the construction method
required. </p>
<p>In this approach, <parmname>CMyViewAppView::NewL()</parmname> is called
from the UI controller. It creates a view object by calling <parmname>CMyViewAppView::NewLC()</parmname>. <parmname>CMyViewAppView::NewLC()</parmname> calls new (<parmname>ELeave</parmname>) on the C++ default constructor <parmname>CMyViewAppView</parmname> to
create the object (and leave if it cannot), <xref href="jar:GUID-35228542-8C95-4849-A73F-2B4F082F0C44.jar!/sdk/doc_source/reference/reference-cpp/Kernel_Architecture_2/CCleanupClass.html#%3a%3aCCleanup%3a%3aPushL%28CBase%20%2a%29" format="application/java-archive">pushes</xref> a pointer to the clean-up stack in case the second phase construction method
leaves, and then calls the second phase construction method of the object.
When it returns to <parmname>CMyViewAppView::NewL()</parmname>, the pointer
pushed to the cleanup stack is <xref href="jar:GUID-35228542-8C95-4849-A73F-2B4F082F0C44.jar!/sdk/doc_source/reference/reference-cpp/Kernel_Architecture_2/CCleanupClass.html#%3a%3aCCleanup%3a%3aPop%28%29" format="application/java-archive">removed</xref>.</p>
</itemgroup>
</li>
<li><p>Symbian 2nd phase constructor with code that might leave.
A common implementation is:</p>
<itemgroup>
<codeblock id="GUID-F282B41C-0AF0-4B62-853A-812F34667C78" xml:space="preserve">void CMyViewAppView::ConstructL()
{
// construct r_name32 resources
BaseConstructL(r_name32 );
}
</codeblock>
<p><parmname>CMyViewAppView::ConstructL()</parmname> is a public class
providing the second phase construction that accepts the rectangle the view
is drawn to.</p>
<p><xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-B9CF9FAC-AA26-3787-83E5-71030E221347"><apiname>CAknView::BaseConstructL()</apiname></xref> initializes this view
with standard values. It accepts the symbolic ID name of a resource from the
resource file.</p>
</itemgroup>
</li>
<li><p>a method for returning the UID for the view. A common implementation
is:</p>
<itemgroup>
<codeblock id="GUID-272134EE-D14C-4F97-A46D-0BEC71EF01ED" xml:space="preserve">
TUid CMyViewAppView::Id() const
{
return KViewId;
}
</codeblock>
<p><parmname>CMyViewAppView::Id()</parmname> is the override of <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-82E37EFD-FCCF-3D3E-AA36-7E20A688C980"><apiname>CAknView::ID()</apiname></xref> to
return the UID of the view</p>
<p><parmname>KViewId</parmname> is defined somewhere in a header file,
and is unique to this application</p>
</itemgroup>
</li>
</ul>
<section id="GUID-952D9762-EA63-489D-9698-FC504BD73001"><title>Scalability</title>
<p>If you wish to support <xref href="GUID-B02C762B-C452-4184-ABEA-4753E6CD47D2.dita">scalability</xref> in
your application, then you need to implement <xref href="GUID-1185F595-0488-3E93-8D60-6B3A1A3AC32E.dita#GUID-1185F595-0488-3E93-8D60-6B3A1A3AC32E/GUID-7B8E4FA3-29F4-39DF-BBB3-71E7AB2433C4"><apiname>CEikAppUi::HandleResourceChangeL()</apiname></xref> in
the <xref href="GUID-FD2CDEB8-0784-4BE5-A775-170F57D71BBC.dita"> UI controller</xref>,
and then a <parmname>HandleClientRectChange</parmname> method in the view
controller.</p>
<p>A common implementation is as follows:</p>
<codeblock id="GUID-F5BC393D-EA47-45B2-8892-B71CE934F5B6" xml:space="preserve">
void CMyViewAppView::HandleClientRectChange()
{
if ( iContainer )
{
iContainer->SetRect( ClientRect() );
}
}
</codeblock>
<p>, where</p>
<p><parmname>CMyViewAppView::HandleClientRectChange()</parmname> calls <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita#GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160/GUID-AC806401-86C7-308A-9D18-39085CB8D877"><apiname>CCoeControl::SetRect(aRect)</apiname></xref> to
set the window size according to the requirements of the mobile device.</p>
</section>
<section id="GUID-DC760F92-C154-4DAA-AAD1-A0C02766C6B0"><title>Activating and
deactivating views</title>
<p>In order for a view to be displayed, it needs to be activated by <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-F6105D54-1C2A-36C0-8522-50DAB45FEF67"><apiname>CAknView::DoActivateL()</apiname></xref>.
The override of this method in the view controller must create a <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived
view to display visual content to mobile device users. The <parmname>DoActivateL()</parmname> call
must be prepared to handle the case where it is called while the view is already
active.</p>
<p>If the view is not published for external use, or does not handle message
parameters, a simple check and return if the view is already active is sufficient.</p>
<p>A common implementation is as follows:</p>
<codeblock id="GUID-01819343-975C-499B-9DF6-14DA9BB5912E" xml:space="preserve">
void CMyViewAppView::DoActivateL(
const TVwsViewId& /*aPrevViewId*/,TUid /*aCustomMessageId*/,
const TDesC8& /*aCustomMessage*/)
{
if (!iContainer)
{
iContainer = new (ELeave) CMyViewAppContainer;
iContainer->SetMopParent(this);
iContainer->ConstructL( ClientRect() );
AppUi()->AddToStackL( *this, iContainer );
}
// Message handling would take place here.
}
</codeblock>
<p>, where</p>
<ul>
<li><p><parmname>CMyViewAppView::DoActivateL()</parmname> is the
override for <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-F6105D54-1C2A-36C0-8522-50DAB45FEF67"><apiname>CAknView::DoActivateL()</apiname></xref> for the application.</p>
</li>
<li><p><parmname>if (!iContainer)</parmname> checks to see if the
view already exists.</p></li>
<li><p><parmname>iContainer = new (ELeave) CMyViewAppContainer;</parmname> calls
the first phase constructor of the <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived
class that provides the view.</p></li>
<li><p><xref href="GUID-1E95CF3C-A54A-3073-A7A9-6DC56A6B89E2.dita"><apiname>iContainer->SetMopParent(this);</apiname></xref> sets the
context for the view being created. In this case, it assigns the <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived
view to the view controller.</p></li>
<li><p><parmname>iContainer->ConstructL( ClientRect() )</parmname> calls
the second phase constructor of the <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived
class that provides the view.</p></li>
<li><p><xref href="GUID-18937B25-9AFE-36E2-BA5F-A6716DCD6F39.dita"><apiname>AppUi()->AddToStackL( *this, iContainer );</apiname></xref> adds
the <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived view to the control stack for <xref href="GUID-542550FA-F9F1-46D6-8182-6E7FAA013572.dita">key event handling.</xref></p>
</li>
</ul>
<p>The view architecture supports an automatic recovery mechanism if <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-F6105D54-1C2A-36C0-8522-50DAB45FEF67"><apiname>CAknView::DoActivateL()</apiname></xref> leaves.
The Symbian platform calls <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-7F1B73A0-098D-3FDB-AD2E-D4901700AF02"><apiname>CAknView::DoDeactivate()</apiname></xref> in
the view that has left, reinstates the previous view of the application, and
returns to the view that was just displayed. If the application had no previous
view, it exits. If the application’s previous view was the same as the activating
view (that is, the view is reactivated with a new message), the application
attempts to recover to the default view.</p>
<p>In most cases, this mechanism removes the need to put any recovery mechanism
in the <parmname>DoActivateL()</parmname> methods. The one situation where
you may consider something more complex is when the view can be reactivated
(that is, activated with a new message while already active). In this case,
the view may attempt a more complex strategy to preserve the existing state
if a leave happens during the attempt to handle the new message.</p>
<p>To destroy the <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived control in a view
control, you must override <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-7F1B73A0-098D-3FDB-AD2E-D4901700AF02"><apiname>CAknView::DoDeactivate()</apiname></xref>. It
is called when the application exits, or another view has been activated and
the previous active window needs to be shut down. This order makes view switching
fast. In <parmname>DoDeactivate</parmname> the view is removed from the stack
and therefore the view’s container and its controls are destroyed. This function
must not leave.</p>
<p>A common implementation is as follows:</p>
<codeblock id="GUID-01F7257D-47C2-4A42-9717-97D3913F3AB0" xml:space="preserve">
void CMyViewAppView::DoDeactivate()
{
if ( iContainer )
{
AppUi()->RemoveFromViewStack( *this, iContainer );
}
delete iContainer;
iContainer = NULL;
}</codeblock>
<p>, where</p>
<ul>
<li><p><parmname>CMyViewAppView::DoDeactivateL()</parmname> is the
override for <xref href="GUID-11967EBB-7439-3775-B287-7560ECA0AF1F.dita#GUID-11967EBB-7439-3775-B287-7560ECA0AF1F/GUID-F6E07F12-FAB3-3CB8-AE1F-3F4E7023089A"><apiname>CAknView::DoDeactivateL()</apiname></xref> for the application.</p>
</li>
<li><p><parmname>if (!iContainer)</parmname> checks to see if the
view already exists.</p></li>
<li><p><xref href="GUID-67932EAC-2A97-393F-9719-894D5764B315.dita"><apiname>AppUi()->RemoveFromViewStack( *this, iContainer
);</apiname></xref> removes the <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>-derived view from
the control stack.</p></li>
<li><p><parmname>delete iContainer;</parmname> deletes the <parmname>CCoeControl</parmname>-derived
view.</p></li>
</ul>
</section>
</conbody></concept>