此文摘译自SDK 3rd MR中:/9.1/S60_3rd_MR/S60Doc/s60_platform_avkon_ui_resources_dialogs_v1_1_en.pdf
对话框分为single-page对话框和multi-page对话框。这里将分别介绍之。
下图显示了对话框的terminology和philosophy:
Multi-page tabs只在多页对话框中存在,它们用来访问独立的对话框页。多页对话框与视图切换架构的区别是,视图中视图切换时视图状态和数据需要被保存,每个视图都可以从外界激活;而多页对话框在关闭对话框事,数据才被保存,并且不能从外界进入对话框的任意Tab页。大多数Avkon框架是基于对话框框架的.
实现对话框
S60环境中实现对话框有两个阶段:
①在.rss文件中定义对话框资源
②定义CAknDialog的子类,并实行其中部分虚方法
对话框资源定义
对话框资源定义使用DIALOG结构,它在eikon.rh中定义:
STRUCT DIALOG
{
LONG flags=0;
LTEXT title="";
LLINK pages=0;
LLINK buttons=0;
STRUCT items[];
LLINK form=0;
}
Dialog flags
DIALOG中的flags指定了对话框类型。flags的值在eikon.hrh和avkon.hrh中定义。下面是具体值和含义:
因为兼容性的原因,在S60平台中仍保留着一些flags,但在S60平台中它们并没有使用,下面列举之:
Items — dialog lines
对话框行结构在eikon.rh中定义:
STRUCT DLG_LINE
{
WORD type;
LTEXT prompt;
WORD id=0;
LONG itemflags=0;
STRUCT control;
LTEXT trailer="";
LTEXT bmpfile = "" ;
WORD bmpid = 0xffff ;
WORD bmpmask ;
LTEXT tooltip = "" ;
}
Dialog items flags
对话框行可以有自己的flags。如下表:
下面的flags只为了兼容性而仍保留着:
Buttons — softkeys
软件通过CBA资源来定义。下面是avkon.rsg中的预定义软键:
如果上面的软键不能满足需求,可以通过定义新的CBA资源来定义新的软件。下面示例:
RESOURCE CBA r_softkeys_options_next
{
buttons =
{
CBA_BUTTON
{
id = EAknSoftkeyOptions;
txt = qtn_aknexeditor_cba_options;
},
CBA_BUTTON
{
id = EAknMyCmdNext;
txt = qtn_Myapp_cba_next;
}
};
}
单页对话框资源定义
示例如下:
RESOURCE DIALOG r_demo_singlepage_dialog
{
flags = EEikDialogFlagNoDrag | EEikDialogFlagFillAppClientRect | EEikDialogFlagCbaButtons |
EEikDialogFlagWait;
buttons = R_AVKON_SOFTKEYS_OK_CANCEL;
items =
{
DLG_LINE
{
type = EEikCtNumberEditor;
// The caption(prompt)
prompt = "Number1:";
id = ESinglePageDlgC1Id;
// The control
control = NUMBER_EDITOR { min=0; max=999; };
// The tag, indicating the measurement unit
trailer = "cm";
},
DLG_LINE
{
type = EEikCtNumberEditor;
// The caption(prompt)
prompt = "Number2:";
id = EsinglePageDlgC2Id;
// The control
control = NUMBER_EDITOR { min=0; max=999; };
// The tag, indicating the measurement unit
trailer = "cm";
}
};
}
多页对话框资源定义
与单页对话框不同,多页对话框定义了一个pages list(单页对话框是item列表)。软键定义一般是
针对整个对话框的,而不是针对每个页。
示例如下:
RESOURCE DIALOG r_multipage_form
{
flags = EEikDialogFlagNoDrag | EEikDialogFlagFillAppClientRect |
EEikDialogFlagNoTitleBar | EEikDialogFlagNoBorder |
EEikDialogFlagCbaButtons;
buttons = R_AVKON_SOFTKEYS_OPTIONS_BACK;
pages = r_multipage_form_pages;
}
RESOURCE ARRAY r_multipage_form_pages
{
items =
{
PAGE
{
id = EAknExFormPageCtrlIdPage01;
text = qtn_multipage_form_label_page1;
form = r_multipage_form_text_field_form;
},
PAGE
{
id = EAknExFormPageCtrlIdPage02;
text = qtn_multipage_form_label_page2;
form = r_aknexform_text_number_field_form;
},
. . .
};
}
RESOURCE FORM r_multipage_form_text_field_form
{
flags = EEikFormUseDoubleSpacedFormat;
items =
{
DLG_LINE
{
type = EEikCtEdwin;
prompt = qtn_multipage_form_label_edwin;
id = EAknExFormDlgCtrlIdEdwin11;
itemflags = EEikDlgItemTakesEnterKey |
EEikDlgItemOfferAllHotKeys;
control = EDWIN
{
flags = EEikEdwinNoHorizScrolling | EEikEdwinResizable;
width = AKNEXFORM_EDWIN_WIDTH;
lines = AKNEXFORM_EDWIN_LINES;
maxlength = EAknExFormEdwinMaxLength;
// added to limit expanding in forms.
// If you want full screen use 5 here
max_view_height_in_lines = 5;
// if you have the line above, you must have this.
// It's calculable from LAF
base_line_delta = 21;
};
tooltip = qtn_multipage_hint_text_edwin;
},
};
}
对话框类的实现
对话框类的实现分为四个大步:
1. 重写继承自CAknDialog的类,或直接使用CAknDialog
2. 如果对话框控件需要用来自外部数据初始化,需要重写PressLayoutDynInitL()
3. 如果类是继承自CAknDialog,一般需要实现一个RunDlgLD()方法,方法中实例化一个对话框
,并使用相应对话框资源运行它
4. 如果需要保存控件的数据,需要重新OkToExitL()方法,该方法中保存数据,并判断是否退
出对话框
类定义的头文件示例如下:
Class CMyDialog::public CAknDialog
{
public:
// the static RunDlgLD launch function
static TInt RunDlgLD(TInt aResouceId);
private: // From CAknDialog
// base constructor - CAknDialog::CAknDialog() is used
// Destructor
~CMyDialog()
// the control initializer function
void PreLayoutDynInitL();
// the function that collects final control values as well as // checking the exit condition
TBool OkToExitL(TInt aButtonId);
private:
//data items
};
另外,还有一些方法可用来初始化对话框或对对话框数据进行有效性校验。
PostLayoutDynInitL()
与PreLayoutDynInitL()不同的是,PreLayoutDynInitL()是在对话框sized和layed out之前被调用的;
PostLayoutDynInitL()是在sized和layed out之后,但在actived之前被调用。
SetInitialCurrentLine()
设置第一个获取焦点的对话框行。默认情况下,第一个对话框页的第一行获取焦点。子类可
以重写该方法,但子类必须通过调用ActivateFirstPageL()来激活对话框页
HandleControlStateChangeL()
重写后处理控件状态的变化。这个方法在控件的事件类型为EEventStateChanged被调用。
PageChangedL(TInt aPageId )
切换到指定对话框页时被调用,默认为空。
LineChangedL(TInt aControlId )
切换到指定对话框行时被调用,默认为空。
PrepareForFocusTransitionL()
切换行的时候被调用,可以用来校验当前控件的内容是否合法等。
对话框类方法的实现
1. RunDlgLD()
TInt CMyDialog::RunDlgLD()
{
CMyDialog* dlg = new (ELeave) CMyDialog();
return dlg->ExecuteLD(R_DEMO_SINGLEPAGE_DIALOG);
}
2. PreLayoutDynInitL()
void CMyDialog::PreLayoutDynInitL()
{
// Get the Number1 editor control
CEikNumberEditor* editor1 = (CEikNumberEditor*) Control(ESinglePageDlgC1Id);
// Set the value to the Number1 editor
editor1->SetNumber(100);
// Get the Number2 editor control
CEikNumberEditor* editor2 = (CEikNumberEditor*) Control(EsinglePageDlgC2Id);
// Set the value to the Number2 editor
editor2->SetNumber(200);
}
3. OkToExitL()
TBool CMyDialog::OkToExitL (TInt aButtonId)
{
// Get the Number1 editor control
CEikNumberEditor* editor1 = (CEikNumberEditor*) Control(ESingleDlgId);
// Get the Number2 editor control
CEikNumberEditor* editor2 = (CEikNumberEditor*) Control(ESingleDlg2Id);
// Check the validity of the values in the two editors
if ( editor1->Number() > editor2->Number())
{
// Show an error note
CAknErrorNote* note = new (ELeave) CAknErrorNote;
note->ExecuteLD(_L("Number1 should be less than number2"));
return EFalse;
}
return ETrue;
}
对话框使用
使用对话框包括两步:
1. 使用new(ELeave)或NewL()创建对话框类实例
2. 调用ExecuteLD(TInt aResourceId)。它将调用PrepareLC(TInt aResourceId)和RunLD()。
有时候对话框类实现了RunDlgLD()方法,我们可以直接调用它来初始化和运行对话框。