原帖地址http://blog.csdn.net/sharetop/archive/2008/03/12/2173005.aspx 來自顏承的blog 自己隨手轉一個 方便以後查閱開發symbian的GUI應用是有模板的,用Carbide C++的工程嚮導可以自動產生程式的基本架構。不過可能與安裝的SDK版本有關,我現在只能產生一個AppUi一個Container的常規模板(以前用2nd FP3時還可以產生多個view多個container的視圖模板)。
不管是哪一種模板,它們共同的部分是入口函數、Application和Document。即以下三個檔案是所有工程都具有的:
1)有一個與工程同名的cpp檔案,它只提供了兩個全域函數,是程式執行的入口,負責創造Application。這個檔案我們不用管它。
2)有一個以工程名+Application命名的類,派生於CAknApplication,它負責建立文檔類並提供應用的UID。一般情況下它也不需要我們操心,但是因為它提供了一個函數OpenIniFileLC,如果我們需要在啟動程式時載入ini檔案中的配置,可以重載它。
3)有一個以工程名+Document命名的類,派生於CAknDocument,它負責建立Ui類,同樣一般情況我們不管它,但是它也提供了一個函數OpenFileL,如果需要載入普通檔案,也可以重載它。
下面來看看兩種模板的不同點吧。
一. 基於CCoeControl的常規模式
這種模式的特點是一個AppUi類並且對應一個Container類。
它在上述三個檔案以外,還有下面兩個檔案:
4)有一個以工程名+AppUi命名的類,派生於CAknAppUi,它主要的工作是負責使用者介面(所謂的UI)並且建立Container類,所以它是我們關注的重點之一。
它最重要的成員函數是HandleCommandL,這個函數來自於CEikAppUi類,負責處理各種命名/事件。
有兩個函數DynInitMenuBarL和DynInitMenuPaneL,如果需要動態更改菜單的項目,可以重載它們。
HandleKeyEventL函數則可以在需要自己處理鍵盤事件時重載一下。
此外,這個AppUi還提供一些比較常用的函數,比如:
Document() 可以擷取Document對象指標。
Application() 可以擷取Application對象指標。
StatusPane() 可以擷取狀態列的指標。
Cba() 可以擷取控制欄的指標。
5)有一個以工程名+Container命名的類,派生於CCoeControl,它負責內容的展示,也是我們關注的重點。
如果需要在介面上增加控制項類類的東西,都是在這個類中實現,總的來說,它負責所有與介面展示相關的東西。
它有一個Draw函數,但是如果我們是通過控制項來展示資訊,則這個函數裡的代碼似乎與我們關係不大,除非我們的介面完全是靠畫出來的。
另兩個函數ComponentControl和CountComponentControls分別擷取控制項與擷取控制項個數,在依賴於控制項展示的GUI應用中則更為重要。
因為它實現了介面MCoeControlObserver,所以函數HandleControlEventL也需要實現一下。
利用它的成員iCoeEnv可以取到AppUi類的指標,不過需要強制轉型一下,如:STATIC_CAST(CiMusicAppUi*,iCoeEnv->AppUi())->...
二. 基於CAknView的MVC模式
這種模式的特點是在AppUi類與Container類之間增加一個AppView的類,即一個AppUi對象,N個AppView和N個Container。
除了公用的三個檔案以外,它包括的檔案有:
4) 有一個以工程名+AppUi命名的類,派生於CAknViewAppUi類,其實也是間接派生於CAknAppUi類,它的工作職責與常規模式中的AppUi類也基本相同。
唯一的區別在於它不是直接建立Container類,而是建立AppView類,並且是建立多個AppView類。同時它還需要負責將建立的view加入視圖棧裡AddViewL。
CiMusicViewMusic* view1 = new (ELeave) CiMusicViewMusic;
CleanupStack::PushL( view1 );
view1->ConstructL();
AddViewL( view1 ); // transfer ownership to CAknViewAppUi
CleanupStack::Pop(); // view1
CiMusicViewFavt* view2 = new (ELeave) CiMusicViewFavt;
CleanupStack::PushL( view2 );
view2->ConstructL();
AddViewL( view2 ); // transfer ownership to CAknViewAppUi
CleanupStack::Pop(); // view2
CiMusicViewWeb* view3 = new (ELeave) CiMusicViewWeb;
CleanupStack::PushL( view3 );
view3->ConstructL();
AddViewL( view3 ); // transfer ownership to CAknViewAppUi
CleanupStack::Pop(); // view3
this->ActivateLocalViewL(KViewMusicId);
5)有多個以工程名+View命名的類,派生於CAknView類。它負責分擔AppUi部分事件的處理,所以,它也有HandleCommandL函數。
此外,它的DoActivateL和DoDeactivate兩個函數在當前視圖啟用或失活時被調用,需要重載一下。
在啟用時,需要建立視圖對應的Container類,並且調用Container的SetMopParent為自己,還要在上層的AppUi中將這個Container加入棧中。一般代碼如下: iContainer = new (ELeave) CiMusicContainerFavt;
iContainer->SetMopParent(this);
iContainer->ConstructL( AppUi()->ApplicationRect() );
iContainer->listType=type;
AppUi()->AddToStackL( *this, iContainer );
注意,它的AppUi()可以得到它的上層的AppUi對象指標。
失活時則正好相反,需要if ( iContainer )
{
AppUi()->RemoveFromViewStack( *this, iContainer );
}
delete iContainer;
iContainer = NULL;
6)有多個以工程名+Container命名的類,派生於CCoeControl並實現介面MCoeControlObserver,所以它的行為與常規模式中的Container類似。
這種模式可以有效地組織應用程式,根據應用的多個功能介面切割成數個模組(視圖)。由多個AppView來分擔AppUi中的事件處理,負責自己這個視圖下的具體行為與顯示。
各個視圖之間的切換也很簡單:
STATIC_CAST(CiMusicAppUi*,iCoeEnv->AppUi())->ActivateLocalViewL(KViewMusicId);
[補充]
三 比較兩種模式
有些教材還提出過對話方塊模式,但是我覺得那似乎不太實用,也沒注意過它的結構組成。
對比上述兩種架構模板,很顯然,第二種基於視圖的模板應該更有實用性一點,除非程式實在簡單。
不過,這裡的“視圖”很容易讓人產生誤解。一般我們說MVC的時候,模型-視圖-控制器,但是這裡的AppView其實對應的控制器,而Container對應的則是視圖。
所以在新的SDK裡,第一種模板中由嚮導產生的工程中源於CCoeControl的類名改成了AppView,對應繼承於CAknAppUi控制器的類名叫AppUi。因為我沒有看到多視圖的工程產生的程式碼,如果這樣的話,估計也應該對應的改一下吧。
[補充@2008-03-20]
在多視圖構架中要注意幾個地方:
1、在AppUi的解構函式中千萬不要去刪除AppView的執行個體,否則會有錯誤。
2、在AppView的解構函式中調用一下DoDeactivate(),因為只有在這個函數才會去清掉Container。