Wiley.Developing.Software.for.Symbian.OS.2nd.Edition.Dec.2007 (779887), страница 71
Текст из файла (страница 71)
For applicationsthat have no persistent data, and therefore are not file-based, the documentclass simply implements the CreateAppUiL() function to return theapplication’s UI object, as the following code from SimpleEx for UIQ3 shows:class CSimpleExDocument : public CQikDocument{public:CSimpleExDocument(CEikApplication& aApp) : CQikDocument(aApp) { };private:CEikAppUi* CreateAppUiL();};CEikAppUi* CSimpleExDocument::CreateAppUiL(){// Create the application user interface, and return a pointer to it;// the framework takes ownership of this objectreturn new (ELeave) CSimpleExAppUi;}An application’s data is said to be persistent if it remains in existencebeyond the time when the application is closed down. This implies thatthe data is stored externally to the application, and it would normally bestored in a file.An application that has data it wants to save when the applicationcloses, and reload when the application starts up again, can provideimplementations for the document class’s StoreL() and RestoreL()functions, which are prototyped as:void StoreL(CStreamStore& aStore, CStreamDictionary& aStreamDic) const;and:APPLICATION CLASSES371void RestoreL(const CStreamStore& aStore, const CStreamDictionary&aStreamDic);The application framework calls these functions as necessary to create,save, and reload the file.To use these functions, you need to understand the concepts of streamsand stores.
A stream is a sequence of data items that supplies an externalrepresentation of a class instance. The external form is one that is freeof any peculiarities of the internal storage format, such as byte order ordata alignment. Symbian OS supports the conversion of data betweenthe two formats by means of internalization (>>) and externalization (<<)operators, and a class’s implementation of the InternalizeL() andExternalizeL() functions. You should refer to the SDK documentationfor further information.A Symbian OS store is a collection of streams, and is normally usedto implement persistent data.
Such data is usually, but not always,stored in a file, with the aid of either the CDirectFileStore orCPermanentFileStore classes. You can use the CBufStore classto store data in a memory buffer, but such storage will, of course, notbe persistent. Other classes of interest are CSecureStore, to storeencrypted data, and CEmbeddedStore, which, as its name suggests,allows you to create more complex stores, where one store may beembedded within another.
All these store classes inherit from an abstractCStreamStore base class (which is used as the type of the first parameterfor the StoreL() and RestoreL() functions). Each store containsa root stream, which is the first stream to be read on opening thestore. The root stream contains an index (which is an instance of theCStreamDictionary class) that provides access to the other streamswithin the store. Refer to the SDK documentation for examples, andfurther information about creating and using stores.The persistence mechanism described above results in the wholefile being read on application startup and written when the applicationcloses.
In consequence, it is not suited to applications that display andmanipulate one or more records from a (potentially large) database file.Such an application should not implement the document’s StoreL()and RestoreL() functions, but should provide its own mechanisms forupdating the database file as and when necessary.Since most S60 applications fall into this category, the default behaviorof the S60 document class is to disable the automatic saving and loadingof persistent data. If necessary, you can re-enable it by supplying thefollowing implementation of your document’s OpenFileL() function:CFileStore* CMyDocument::OpenFileL(TBool aDoOpen, const TDesC& aFilename,RFs& aFs){372GUI APPLICATION PROGRAMMINGreturn CEikDocument::OpenFileL(aDoOpen, aFilename, aFs);}The application UI classYour application’s UI class is responsible, upon construction, for creatingthe application’s default view.
In S60, for basic one-view applications(i.e., the view is a simple control), the UI class contains the commandhandler that handles all the commands the users initiate via the GUI. Ifyou are using multiple views, however, this command handler would bein the view class. In UIQ, this command handler is always in the viewclass.The declaration for the UIQ version of SimpleEx’s application UIclass is as follows:class CSimpleExAppUi : public{public:void ConstructL();private:CSimpleExAppView* iAppView;};CQikAppUiBelow is the implementation of the ConstructL() function in theUI class:void CSimpleExAppUi::ConstructL(){BaseConstructL();iAppView = CSimpleExAppView::NewLC(*this);AddViewL(*iAppView);CleanupStack::Pop(iAppView);}The application framework calls the document’s CreateAppUiL()function, to create the application’s instance of its application UI class,and then invokes the application UI’s ConstructL() function.
Thisfunction must contain all the logic to initialize your GUI application,including the creation of the application view. A pointer to this viewshould be assigned to iAppView for future reference; however, note thatthe framework actually owns the view instance, so an explicit delete neednot be done in your application.The S60 UI class is similar to UIQ in that it also creates the view inits ConstructL(). S60, however, also implements the HandleCommandL() function in the UI class, in the case of single control viewAPPLICATION CLASSES373(like in the S60 SimpleEx example), to process the application’s command events.
Below is SimpleEx’s S60 implementation of the UI classincluding the command handler:void CSimpleExAppUi::ConstructL(){BaseConstructL(CAknEnableSkin); // S60 requires CAknEnableSkin argumentiAppView = CSimpleExAppView::NewL(ClientRect());}CSimpleExAppUi::~CSimpleExAppUi(){delete iAppView;}void CSimpleExAppUi::HandleCommandL(TInt aCommand){switch(aCommand){case EAknSoftkeyExit:case CEikCmdExit:Exit();break;case ESimpleExCommand:{_LIT(KMessage,"Start Selected!");iEikonEnv->AlertWin(KMessage);break;}}}The events handled by HandleCommandL() are identified by 32-bitintegers that are defined (typically in an enum) in an include file, whichis included in both your resource file and your source code.
Dependingon the platform, these events may originate from a variety of sources,including menu bars, keyboard hotkey combinations, tool bars, andcommand button arrays.The S60 UI class should also override the HandleResourceChangeL() function. This will ensure that your application will runwhen you change the orientation of the screen from portrait to landscapeand vice versa (for example, the Nokia E70 will automatically switch tolandscape mode when you unfold its keyboard). You can also cause anorientation switch to occur on the S60 emulator by pressing the buttonat the top left of the emulator screen.
For the examples in this book, thebelow function will suffice to ensure it works during orientation switches:void CSimpleExAppUi::HandleResourceChangeL( TInt aType ){CAknAppUi::HandleResourceChangeL( aType );if ( aType==KEikDynamicLayoutVariantSwitch )374GUI APPLICATION PROGRAMMING{iAppView->SetRect( ClientRect() );}}The application view classThe application view class handles the presentation of your applicationon the smartphone’s screen, as well as allowing the user to interactwith your program. In Symbian OS all objects drawn to a screen arecontrols – including the application view, which is a custom control.Let’s look at the SimpleEx application’s view implementation andbriefly discuss its key points starting with UIQ.The declaration for SimpleEx’s application view class for UIQ is asfollows:class CSimpleExAppView : public CQikViewBase{public:static CSimpleExAppView* NewL(CQikAppUi& aAppUi);static CSimpleExAppView* CSimpleExAppView::NewLC(CQikAppUi& aAppUi);// from CQikViewBaseTVwsViewId ViewId()const;void ViewConstructL();void HandleCommandL(CQikCommand& aCommand);private:void Draw(const TRect&) const;CSimpleExAppView(CQikAppUi& aAppUi);void ConstructL();};The NewL() and NewLC() functions are implemented as follows:CSimpleExAppView* CSimpleExAppView::NewL(CQikAppUi& aAppUi){CSimpleExAppView* self = CSimpleExAppView::NewLC(aAppUi);CleanupStack::Pop(self);return self;}CSimpleExAppView* CSimpleExAppView::NewLC(CQikAppUi& aAppUi){CSimpleExAppView* self = new (ELeave) CSimpleExAppView(aAppUi);CleanupStack::PushL(self);self->ConstructL();return self;}The view’s static NewL() factory method both instantiates the application view class and calls its ConstructL() secondary constructor.The application UI calls this NewL() function to create the view class,passing a pointer to itself as an argument.APPLICATION CLASSES375The constructor and the secondary constructor, ConstructL(), areshown below:CSimpleExAppView::CSimpleExAppView(CQikAppUi& aAppUi): CQikViewBase(aAppUi, KNullViewId){}void CSimpleExAppView::ConstructL(){BaseConstructL();}In the constructor we just pass a pointer to the UI class and a NULLview ID (KNullViewId), which is all that is needed for the example.
InConstructL() you must call the BaseConstructL() method.Below is the ViewConstructL() method:void CSimpleExAppView::ViewConstructL(){// Loads information about the UI configurations this view supports// together with definition of each view.ViewConstructFromResourceL(R_SIMPLEEX_CONFIGURATIONS);}Here we load the QIK VIEW CONFIGURATIONS resource from theresource file. This is applicable for UIQ only. This resource definesthe various UIQ display and interaction modes that the application cansupport. Section 12.4.2 will provide more detail on this.ViewId() returns a unique identifier for the view, which consists ofa combination of the application UID and the view UID:TVwsViewId CSimpleExAppView::ViewId()const{return TVwsViewId(KUidSimpleExApp, KUidSimpleExView);}The view UID must be unique for all views within an application.Since we only have one view, define KUidSimpleExView as 1.Although not required, as mentioned, we overrode the Draw() methodto draw text directly on the screen:void CSimpleExAppView::Draw(const TRect&) const{CWindowGc& gc = SystemGc();gc.Clear();const CFont* font = iEikonEnv->TitleFont();gc.UseFont(font);TRect drawRect = Rect();TIntbaselineOffset=(drawRect.Height() - font->HeightInPixels())/2;_LIT(KScreenText,"Simple Example");gc.DrawText(KScreenText,376GUI APPLICATION PROGRAMMINGdrawRect,baselineOffset,CGraphicsContext::ECenter, 0);gc.DiscardFont();}Although I do not discuss the details of how drawing is done, bylooking at the SimpleEx view’s Draw() function, you should be able tosee that it is simply clearing the screen and drawing the text ‘SimpleEx’.In UIQ, the command handler is in the view class as opposed to the UIclass we implemented for the S60 example.