symbian 界面

Symbian中的應用程序通常分爲兩個部分,engine和UI,如此的劃分增加了可維護性和靈活性,engine就好象是程序的核心,它主要處理運算和數據,而UI(應該是User Interface)主要處理數據的顯示和所有行爲(操作行爲應該是)。

engine不談,它是程序起作用的靈魂,這個是因程序而異的,我們來看應用程序外觀,它可以分爲三種體系結構:
一、傳統的symbianOS控制體系結構
二、基於對話框的體系結構
三、視圖體系結構

看看好象跟MFC搞的似的,也有個View和Dialog,不過也是Symbian就是用C++寫的,面向對象特性非常好。

運用什麼樣的界面取決於程序和界面佈局的需要,就不多說了。只是不管你使用哪種,都是從一個基類繼承而來的,就好象是CView一樣。

[傳統SymbianOS應用程序的體系結構]
傳 統意義上,SymbianOS應用程序是在CCoeControl類的基礎上派生出我們自己的view controls,這些都存放在應用程序的control stack中,也就是我們應用程序的視圖。這些controls會根據應用程序的需要來創建釋放或顯示隱藏,以產生相應的操作。

[Dialog體系結構]
如果主體應用是對話框,那我們更應該使用這樣的體系結構,使用dialogs的好處是我們光可以靠改變resource文件來修改內容和佈局,而不需要重新編譯那c++代碼。

注意,如果不小心規劃,那嵌套的對話框將耗去大量的堆棧空間。

另外,如果dialog體系結構被用於主要視圖,那建議講其設計爲非模態對話框。(它不壟斷用戶的輸入,用戶打開非模態對話框後,仍然可以與其它界面進行交互。)如果你要生成一個主界面對話框,要求是滿屏,並提供多頁設計,那應該包括如下features:
RESOURCE DIALOG r_dlgapp_main_dialog
{
flags = EEikDialogFlagNoDrag | EEikDialogFlagNoTitleBar |
EEikDialogFlagFillAppClientRect |
EEikDialogFlagCbaButtons | EEikDialogFlagModelss;

buttons = r_dlgapp_softkeys_options_home;
pages = r_dlgapp_main_pages;
}

如果要創建一個對話框應該如下:
void CDlgappAppUi::ConstructL()
{
BaseConstructL();
iAppView = new(ELeave) CDlgAppMainView;
iAppView->ExecuteLD(R_DLGAPP_MAIN_DIALOG);
AddToStackL(iAppView);
}

ExecuteLD()在調用後立即返回,並且對話框必須要加到control stack中——使用AddToStack函數,因爲非模態對話框不會自己處理這些。

[View體系結構]
使用view的應用程序每次只能有一個活動的view,當另一個view要激活時,當前的view就要被釋放。當一個view被釋放後,所以的菜單,對話框以及包含的應用都將被關閉。
每個view都被當作一個應用UI對待,它必須提供一個Id()函數以便爲系統所標識,它也要重載DoActivateL(),DoDeactivate (),HandleForegroundEventL(),HandlCommandL()和HandleStatusPaneSizeChange() 函數以處理各種事件。

下面一個個的看
DoActivateL()
當客戶端要求你的view激活時,它就要被調用。 client可能發送消息參數給你的view,如果你的view已經是激活了,那只有當client明確要求再次激活時才被調用,所以你的 DoActivateL()實現得應付這種情況,ie已經激活了view。如果你不打算顯示view或者你的view不想處理任何消息,那一個簡單的檢查和return即可。

DoDeactive()
這個函數當你的view被註銷時調用,view被註銷時通常有兩種情況:一是你的應用程序要退出了,二是相同程序裏另一個view要被激活。這個函數很重要,咱們可不能忘記了:)

HandleForegroundEventL()
這個函數主要是在你的view被激活時調用(即在DoActivateL()和DoDeactivate()之間被調用)。當你的view在前臺時,它將是 HanleForegroundEvent(ETrue),當你的view移出前臺時,它將爲HandleForegroundEvent (EFalse),只有當前臺狀態確實改變時這個函數纔會被調用。

HandleCommandL()
當view菜單產生一個命令後本函數將被調用。

HandleStatusPaneSizeChange()
當client的尺寸由於status pane而改變時,本函數被調用了就。

下面是一個view在接受事件的典型調用順序
1.DoActivateL()
2.HandleForegroundEventL(ETrue)
3.HandleForegroundEventL(EFalse)
4.DoDeactivate()

其中一對HandleForegrounEventL在view被激活的過程中會發生多次調用。

而DoActivateL()在DoDeactivate()被調用前可能會被多次調用。

