Symbain OS 對話方塊的基類實在Uikon中定義的CEikDialog類,在此基礎上各個介面平台又封裝了各種對話方塊類,例如S60平台的Avkon定義了 CAknDialog類作為S60對話方塊的基類,而UIQ平台仍然使用CEikDialog類作為對話方塊基類,但是封裝了 CQikSaveFileInFolderDlg類等UIQ平台特有的對話方塊類。
Uikon中的CEikDialog實現了三個介面,包括:
McoeControlObserver,對話方塊子控制項的觀察者介面,當子控制項狀態發生變化時該介面的HandleControlEventL()函數被調用。
MeikDialogPageObserver,在多頁對話方塊中,可以通過實現該介面觀察頁面的變化。
McoeControlContext,在多個控制項之間共用圖形內容相關的介面。
CAknDialog類和CEikDialog類最大的不同是前者可以擁有菜單,相應地實現了MEikMenuObserver介面,用於觀察菜單狀態的變化。
CAknDialog是大部分Series60對話方塊的基類。關於對話方塊的使用,大體分為以下步驟:1.定義資源。2.執行對話方塊。3.動態地初始化標準對話方塊。4.退出對話方塊。
1.定義資源
使用DIALOG定義資源,資源指定了對話方塊的布局,在資源中定義對話方塊應該包含的行數、使用的控制項、對話方塊是否為模態以及使用的軟鍵等。資源結構在eikon.然後中定義:
STRUCT DIALOG
{
LONG flags=0;
LTEXT title="";
LLINK pages=0;
LLINK buttons=0;
STRUCT item[];
LLINK form=0;
}
flags:說明了對話方塊的屬性,其中的屬性值可參考,可以多個一起用。
#define EEikDialogFlagWait //等待對話方塊
#define EEikDialogFlagNotifyEsc //退出通知,當使用者選擇某個軟鍵時對話方塊調用OkToExit()函數
#define EEikDialogFlagButtonsBelow
#define EEikDialogFlagButtonsRight
#define EEikDialogFlagNoUserExit //不允許使用者選擇退出對話方塊,即不顯示軟鍵
#define EEikDialogFlagModeless //無強制回應對話方塊,使用該
#define EEikDialogFlagNoTitleBar //無標題列
#define EEikDialogFlagAllKeysToButtons
#define EEikDialogFlagFillScreen
#define EEikDialogFlagNoDrag //不可拖動
#define EEikDialogFlagDensePacking
#define EEikDialogFlagNoBackup
#define EEikDialogFlagFillAppClientRect //對話方塊佔滿整個主面板
#define EEikDialogFlagCbaButtons //使用CBA按鈕
#define EEikDialogFlagNoBorder
#define EEikDialogFlagNoShadow
其中,把標準對話方塊定義為等待對話方塊是一種良好的習慣。應該只在合理的時候(例如在主應用程式視窗中)才把標準對話方塊定義為非等待。
title:對話方塊的標題列文本
pages:多頁對話方塊中,頁面資源的ID
buttons:指定了使用的軟鍵(按鈕資源的 ID),其中的取值可參考
#define R_AVKON_SOFTKEYS_EMPTY
#define R_AVKON_SOFTKEYS_EMPTY_WITH_IDS
#define R_AVKON_SOFTKEYS_OK_EMPTY
#define R_AVKON_SOFTKEYS_SELECT_CANCEL
#define R_AVKON_SOFTKEYS_OK_CANCEL
#define R_AVKON_SOFTKEYS_OK_DETAILS
#define R_AVKON_SOFTKEYS_CALL_CANCEL
#define R_AVKON_SOFTKEYS_OPTIONS_BACK
#define R_AVKON_SOFTKEYS_OPTIONS_DONE
#define R_AVKON_SOFTKEYS_OPTIONS_CANCEL
#define R_AVKON_SOFTKEYS_OPTIONS_EXIT
#define R_AVKON_SOFTKEYS_OK_BACK
#define R_AVKON_SOFTKEYS_CANCEL
#define R_AVKON_SOFTKEYS_BACK
#define R_AVKON_SOFTKEYS_CLOSE
#define R_AVKON_SOFTKEYS_DONE_BACK
#define R_AVKON_SOFTKEYS_DONE_CANCEL
#define R_AVKON_SOFTKEYS_SELECT_BACK
#define R_AVKON_SOFTKEYS_MARK_BACK
#define R_AVKON_SOFTKEYS_UNMARK_BACK
#define R_AVKON_SOFTKEYS_YES_NO
#define R_AVKON_SOFTKEYS_UNLOCK_EMPTY
#define R_AVKON_SOFTKEYS_SAVE_BACK
#define R_AVKON_SOFTKEYS_SHOW_CANCEL
#define R_AVKON_SOFTKEYS_SHOW_EXIT
#define R_AVKON_SOFTKEYS_ANSWER_EXIT
#define R_AVKON_SOFTKEYS_EXIT
#define R_AVKON_SOFTKEYS_READ_EXIT
#define R_AVKON_SOFTKEYS_LISTEN_EXIT
#define R_AVKON_SOFTKEYS_SEARCH_BACK
#define R_AVKON_SOFTKEYS_AGAIN_QUIT
#define R_AVKON_SOFTKEYS_QUIT
#define R_AVKON_SOFTKEYS_INSERT_BACK
items:它定義了對話方塊包含的實際內容。需要為希望包含到對話方塊的每個控制項分別定義一個DLG_LINE,它也在eikon.rh總定義,在每個DLG_LINE中至少應該指定以下欄位:
* id :在應用程式中使用該值引用此對話方塊行,必須在應用程式的.hrh檔案中枚舉它。
* type :此對話方塊行包含的控制項類型(在avkon.hrh或uikon.hrh中定義)。
* control :在此對話方塊中使用的控制項。
此外,還可以選擇在DLG_LINE資源中指定一個itemflags欄位,使用該欄位決定對話方塊行的行為。例如彈出欄位文本控制項可以使用 itemflags說明應該在“選擇”鍵被按下時開啟一個快顯視窗,例如 EEikDlgItemTakesEnterKey|EEikDlgItemOfferAllHotKeys。可以在 uikon.hrh中找到 itemflags的值。最常用的可能當屬EEikDlgItemSeparatorBefore標誌,用於在對話方塊行之前插入一個水平“分隔字元”行。
本節的MySimpleDlg樣本程式中定義了一個顯示一個標籤的簡單的對話方塊,在.rss中定義的資源如下:
RESOURCE DIALOG r_simpledlg_dialog
{
flags=EEikDialogFlagNoDrag|EEikDialogFlagNoTitleBar|EEikDialogFlagFillAppClientRect|
EEikDialogFlagCbaButtons|EEikDialogFlagWait|EEikDialogFlagNotifyEsc;
buttons = R_AVKON_SOFTKEYS_OK_CANCEL;
items =
{
DLG_LINE
{
id = ESimpleDlgCtlLabel; //子控制項的ID(在下面.hrh中定義)
type = EEikCtLabel; //子控制項的類型
control = LABEL //子控制項的資源定義
{
txt = "This is a simple dialog";
};
}
};
}
除此之外還要在.hrh中定義:
enum TSimpleDlgControlIds
{
ESimpleDlgCtlLabel = 1
};
2.執行對話方塊
在c++代碼中一般用CEikDialog::ExecuteLD()函數執行對話方塊,該函數在eikdialg.h中定義:
//eikdiag.h
...
public:
virtual TInt ExecuteLD(TInt aResourceId);
....
函數的參數aResourceId是執行對話方塊的資源ID,如果對話方塊的屬性值包含EEikDialogFlagWait,則表示是一個等待對話方塊,此時ExecuteLD()函數調用會掛起,知道對話方塊關閉後該函數才返回。對於非等待對話方塊,該函數會立即返回。 對話方塊在ExecuteLD()的最後會刪除自己。
本節MySimpleDlg程式中建立了一個CAknDialog對象,並調用它的ExecuteLD()函數,代碼如下
//MySimpleDlgAppUi.cpp
#include
....
void CMySimpleDlgAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
...
case ESimpleDlgCmdDialog: //在下面的.rss和.hrh中定義
{
iEikonEnv->InfoMsg(_L("test"));
CAknDialog* dialog = new(ELeave)CAknDialog; //建立對話方塊對象
if(dialog->ExecuteLD(R_SIMPLEDLG_DIALOG)) //執行對話方塊並判斷傳回值
{
_LIT(KButtonOk,"OK");
iEikonEnv->InfoMsg(KButtonOk());
}
else
{
_LIT(KButtonCancel,"Cancel");
iEikonEnv->InfoMsg(KButtonCancel());
}
break;
}
........
// TODO: Add Your command handling code here
default:
break;
}
}
那麼為什麼在new之後沒有將其壓入清除棧呢?因為ExecuteLD()擁有改對話方塊的所有權,該方法封裝了對其他兩個方法的調用:PrepareLC()和RunLD()。PrepareLC()會把對話方塊的指標放入清除棧,然後完成對話方塊的建立。RunLD()會顯示該對話方塊,然後把它從清除棧中彈出。但如果在調用ExecuteLD()之前需要調用任意可能導致異常退出的代碼,則應該將其放入清除棧,並在調用 ExecuteLD()前把它彈出。但,如果對話方塊為非等待的,則會直接從ExecuteLD()返回而不被刪除
在.rss和.hrh檔案中定義 ESimpleDlgCmdDialog:
//MySimpleDlg.rss
RESOURCE MENU_PANE r_mysimpledlg_menu
{
items =
{
MENU_ITEM { command = ESimpleDlgCmdDialog; txt = qtn_appl_dialog; },
MENU_ITEM { command = ESimpleDlgCmdPrepare; txt = qtn_appl_prepare; },
MENU_ITEM { command = ESimpleDlgCmdPreLayout; txt = qtn_appl_prelayout; },
MENU_ITEM { command = EAknCmdExit; txt = qtn_appl_exit; }
};
}
//MySimpleDlg.hrh
enum TMySimpleDlgCommandIds
{
ESimpleDlgCmdDialog = 1,
ESimpleDlgCmdPrepare,
ESimpleDlgCmdPreLayout
};
3.動態地初始化標準對話方塊
對話方塊的子控制項在定義時被賦予初始值,但在某些情況下應用程式需要在執行對話方塊之前根據情況改變子控制項的值,有兩種方法:
第一種:使用PrepareLC()函數和RunLD()函數
ExecuteLD()函數內部首先調用PrepareLC()函數從資源中載入對話方塊,然後調用RunLD()函數彈出對話方塊,因此可以在這兩個函數之間加入初始化對話方塊的代碼,本節MySimpleDlg樣本程式 MySimpleDlgAppUi.cpp檔案中代碼如下:
#include
void CMySimpleDlgAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
......
case ESimpleDlgCmdPrepare:
{
CAknDialog* dialog = new(ELeave)CAknDialog;
dialog->PrepareLC(R_SIMPLEDLG_DIALOG); //從資源檔中載入對話方塊
CEikLabel* label = static_cast(dialog->Control(ESimpleDlgCtlLabel)); //擷取對話方塊 的子控制項的指標
_LIT(KMyLabel,"Changed after PrepareLC()");
label->SetTextL(KMyLabel()); //修改子控制項的值
dialog->RunLD();
break;
}
.......
// TODO: Add Your command handling code here
default:
break;
}
}
注意:需要在.mmp檔案中加入eikdlg.lib
第二種方法:使用PreLayoutDynInitL()函數或PostLayoutDynInitL()函數
該方法需要自訂對話方塊類,並重載 CEikDialog::PreLayoutDynInit()函數和CEikDialog::PostLayoutDynInitL()函數。這兩個函數都是虛函數,他們會在顯示對話方塊之前被調用。其中對話方塊完成控制項布局會調用PreLayoutDynInitL()函數,因此該函數常用於完成可能會影響對話方塊布局的初始化操作,例如建立新的控制項。對話方塊完成布局之後會調用PostLayoutDynInitL()函數,該函數用於實現不影響對話方塊布局的操作,如為控制項賦值等。
本節的MySimpleDlg樣本程式自訂了一個對話方塊CMySimpleDialog類,它重載了PreLayoutDynInitL()函數,MySimpleDialog.cpp主要代碼如下:
#include // for CEikonEnv
#include // for example label control
#include "MySimpleDlg.hrh"
void CMySimpleDialog::PreLayoutDynInitL()
{
CEikLabel* label = static_cast(Control(ESimpleDlgCtlLabel)); // 通過CEikDialog::Control()函數獲得控制項的指標
_LIT(KMyLabel, "Changed by PreLayoutDynInitL()");
label->SetTextL(KMyLabel());
}
使用此方法可以直接調用ExecuteLD()函數執行對話方塊,MySimpleDlgAppUi.cpp代碼如下:
#include // for CEikLabel
#include
#include //對話方塊標頭檔
#include "MySimpleDialog.h" // for CMySimpleDialog
.....
void CMySimpleDlgAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
......
case ESimpleDlgCmdPreLayout:
{
CAknDialog* dialog = new(ELeave)CMySimpleDialog; //建立自訂對話方塊
dialog->ExecuteLD(R_SIMPLEDLG_DIALOG); //執行對話方塊
break;
}
// TODO: Add Your command handling code here
default:
break;
}
}
注意:Symbian 使用vc6.0開發環境,加入新類以後,最好把.h標頭檔放在inc檔案夾中,.cpp源檔案放在src檔案夾中(保持統一),必須在.mmp檔案中加入 source檔案,如本章的.mmp加入如下代碼:
SOURCE MySimpleDialog.cpp
最後重新編譯。
4.退出對話方塊
當為對話方塊資源指定了 EEikDialogFlagNotifyEsc標記時,對話方塊會在使用者按下軟鍵時調用CEikDialog::OkToExitL()函數。因此可以在自訂的對話方塊中重載CEikDialog::OkToExitL()函數。當該函數返回ETrue時,對話方塊退出,並且由系統銷毀。返回EFalse
時,對話方塊繼續保留。
本節的MySimpleDlg樣本程式中的自訂對話方塊 CMySimpleDialog類,該類重載了此函數,代碼如下:
#include // for CEikonEnv
TBool CMySimpleDialog::OkToExitL(TInt aButtonId)
{
//調用基類的OkTkExitL()函數,完成預設功能,例如快顯功能表等。
TBool ret = CAknDialog::OkToExitL(aButtonId);
CEikonEnv* env = CEikonEnv::Static();
if(aButtonId==EEikBidOk) //使用者選擇了左軟鍵
{
_LIT(KOkToExit, "OK to exit");
env->InfoMsg(KOkToExit());
}
else if(aButtonId==EEikBidCancel) //使用者選擇了右軟鍵
{
_LIT(KCancelToExit, "Cancel to exit");
env->InfoMsg(KCancelToExit());
}
return ret; //返回CAknDialog::OkToExitL()函數的傳回值
}