|
|
|
3.2 Construction and life cycle of a view
3.4 DNL - Navigation - View switch
3.9 View Mode - Full Screen Mode
The purpose of this guide is to explain the most common use cases of the classes CQikViewBase and
CQikMultiPageViewBase.
The purpose of this document is also to give concrete examples of how to implement these use cases.
The views of an application are owned by the AppUi object, the CQikAppUi
based application class.
The document is divided into two main parts, one basic part and one advanced part. The basic part describes a very simple use case using the CQikViewBase class. All that is needed to bring up a single page view is described in the QHelloWorld example which is included in the SDK. The advanced part describes additional and optional parts of the view classes; this part is needed when implementing more advanced views. Examples of contents in this part are: How to use the CQikMultiPageViewBase class, how to use the view context bar and how to use categories. The more advanced examples included in the SDK are used in this part.
The class CQikViewBase is a base class for views. All UIQ views should derive from this class or the CQikMultiPageViewBase class. The CQikMultiPageViewBase class inherits from the CQikViewBase class, too. The CQikViewBase class handles much the new functionality found in UIQ 3:
Constructing views, controls and layouts from data in resource files,
Basic focus management,
Hardware-button navigation between controls,
Command handling,
Interface for changing UI configurations in runtime,
Handling the Context bar.
Here are some screen shots from an example application that uses a view with a single page without tabs:
|
The class CQikMultiPageViewBase is a base class for views with multiple pages.
Here are some screen shots from an example application that uses a view with multiple pages and tabs:
|
See other UIQ Developer Library Documents:
UIQ How-To guides Application Title Bar and View Context Bar,
Programmer's Guide to New Features in UIQ 3,
See UIQ API Reference for:
Use one of the following #include directives in your view class:
#include <QikViewBase.h>
or
#include <QikMultiPageViewBase.h>
Use the following LIBRARY directive in the project's mmp-file:
LIBRARY qikcore.lib
To create a view that supports the new framework, you need to inherit from the
CQikViewBase class. Your class declaration looks like this:
class CMyView : public CQikViewBase
The construction of the view object is divided into a couple of stages, to provide efficient and fast startup of the application. In this way, the view is not fully constructed before it is really needed. The constructor of the view can in a simple case look like this:
CMyView::CMyView(CQikAppUi& aAppUi) : CQikViewBase(aAppUi, KNullViewId)
{
}
The second parameter passed to the view base class is an ID of the parent view. This is the logical view that is normally activated when a back command is issued. For the application's default view, however, it is common to pass KNullViewId as the second parameter; this causes the user to exit the application when issuing the back command.
The ConstructL() method of the view class can look like this:
void CMyView::ConstructL()
{
BaseConstructL();
}
When implementing the method ConstructL(), the first thing to do must be to call the method BaseConstructL(), which takes care of basic initiation of member data of the class.
The contents, containers and UI controls of the view are often not created in the method ConstructL(); it is more common and efficient to do this in the method ViewConstructL(). If it is necessary to create a control and add it to the view as early as in ConstructL(), then from within this method call PreemptViewConstructionL(); this causes the view framework to call ViewConstructL(). This should normally be avoided due to the increase of the application's start-up time. The method ConstructL() now looks like this:
void CMyView::ConstructL()
{
BaseConstructL();
}
The factory method NewLC() of the view class is called from the AppUi class:
CMyView* CMyView::NewLC(CQikAppUi& aAppUi)
{
CMyView* self = new(ELeave) CMyView(aAppUi);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
The pure virtual method ViewId() that must be implemented by the view class can look like this:
TVwsViewId CMyView::ViewId()const
{
return TVwsViewId(KUidMyApp, KUidMyView1);
}
This method, which is called by the application framework, returns a unique identifier of the view. This ID consists of two parts: the application UID and the view UID. More information about UID is available in Symbian OS Developer Library, see Further Reference. The view UID only needs to be unique within the application. It is recommended to use a view UID between 0x00000001 and 0x0fffffff; UIDs outside this range are reserved.
The method ConstructL() of the AppUi class inherits from the CQikAppUi class. It is common that this method creates the view by calling the method NewLC() of the view class. The view object is also added to the AppUi object in this method by calling AddViewL():
void CMyAppUi::ConstructL()
{
CQikAppUi::BaseConstructL();
CMyView* myView = CMyView::NewLC(*this);
AddViewL(*myView);
CleanupStack::Pop(myView);
}
AddViewL() registers the view and puts it on the control stack. Ownership of the view
is transferred to CQikAppUi so you do not need to unregister and delete it yourself; this will be done by the destructor of CQikAppUi.
This method fully constructs the view; it is called by the application framework when the view is activated for the first time. All of the elements in the view should be available after a call to this method. The following example shows how to use the View Framework to construct the view by using data from a resource file.
/**
Called the first time a view is activated
*/
void CMyView::ViewConstructL()
{
ViewConstructFromResourceL(R_UI_CONFIGURATIONS);
}
It is not a requirement, but it is recommended to add the controls constructed in C++ code to the view by appending them to the CCoeControlArray. Since CQikViewBase inherits from CQikContainer, the access method to get the CCoeControlArray is called Controls(). This is how it is done:
_LIT(KText,"MyLabel");
CEikLabel* labelCtrl = new (ELeave) CEikLabel;
Controls().AppendLC(labelCtrl); //Do not push on Cleanup Stack before
labelCtrl->ConstructL();
labelCtrl->SetTextL(KText);
CleanupStack::Pop(labelCtrl);
This method can be used to initialize the view and is called every time the view is activated. This method can be used to update the view with current user data which can include adding new view content and commands:
/**
Called every time a view is activated
*/
void CMyView::ViewActivatedL(
const TVwsViewId& /*aPrevViewId*/,
TUid /*aCustomMessageId*/,
const TDesC8& /*aCustomMessage*/)
{
// Update the controls included in the view with new data.
}
This method is called every time a view is deactivated. It can be used to remove view content and commands on view deactivation:
/**
Called every time a view is deactivated
*/
void CMyView::ViewDeactivated()
{
// Removes focus from the focused control.
RequestFocusL(NULL);
}
This section describes how to create view content and command lists on view activation and destroy them on view deactivation. This is done so that UI objects do not need to be held in memory all of the time. Although this can be useful under some circumstances, we do not recommend this when developing applications. This is because:
Deleting UI controls when deactivating a view also deletes the view state. Loosing the view state means that the multi-task navigation model will not work without tweaking code in the application,
Dynamically creating and deleting UI controls has a negative impact on performance,
Dynamically creating and deleting commands also has a negative impact on performance,
Manually switching command lists when UI configurations change and transferring the application state to commands at view activation complicate application code,
Command lists often use small amounts of memory. Destroying command lists and recreating them when needed, as a general rule, is not as beneficial as saving memory in the few areas that consume large amounts of memory.
/**
Set the command_list member of your QIK_VIEW_CONFIGURATION structs to zero to prevent command lists from being auto-loaded by ViewConstructFromResourceL()
*/
RESOURCE QIK_VIEW_CONFIGURATIONS r_ui_configurations
{
configurations =
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStylePortrait;
command_list = 0;
view = r_layout;
}
};
}
/**
Overrides InitializeViewFromResourceL to prevent it from being executed twice at program start up when you also call it from your ViewActivatedL. (It is also called from inside ViewConstructFromResourceL)
*/
void CMyView::InitializeViewFromResourceL(const TQikViewConfigData& aViewConfigData)
{
if( iAppUi.IsViewConstructed(ViewId()) )
CQikViewBase::InitializeViewFromResourceL(aResourceId);
}
In summary, follow these steps to quickly create a view:
Set the logical back view in CQikViewBase's constructor, the parent view parameter,
Implement the pure virtual method CQikViewBase::ViewId(),
Call the method CQikViewBase::BaseContructL() as the first step in the view class method ConstructL(),
Add the view object to the CQikAppUi object by calling the method CQikAppUi::AddViewL(),
Load UI configurations, controls, layouts and commands in your view's ViewConstructL() method,
Use CCoeControlArray for compound controls and views.
For hardware-key navigation to work correctly, you need to make sure you set a control's parent.
The parent is the compound control that owns the control. This is done automatically when you call
SetContainerWindowL(CCoeControl) for a control. Otherwise, use the
CCoeControlArray to add component controls or let the view framework construct
your controls from resource data. This is also done automatically when adding the control to
an existing container control like the view class. A control's parent can also be set with
CCoeControl::SetParent().
You should use layout managers for navigation to function as expected. If you do not use layout managers, navigation could be inconsistent. Without layout managers, navigation is performed by calculating the distance to controls in the desired direction. The distance is currently calculated by comparing the controls' center positions.
Also, make sure that the controls that are not supposed to have focus are set up as
non-focusing and those that are supposed to have focus are set up as focusing.
Use CCoeControl::SetFocusing() to set this. The default setting in
CCoeControl is non-focusing. However, many stock controls, which are able to receive
focus, override this. If a child control wants to have focus, but its compound parent does
not want to have focus, only the child control needs to be a focusing control.
To manually give focus to a control, use the CQikViewBase::RequestFocusL() method.
This will take care of calling PrepareFocusLossL() and PrepareFocusGainL()
throughout the whole focus chain and it will also set/reset focus on the appropriate controls
in focus chains.
If you use CQikViewBase::RequestFocusL() you should not call
PrepareFocusLossL() and PrepareFocusGainL() for the controls
in the control chain. If you want to set focus manually with CCoeControl::SetFocus(),
you need to make sure that PrepareFocusLossL() and PrepareFocusGainL()
are called for all the controls in the focus chain that change focus. For most cases,
RequestFocusL() is sufficient, so avoid using SetFocus() in UIQ 3.
If you want automatic focus transitions when selecting controls, you need to set your view as
the control observer of the control with CCoeControl::SetObserver().
CQikViewBase::HandleControlEventL() will then take care of requesting focus
for the control. If you define your view in a resource file, the view is automatically set
as your control's observer.
If a view has tabs, the left and right navigation keys are used to switch tabs if the key event is not consumed by any control or focus transition.
The base view’s OfferKeyEventL() will forward hardware-key events downward
in the focus chain. This means that parent controls get a chance to consume key events
before they reach the child controls. Make sure to call the view base’s
OfferKeyEventL() if you override this method.
One entry should be highlighted when a view is launched. The method
SetInitialFocusL() is used to set the focus unless there is already a control with focus. The default implementation sets focus on the first focusing control,
which should be correct for most views. However, you can override SetInitialFocusL()
to set the focus on any control.
If you want focus to be reset, for example when you back away from a view, you can call
RequestFocusL(NULL) or SetInitialFocusL().
Going back takes the user to the previous view. This could be the view in another application that
used a DNL to the current view or the view's parent view. All views, except the base/default view,
normally have a parent view. The first view added to the AppUi becomes the default view, but this
can be overridden by calling CCoeAppUi::SetDefaultViewL(). When going back from the application’s
default view, the user ends up in the system default view.
Here is an example of how to handle back behavior:
void CMyView::HandleCommandL(CQikCommand& aCommand)
{
switch(aCommand.Id())
{
case EMyCmdOk: // SaveL will be called asynchronously
RequestFocusL(NULL); //see 2.5.3.3
ActivatePreviousViewL(ESave);
break;
case EQikCmdGoBack: // Cancel – SaveL will NOT be called
RequestFocusL(NULL); //see 2.5.3.3
ActivatePreviousViewL(ECancel);
break;
default:
CQikViewBase::HandleCommandL(aCommand);
break;
}
}
Note: Back links are only remembered between views, not in dialogs.
CQikViewBase implements a virtual SaveL() method which is overridden by views that
want to save data to a disk. SaveL() is called:
At view deactivation, caused by a call to CQikViewBase::ActivatePreviousViewL(),
At view deactivation, caused by a call to CCoeAppUi::ActivateViewL(TVwsViewId&),
At activation of the same view that is already active. This is typically due to a notifier
using CCoeAppUi::ActivateViewL(TVwsViewId&),
When SaveThenDnlToL(TVwsViewId&) is called.
SaveL() is not called when executing CQikViewBase::ActivatePreviousViewL(ECancel).
ActivatePreviousViewL(ECancel) can be called directly, but it is also executed
when CQikViewBase::HandleCommandL(CQikCommand&) handles the EQikCmdGoBack
command.
It is up to each application to display the CQikSaveChangesDialog to warn users about
unsaved data.
When a user returns to an application that was switched away from by using the back key, the view tab and highlight position are shown in their default positions.
Resetting the highlight, the scrollable container and the selected tab on back navigation events is
the responsibility of each application. This behavior can be achieved, for example, by intercepting
EQikCmdGoBack events in HandleCommandL(CQikCommand&) and there removing focus by calling
RequestFocusL(NULL) before passing the event to the base implementation of HandleCommandL().
Using multiple applications to complete a task requires that the state remains unchanged in applications left by switching away, instead of being left by using the back option. The next time the application is activated, the application state, that is, the selected view, the selected tab and the scroll position, are just as they were when the application was deactivated except that menus and active pop-outs are closed. For this navigation approach to work, your application cannot delete view content when the view is deactivated.
If an application is left in a specific state as described above, the state will be lost if another application uses a DNL to switch to the application.
To support back behavior:
"Save" and "Done" exit routes use ActivatePreviousViewL(),
The "Cancel" exit route forwards EQikCmdGoBack to
CQikViewBase::HandleCommandL(),
Call RequestFocusL(NULL) to force a call to SetInitialFocusL()
at the next activation,
The "Cancel" exit route raises a warning dialog if the view contains unsaved data.
The Application Title Bar, as default, shows the application name. When CQikViewBase::SetCategoryModelAsCommandsL() has been called, the Application Title Bar displays the name of the selected category instead of the application name when any other category than "All" is selected.
The Application Title Bar also functions as a command operator when the UI configuration is EQikUiConfigMenu, rather than EQikUiConfigSoftkey. The command types the different drop-down menus accept, as well as some of the other parameters, are configurable by phone manufacturers in QikCtl.rss.
When the Category title contains just one item, pressing the title has the same effect as opening the menu pane, selecting the item and closing the menu pane, but no menu pane will be opened graphically. If the item supplies an icon, that icon will replace the icon for the Category title. A phone manufacturer can turn on/off this behavior system wide from the resource file.
The Application Title Bar resides above the application area. It is not directly reachable for an application developer. The idea is that the Command Processing Framework, together with the current UI configuration, decides which commands are added to the Application Title Bar and thereby are displayed to the user. Any other interaction with the Application Title Bar is performed through the Category Model or the View Base Class. A developer should not, under any circumstances, try to access the Application Title Bar directly.
On a phone using softkey style, the Application Title Bar does not accept input from the user; it simply acts as an information bearer. On a phone with a touchscreen, the Application Title Bar replaces the former menu bar. In the standard configuration, the Application Title Bar has two titles, one text title that opens up the application's menu and one icon title that typically opens up the Category menu.
The text on the title is usually the name of the application. If the Category Model is used, the chosen Category's name will be shown instead of the name of the application after a category has been selected. Selecting the "All" category, determined by handle, not by name, will once again show the name of the application.
If you want to change the currently selected category from code, call CQikViewBase::SelectCategoryL(TInt aHandle). This method is protected and will update the current category and change the title in the Application Title Bar. This is useful when entering a detail view with an item from a given category. The category name should never be set by calling SetAppTitleNameL().
If the name of the application needs to be changed, call SetAppTitleNameL(). If the icon needs to be changed, call SetAppTitleIcon(). Calling them with KNullDesC() and NULL respectively results in resetting them to the original name/icon.
MQikViewContext provided by the CQikViewBase. Tabs are handled directly through the interface MQikTab provided by the CQikViewBase.
The View Context Bar is owned by the view, and not shared between views as is the Application Title Bar. It resides inside the Application Title Bar, to the right of the application icon and below the title. The View Context Bar has no public APIs. Interaction is handled by retrieving an MQikViewContext from the view.
The View Context Bar has two purposes: to display and handle tabs and to add decorations.
The tabs are handled through CQikViewBase or CQikMultiPageViewBase. CQikMultiPageViewBase implements the system with tab pages. As long as your applications use tab pages, you just need your view to inherit from CQikMultiPageViewBase. If you do not use tab pages or want to use the tabs in a customized way, inherit from CQikViewBase. Special implementations can inherit directly from CQikViewBase and make use of the tabs in customized ways.
To add texts and icons to the View Context Bar, call ViewContext() in the view. This gives you an interface, MQikViewContext, to the View Context Bar. With this interface you can add texts, add icons, change the text, remove texts, etc.
It is worth noting that the component IDs you use when adding/deleting range from 1 to 999 and then from 1001 and upwards. The first series makes them left aligned, while the second will make them right aligned. The use of 0 and 1000 is strongly discouraged. Do not expect your code to work if you try to use them. A component with a higher numbered ID is granted placement to the right of a component with a lower numbered ID.
In Pen style, applications have a button bar that contains, as a minimum, a back button. The back command is automatically added to all applications and does not need be included as part of the application specific commands.
Commands of type EQikCommandTypeYes, EQikCommandTypeDone, EQikCommandTypeNo and EQikCommandTypeCancel
are automatically consumed by the button bar as long as there is enough room.
If a command is used in the button bar, it is also consumed, that is, it is not passed on to other command operators.
The following commands will automatically be added as buttons to the button bar if they fit:
EQikCommandTypeDone,
EQikCommandTypeCancel,
EQikCommandTypeYes,
EQikCommandTypeNo,
Any other command type combined with the CPF-flag EQikCpfFlagPreferToBePlacedInButtonbar.
The button bar may also contain a default button, which differs in appearance from the
other buttons, and is mapped to the hardware confirm key. To specify a button as the default
button, use the flag EQikCpfFlagIsDefault.
But it is to be noted that if the view or the control that has focus contains
an EQikCommandTypeItem command which is not flagged with
EQikCpfFlagPreferToBePlacedInButtonbar, the command will be consumed by
the CQikKeyListener and mapped to the hardware confirm key.
The result is that the default button is not invoked on the hardware confirm key.
If all of the buttons have an image, it is only available space that limits the number of buttons in the button bar. An icon button has a minimum size of 1/9 of the button bar width, minus margins.
Buttons with text grow as the text grows, but as a minimum they are 1/3 of the button bar width, minus margins.
If too many commands are received by the button bar, that is, more than three text buttons or more buttons than fit within the available space, some buttons will be discarded and the corresponding commands passed on to other command operators. The commands will be discarded in the following order:
EQikCommandTypeDone and all other commands specifically flagged as being used in the button bar,
EQikCommandTypeNo,
EQikCommandTypeYes,
EQikCommandTypeCancel.
The buttons will be arranged according to type in the following order from left to right:
EQikCommandTypeYes,
EQikCommandTypeDone,
EQikCommandTypeNo,
EQikCommandTypeCancel,
All other command types.
The buttons are left aligned within the button bar.
To improve support for zooming, and to allow controls to have text in different font sizes, depending on, for example, the current screen mode, improved support for zooming has been added to Cone. It is now possible to attach a TZoomFactor to every CCoeControl using this new CCoeControl method:
class CCoeControl
public:
IMPORT_C void SetZoomFactorL(TInt aZoomFactor, TZoomType aZoomType = ERelativeZoom);
The zoom factor assigned to a control applies to that control and to all the children inside. The zoom factor can be absolute, or relative to that of the control's parents. To retrieve a control’s accumulated zoom factor, call the new CCoeControl method:
class CCoeControl
protected:
IMPORT_C TZoomFactor AccumulatedZoom() const;
When the zoom factor of a control is changed, a KEikMessageZoomChange message is sent to the HandleResourceChange() method of all of the affected controls, and there is a subsequent call to the new CCoeControl::RequestRelayout() method of the control whose zoom has changed.
The zoom factor used for an entire application can also be changed by setting the CCoeEnv's zoom factor, which has been moved to CCoeEnv from CEikonEnv.
For more information about how this new API is used to control the size of a control's fonts, see below.
Here is an example from the SDK example QMyDirectory. This code sample shows how to set the zoom factor to the most recently saved value for the specific view:
/**
Inherited from CQikViewBase and called upon by the UI Framework. It creates the view from resource, sets the zoom level and initiates all controls to default values.
*/
void CMyDirectoryDetailView::ViewConstructL()
{
// Loads information about the UI configurations this view supports
// together with definition of each view, its layout and commands.
ViewConstructFromResourceL(R_MYDIRECTORY_DETAILVIEW_UI_CONFIGURATIONS, R_MYDIRECTORY_DETAILVIEW_CONTROLS);
//Get zoom state from the document and set zoom factor
CMyDirectoryDocument* document = static_cast<CMyDirectoryDocument*>(iQikAppUi.Document());
SetZoomFactorL(document->Preferences().DetailViewZoomState());
Here is an example from the SDK example QMyDirectory. This code sample shows how a "change of zoom factor" command can be handled and implemented by the view class:
/**
Handles all commands in the view. Called by the UI framework when a command has been issued. The command IDs are defined in the .hrh file.
*/
void CMyDirectoryDetailView::HandleCommandL(CQikCommand& aCommand)
{
switch(aCommand.Id())
{
...
case EMyDirectoryZoomCmd:
{
// Launch the zoom dialog
CMyDirectoryDocument* document = static_cast<CMyDirectoryDocument*>(iQikAppUi.Document());
const TInt zoomFactor = CQikZoomDialog::RunDlgLD(document->Preferences().DetailViewZoomState());
// If zoom state have changed it will be stored to persistent
// storage and a relay out will be performed
if(document->Preferences().SetDetailViewZoomState(zoomFactor))
{
// Sets the zoom factor for the view
SetZoomFactorL(zoomFactor);
// Make a relay out of the view for the new zoom level
PerformLayout();
}
break;
...
The base view class implements support for full screen in Softkey style.
The view mode is represented by a class called TQikViewMode. To retrieve the current view mode, use CQikViewBase::ViewMode(). This fills TQikViewMode with Boolean values concerning the use of the various pieces of screen furniture that comprise the current view mode. Then, use the exported functions in TQikViewMode to inquire whether a specific piece of screen furniture is being used or not. For example, UsesAppTitleBar() returns ETrue if the Application Title Bar is being used in the current view mode and EFalse if it is not being used.
Updating the view mode is also a two stage process. First, use the exported functions in TQikViewMode to set the Boolean values in the TQikViewMode object. These determine which pieces of screen furniture will be used in the view mode once it is updated. For example, calling SetButtonOrSoftkeyBar(ETrue) adds the button bar or softkey bar to the list of screen furniture in the TQikViewMode object; calling SetButtonOrSoftkeyBar(EFalse) removes the button bar or softkey bar from the list. Once all of the values in the TQikViewMode object have been updated to reflect the new view mode, pass the list, the TQikViewMode object, as an argument to CQikViewBase::SetViewModeL() to finally set the view mode.
NONSHARABLE_CLASS(TQikViewMode)
{
public:
IMPORT_C TQikViewMode();
IMPORT_C void SetAppTitleBar(TBool aUsed);
IMPORT_C TBool UsesAppTitleBar() const;
IMPORT_C void SetButtonOrSoftkeyBar(TBool aUsed);
IMPORT_C TBool UsesButtonOrSoftkeyBar() const;
IMPORT_C void SetStatusBar(TBool aUsed);
IMPORT_C TBool UsesStatusBar() const;
IMPORT_C void SetToolbar(TBool aUsed);
IMPORT_C TBool UsesToolbar() const;
IMPORT_C void SetNormal();
IMPORT_C TBool IsNormal() const;
IMPORT_C void SetFullscreen();
IMPORT_C TBool IsFullscreen() const;
IMPORT_C TBool operator==(const TQikViewMode& aOther) const;
IMPORT_C TBool operator!=(const TQikViewMode& aOther) const;
…
}
class CQikViewBase
{
public: // View mode
IMPORT_C TQikViewMode ViewMode() const;
…
protected:
IMPORT_C void SetViewModeL(const TQikViewMode& aMode);
…
}
The code samples below show how different pieces of screen furniture can be set available or not available in a specific view mode.
The Full Screen view mode is activated by calling SetFullscreen(). This is a composite state meaning that no screen furniture is available; Application Title Bar, Button Bar, Softkey Bar and Status Bar are all not available.
Be aware that when using Full Screen mode, only the command operator taking care of hardware-key events is available. So usually you need another command operator. See the next section which describes the Full Screen Floating Menu which is a command operator that can take care of the remaining commands.
// Controls if the Application Title Bar is to be available in this view mode.
TQikViewMode viewMode = ViewMode();
viewMode.SetAppTitleBar(EFalse);
SetViewModeL(viewMode);
// Controls if the Button or Softkey Bar is to be available in this view mode.
TQikViewMode viewMode = ViewMode();
viewMode.SetButtonOrSoftkeyBar(EFalse);
SetViewModeL(viewMode);
// Controls if the Status Bar is to be available in this view mode.
TQikViewMode viewMode = ViewMode();
viewMode.SetStatusBar(EFalse);
SetViewModeL(viewMode);
// Controls the Full Screen view mode. This method activates this specific mode.
// Full Screen mode is the opposite state to the normal mode.
TQikViewMode viewMode = ViewMode();
viewMode.SetFullscreen();
SetViewModeL(viewMode);
// Controls the Normal view mode. This method activates this specific mode,
// normal mode is the opposite state to the Full Screen mode.
TQikViewMode viewMode = ViewMode();
viewMode.SetNormal();
SetViewModeL(viewMode);
The Full Screen Floating Menu, CQikFullscreenFloatingMenu, can take care of the remaining commands which
cannot be assigned to some of the standard command operators.
This is very useful for applications using Full Screen mode where the standard
command operators such as Application Title Bar and Softkey Bar are unavailable.
The following example shows how this control can be used:
#include <QikFullscreenFloatingMenu.h>
...
CMyView::~CMyView()
{
...
if(iFloatingMenu)
{
// The custom command operator must be removed from the command manager.
CQikCommandManager::Static(*iCoeEnv).RemoveCustomOperator(*this,*iFloatingMenu);
iFloatingMenu = NULL; // No need to delete the member, it is in the CCoeControlArray.
}
}
void CMyView::ViewConstructL()
{
...
iFloatingMenu = CQikFullscreenFloatingMenu::NewL(*this);
// Append the control to the CCoeCOntrolArray
AddControlLC(iFloatingMenu); // iFloatingMenu is pushed on the CleanupStack
// The custom command operator must be added to the command manager.
CQikCommandManager::Static(*iCoeEnv).AddCustomOperatorL(*this,*iFloatingMenu);
CleanupStack::Pop(iFloatingMenu);
// iFloatingMenu, like all other children, will be activated by the system with ActivateL().
...
}
A view uses the QIK_VIEW_CONFIGURATIONS resource structure to define which UI configurations it supports.
If an application view, for example, supports portrait mode only and the phone tries to launch such a view when currently in landscape mode, the phone will switch to portrait mode. An application can only be started in a UI configuration it supports. However, as an aid during development, the emulator can force an application into an unsupported screen mode with the window server's debug keys.
Please refer to other documents for more information regarding UI configurations in UIQ Developer Library.
The example below sets up a view to support two different UIQ configurations.
|
RESOURCE QIK_VIEW_CONFIGURATIONS r_refui_configurations
{
configurations =
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStylePortrait;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikPenStyleTouchPortrait;
}
};
}
The QIK_VIEW_CONFIGURATIONS resource structure is loaded by calling CQikViewBase::ViewConstructFromResourceL() from ViewConstructL().
Apart from defining the supported UI configurations, you can also use QIK_VIEW_CONFIGURATIONS to set up the view to switch layout and command list automatically when changes of UI configuration occur. This is done with the view and command-list members of the QIK_VIEW_CONFIGURATIONS.
Look into other UIQ How-To guides to see code examples using resource driven layout.
Below is an example showing how to construct a page for a view and add it to a view class which inherits from the CQikMultiPageViewBase class. The example code shows the construction of the page and how to add a scrollable container to the page. A layout manager is also created and set for both the page and the scrollable container. Specific layout data is also created and set for the layout manger of the page. The example also shows how to temporarily remove the page by calling ReleasePageL() and then how to bring it back again. Finally, the example shows how to delete the page by calling DeletePage().
Constructing the page:
void CMyView::ViewConstructL()
{
...
_LIT(KMyTabText, "Control");
CQikContainerBase* controlPage = ConstructPageL(EMyAddPage, KMyTabText, NULL, NULL);
CQikRowLayoutManager* rowLayout = CQikRowLayoutManager::NewLC();
controlPage->SetLayoutManagerL(rowLayout);
CleanupStack::Pop(rowLayout);
CQikScrollableContainer* container = new (ELeave) CQikScrollableContainer();
controlPage->AddControlLC(container);
container->ConstructL(ETrue);
container->SetUniqueHandle(EMyAddPageScrollableContainerCtrl);
container->ScrollBarFrame()->SetScrollBarManagement(CEikScrollBar::EVertical, CEikScrollBarFrame::EComponent);
container->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
CQikRowLayoutManager* rowLayout2 = CQikRowLayoutManager::NewLC();
container->SetLayoutManagerL(rowLayout2);
CleanupStack::Pop(rowLayout2);
CleanupStack::Pop(container);
CQikRowLayoutManager::TLayoutData layoutData;
layoutData.iHorizontalAlignment = CQikLayoutManager::EHAlignFill;
layoutData.iVerticalAlignment = CQikLayoutManager::EVAlignFill;
layoutData.iVerticalExcessGrabWeight = 1;
static_cast<CQikRowLayoutManager*>(controlPage->LayoutManager())->SetLayoutDataL(*container, layoutData);
_LIT(KMyAddText, "My add text");
CEikEdwin* ctrl = new (ELeave) CEikEdwin();
container->AddControlLC(ctrl, EMyAddPageEdwin); //Do not push on Cleanup Stack before
ctrl->ConstructL();
ctrl->SetUniqueHandle(EMyAddPageEdwin);
ctrl->SetTextL(&KMyAddText);
ctrl->SetObserver(this);
CleanupStack::Pop(ctrl);
PerformLayout();
...
}
Deleting the page:
DeletePageL(EMyAddPage);
Here are some examples of how to handle tabs.
Add a tab:
_LIT(KMyTabText, "Tab");
AddTabL(EMyAddTab, KMyTabText);
Remove the tab:
RemoveTabL(EMyAddTab);
Dim or make the tab invisible:
MQikTab* tab = Tab(EMyAddTab);
if(tab)
{
if(tab->IsVisible())
{
tab->SetVisible(EFalse);
}
else
{
tab->SetVisible(ETrue);
}
}
if(tab)
{
if(tab->IsDimmed())
{
tab->SetDimmed(EFalse);
}
else
{
tab->SetDimmed(ETrue);
}
}
Categories are used to divide user data into user-definable sets and act as a filter in the application list view. Categories have already been used extensively in UIQ 2. The framework for category support has been left untouched in UIQ 3. However, CQikViewBase has been equipped with some glue to merge category support and the command processing framework.
CQikViewBase::SetCategoryModel(CQikCategoryModel*) is used to associate a category model with a view. The view takes ownership. Ownership can be retracted by calling SetCategoryModel(CQikCategoryModel*) with NULL as the parameter.
CQikViewBase::SetCategoryModelAsCommandsL() will create a command corresponding to each of the categories in the view’s category model. It also makes the view base the observer of the category model; changes in the category model are automatically transferred to the CPF.
Category commands are displayed in a special menu pane in the Application Title Bar.
In Softkey style, categories are cascaded from the More menu. To change the label, grouping or sorting of the More menu's cascaded categories command, use the view’s DynInitOrDeleteCommandL callback:
CQikCommand* CMyView::DynInitOrDeleteCommandL(CQikCommand* aCommand, const CCoeControl& /*aControlAddingCommands*/)
{
switch(aCommand->Id())
{
case EQikSoftkeyCmdSelectCategory:
{
// commands are sorted by type+group+prio
aCommand->SetGroupId(EMyCategoryGroupId);
aCommand->SetPriority(-1);
break;
}
default:
break;
}
return aCommand;
}
If the view class inherits from CQikMultiPageViewBase, the Page() method can be used to get the container of the page to add the controls to.
_LIT(KText,"MyLabel");
CQikContainerBase* container = Page(EMyPage);
if(container != NULL)
{
CEikLabel* labelCtrl = new (ELeave) CEikLabel();
container->Controls().AppendLC(labelCtrl); //Do not push on Cleanup Stack before
labelCtrl->ConstructL();
labelCtrl->SetUniqueHandle(EMyLabel);
labelCtrl->SetObserver(this);
labelCtrl->SetTextL(KText);
CleanupStack::Pop(labelCtrl);
}
This is what you do to add the control to an existing scrollable container:
_LIT(KText,"MyLabel");
CQikScrollableContainer* container =
LocateControlByUniqueHandle<CQikScrollableContainer>(EMyDetailViewScrollableContainerCtrl);
if(container != NULL)
{
CEikLabel* labelCtrl = new (ELeave) CEikLabel();
container->AddControlLC(labelCtrl, EMyLabel); //Do not push on Cleanup Stack before
labelCtrl->ConstructL();
labelCtrl->SetUniqueHandle(EMyLabel);
labelCtrl->SetObserver(this);
labelCtrl->SetTextL(KText);
CleanupStack::Pop(labelCtrl);
}
Here, the control to add to an existing scrollable container is enclosed in a system building block:
CQikScrollableContainer* container =
LocateControlByUniqueHandle<CQikScrollableContainer>(EMyDetailViewScrollableContainerCtrl);
if(container != NULL)
{
CQikBuildingBlock* block = CQikBuildingBlock::CreateSystemBuildingBlockL(EQikCtCaptionedOnelineBuildingBlock);
container->AddControlLC(block, EMyBuildingBlock);
block->ConstructL();
block->SetUniqueHandle(EMyBuildingBlock);
block->SetDividerBelow(ETrue);
_LIT(KCaptionText,"My Caption");
block->SetCaptionL(KCaptionText, EQikItemSlot1); //the slot ID are defined in qikon.hrh
// Create the Label and add it to the System Building Block
_LIT(KMyLabelText, "My label text");
CEikLabel* labelCtrl = new (ELeave) CEikLabel();
block->AddControlLC(labelCtrl, EQikItemSlot2);
labelCtrl->ConstructL();
labelCtrl->SetUniqueHandle(EMyLabel);
labelCtrl->SetObserver(this);
labelCtrl->SetTextL(KMyLabelText);
CleanupStack::Pop(labelCtrl);
CleanupStack::Pop(block);
}
When you add a control that requires four-way navigation, it might be useful to add a Control Stand-in control for the control. The real control is then used in a Container Pop-out which pops out when the user acts on the Control Stand-in control.
CQikScrollableContainer* container = LocateControlByUniqueHandle<CQikScrollableContainer>(EMyDetailViewScrollableContainerCtrl);
if(container != NULL)
{
CQikBuildingBlock* block = CQikBuildingBlock::CreateSystemBuildingBlockL(EQikCtCaptionedOnelineBuildingBlock);
container->AddControlLC(block, EMyBuildingBlock);
block->ConstructL();
block->SetUniqueHandle(EMyBuildingBlock);
block->SetDividerBelow(ETrue);
_LIT(KCaptionText,"My Caption");
block->SetCaptionL(KCaptionText, EQikItemSlot1); //the slot ID are defined in qikon.hrh
// Create the Plain text editor and add it to the System Building Block.
_LIT(KMyText, "My text");
CEikEdwin* edwin = new (ELeave) CEikEdwin();
CleanupStack::PushL(edwin);
CQikControlStandIn* standIn = new(ELeave) CQikControlStandIn(edwin);
CleanupStack::Pop(edwin);
block->AddControlLC(standIn, EQikItemSlot2);
standIn->ConstructL();
standIn->SetUniqueHandle(EMyStandin);
edwin->ConstructL();
edwin->SetTextL(&KMyText);
edwin->SetUniqueHandle(EMyEdwin);
CleanupStack::Pop(standIn);
CleanupStack::Pop(block);
}
|
|
Your view inherits preferably from CQikViewBase or CQikMultiPageViewBase.
If, for some reason, you need to get the MCoeView instance, there are operators defined in CQikViewBase that will retrieve the MCoeView instance for you.
If you want hardware-key navigation, you should not override CQikViewBase::OfferKeyEventL() or else make sure it gets called in your own OfferKeyEventL() implementation.
You do not need to call SetRect() on the view any more. The rect is automatically set to CQikViewBase::ViewRect() right after ViewConstructL() has executed. ViewRect() is also called when a view is activated and, in the currently active application, when the UI configuration is changed. In normal mode, ViewRect() will return ClientRect().
If you override CCoeControl::SizeChanged(), make sure you call CQikViewBase::SizeChanged(), or CQikMultiPageViewBase::SizeChanged(), depending on from which class you inherit. This will cause the layout managers to layout your controls.
CQikViewBase inherits from MCoeControlObserver. If you override MCoeControlObserver::HandleControlEventL(), make sure to call CQikViewBase::HandleControlEventL() from your implementation if you want automatic focus transitions when selecting controls.
This is an explanation of some of the expressions used in this guide.
|