View Resources
如果你要使用view來顯示pages,那唯一的途徑是創建出自己的AVKON_VIEW資源,裏面有自己的CBA和菜單,把這個資源的id傳遞給view的BaseContructL()函數即可。

RESOURCE AVKON_VIEW r_viewapp_view1
{
hotkeys = r_viewapp_hotkeys;
menubar = r_viewapp_view1_menubar;
cba = R_AVKON_SOFTKEYS_OPTIONS_BACK;
}
注意如果沒有給定的menubar資源,那就會使用確省的系統menubar

Construction
下面這個例程是用的AppUI object's ConstructL來構造出view的,使用了AddView來登記,最後把第一個創建的view做爲缺省的view了:

void CMyViewArchAppUi::ConstructL()
{
BaseConstructL();

CMyViewArchAppView1* view1 = new(ELeave) CMyViewArchAppView1;
CleanupStack::PushL(view1);
view1->ConstructL();
AddViewL(view1); //Add view1 to CAknAppUi; transfers ownership
CleanupStack::Pop();

CMyViewArchAppView2* view2 = new(ELeave) CMyViewArchAppView2;
AddViewL(View2); // transfer ownership to CAknAppUi
CleanupStack::Pop();

CMyViewArchAppView3* view3 = new(ELeave) CMyViewArchAppView3;
AddViewL(View2); // transfer ownership to CAknAppUi
CleanupStack::Pop();

SetDefaultViewL(*view1);

.......(more code)

要讓view發揮作用(注意,一個view自身是沒有繪圖能力的),它必須擁有得到一個從CCoeControl派生的containers,譬如
class CMyViewArchAppView1Container: public CCoeControl, MCoeControlObserver

下面這個例程將展現編程者自己的CAknView派生類
class CMyViewArchAppView1: public CAknVIew
{
.....
private:
CMyViewArchAppView1Container* iVIew;
}

大家可以看出App裏產生了View,View類中有我們必須的Container.

當前激活的view在HandleCommandL()處理命令,這些是自定義功能鍵和菜單所生成的命令。

void CMyAppView1::HandleCommandL(TInt aCommand)
{
switch (aCommand)
{
case EMyAppCmdSwitchView:
AppUi()->ActivateLocalViewL(KView2Id);
break;
case EAknSoftKeyOk:
{
......
break;
}
case EAknSoftKeyBack:
{
((MEikCommandObserver*)AppUi())->ProcessCommandL(EEikCmdExit);
break;
}
default:
AppUi()->HandleCommandL(aCommand);
break;
}
}

Local View Switching
如果你要切換view,你得提供view的UID
//Now switch the view to view2
iAvkonViewAppUi->ActivateLocalViewL(TUid::Uid(2));
事實上,每個view都有自己的菜單系統,如果你要使用它,應當在AVKON_VIEW資源結構中設置,前面已經講過了。

而且不管怎麼說,如果要使用系統菜單,它的內容在切換之前是一定要更新一次的。
//Switch to a new menu system for the new view
iEikonEnv->AppUiFactory()->MenuBar()->SetMenuTitleResourceId(R_MY_VIEW_ARCH_APP_VIEW2_MENU);
//Now swtich the view to view2

如果要進行遠程的視圖切換,那就要調用CCoeAppUi::ActivateViewL()函數,並傳遞了一個包含目標應用程序UID和目標視圖UID的TVwsViewId

Leave recovery
Avkon 視圖體系結構在DoActivateL()退出時會有個自動的回覆機制。系統會調用DoDeactivate()在當前view離去時,回覆前一個 view,並把用戶帶到之前他們所在的地方。如果程序並沒有前一個view的存在,那它就會退出,如果程序前個view就是當前的view(也就是說他們是重激活的),則應用程序會試圖恢復缺省的view.

說了這麼多,那我們在什麼情況下采用合適的體系結構那?下面的內容將會有所幫助。

使用傳統的SymbianOS體系結構,你要花費大量的時間研究代碼是怎麼工作的,但大部分交互和錯誤處理的引擎代碼都是現成,可以降低你的開發難度。

Do you have an acyclic graph shaped navigation structure?
如果你視圖程序中的navigation能夠as an acyclic gragh,那最好使用dialog體系結構。

Are all the application screens dialog like?
如果你的應用程序想使用對話框,那建議你使用dialog體系結構,注意如果要有一個選擇列表,那最好寫成包含在dialog中的選擇列表。

Does the application have multiple views or modes, which deal with different sorts of data at the top level?
如果是這樣,那最好使用傳統或view體系結構。

Do external applications need to switch to different views of your application?
如果是採用view體系結構寫的程序,那它一定支持多個不同的view,而且是外部程序能訪問的。如果你從頭開始寫一個應用程序,那建議你使用view體系結構,

否則給我看看有沒有現成的代碼可利用,不要一味的傻寫呵呵。注意,如果一個外部程序使用的顯示頁面是你的程序所提供的,那你應該在DLL中處理這個顯示頁,這個DLL應該是外部程序所能訪問的。

Can all of the applications views be exited without loosing user data?
使用view體系的程序必須有能力處理因外部程序而引起的views的釋放。如果程序不能自動的釋放這些view,那就要考慮其他兩種體系了,要麼使用view體系as a message passing system,要麼讓app UI在傳統體系中管理view。

Do external applications need complex interactions with the data in your app?
如果外部程序和你的程序有大量的數據交互,那你最好選擇client/server系統。它將減小view的使用量。大量現有的複雜應用,如短信,web以及通訊錄都使用這樣的機制,這是個很好的構想,總比要重寫他們要好:)

Is there only a single complex main view in the app?
如果是這種情況,那還是使用傳統的體系。

<一些例子>
這裏給出一些假象例子的解決方案。

App launcher
這種程序可以單獨運行並且能切換到其他程序,它只有一個view ,並且不接受外部程序的訪問,如果這樣會中斷它。這樣的程序不需要消息的傳遞或外部程序需要的views.

Fast swap window
一個在運行時刻的彈出窗口,這是一個睡眠的彈出對話框其實,它沒有狀態。

Email app
電子郵件程序可以讀或寫電子郵件。這個程序有外部使用views,內部可切換的views,並能做中斷操作。Notifier信息能告知程序顯示一個新的信息給用戶,所以該程序要有處理此請求的機制,即使在做其他事情時。編輯框可以做爲其他程序的view顯示,使用DLL形式,我們就可以做到外部程序的調用自如。SymbianOS的messaging程序就是一個client/server機制可以在其他程序中被調用。當然要實現內嵌在外部程序中有許多工作要做的。當你在寫郵件時,很可能又收到新郵件的同志,這個時候新郵件是做爲一個嵌套的對話框似的組件顯示在裏面的,注意,做這個工作時要特別依賴 inter-application interaction model。

Contacts app
通訊錄程序允許進行通訊錄的顯示、編輯和選擇。選擇後的結果可以做爲其他程序所用。注意它不能因外部view的切換而中斷。

通過一個外部程序可訪問的dll,通訊錄就可以被外部程序所訪問。程序本身並不需要views,所以最好使用傳統的體系結構編寫,而用dialog應付所有的編輯窗口。

web browser
web瀏覽器可以做爲單一的web上網工具,也可以內嵌在其他的文檔中。web瀏覽器可以通過外部程序可以訪問的dll來提供一個UI control,但並不給外部提供可用的全屏應用。它必須能夠應付外界的訪問,譬如說應付在點擊mail連接後撰寫電子郵件的過程。
主體程序主要是用傳統的體系結構,也可以採用view體系來應付訪問頁面的需求。

Settings
我們要關心的是全局設置和特定應用程序的設置。他們不是一回事情。經管他們可能共享一個庫,實際上他們互不相干。

設置程序並不需要爲外部的訪問做什麼處理提供什麼界面,因此他的編寫很簡單,用傳統的或者基於dialog的體系都可以。而局部設置要注意必須小心對待外部可能出現的中斷,並且他有可能做爲一個模態dialog而處理。

Telephony app
電話號碼簿程序並不提供外部view,但他必須要處理外部資源的請求。有時候直接用傳統的體系去寫即可,大部分的外部交互可以通過ETEL Server.

[應用程序的啓動]
從CEikApplication派生的類CAknApplication,他有幾個必須重載的函數:
PreDocContructL()
OpenIniFileLC(RFs& aFs)

PreDocConstructL,主要是處理已經構造好的應用程序實體是否正確準備好了。如果已經準備好了,那應用程序可以切換到實體上。注意,這個函數只檢查非內嵌程序。

通常,ini文件並不被series60所支持,如果要處理,那就要強制性的調用CEikApplication::OpenIniFileC

[BASE CLASSES]

CAknDocument
這個類是做爲應用程序文檔的基類準備的。用這個函數訪問文檔可以不用初始化。這個是訪問Avkon應用程序的比較好的途徑。

CAknAppUi
所有的Avkon應用程序必須從這個類派生。
這個類支持下面幾個特定應用函數:
KeySound support
Accessories for CBA and StatusPane
TextResolver-Avkon-specific error reporting from CAknAppUI::HandleError()
Avkon view architectrue integration
Control dumping - Debug feature

CAknViewAppUi
所有的視圖結構必須由此派生

發佈了1 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章