【转】对话框之 通知

原文:http://hi.baidu.com/richiechyi/blog/item/0d0a616601b32120aa184cc5.html

 

为了使应用程序显示的通知标准化,Series60提供了包装式通知(wrapped note) ,使用这些标准通知时,只需要提供希望显示的文本,而不需指定资源。包装式通知有四种不同的类型:确认通知、信息通知、警告通知和错误通知。

关于包装式通知的使用,它们的构建和执行都遵循相同的模式,下面以CAknConfirmationNote示例之,首先使用第一阶段构造函数创建 一个包装式通知,然后调用ExecuteLD(),并传入希望此通知显示的描述符完成构建,该函数会完成第二阶段构造、显示通知,并在退出时 清除它。

     HBufC* noteText;
     noteText = StringLoader::LoadLC(R_SAVED_GAME_NOTE_TEXT);
     CAknConfirmationNote* note = new(ELeave)CAknConfirmationNote ();
     note->ExecuteLD (*noteText);
     CleanupStack::PopAndDestroy(noteText);

如果需求与标准的包装式通知有差异,可以为通知定义自己的资源并执行它,下面示例自定义通知
RESOURCE DIALOG r_confirmationnote_loaded_games_note
{
flags=EAknConfirmationNoteFlags;
items =
   {
   DLG_LINE
    {
    type = EAknCtNote;
    id = EConfirmationNote;
    control = AVKON_NOTE
     {
     layout = EGeneralLayout;
     singular_label = LOADED_GAMES_SINGULAR_TEXT;
     plural_label = LOADED_GAMES_PLURAL_TEXT;
     imagefile = "z://system/data/avkon.mbm";
     imageid = EMbmAvkonQgn_indi_marked_add;
     imagemask = EMbmAvkonQgn_indi_marked_add_mask;
     };
    }
   };
}

其中的标志flags=EAknConfirmationNoteFlags说明这是一个确认通知。
默认情况下,确认通知没有软键标签,为了把右软键显式设置为“取消”标签,可以在DIALOG资源的buttons字段中,把通知使用的软键指定为R_AVKON_SOFTKEYS_CANCEL。

为了创建自定义通知,需要从CAknNoteDialog派生一个通知对话框类。应该使用标准的对话框构建和执行方法来构建它。
void CConfirmationNoteContainer::ConstructL(const TRect& aRect)
{
CreateWindowL();

CAknNoteDialog* note = new (ELeave) CAknNoteDialog (CAknNoteDialog::EConfirmationTone, CAknNoteDialog::EShortTimeout);
note->PrepareLC (R_CONFIRMATIONNOTE_LOADED_GAMES_NOTE);
TInt numberOfLoadedGames = LoadGames();
note->SetTextPluralityL (numberOfLoadedGames > 1);
note->SetTextNumberL (numberOfLoadedGames);
note->RunLD ();

SetRect(aRect);
ActivateL();
}

构造函数需要提供音调和超时值两个参数。在执行通知时有两种方法,其一,调用ExecuteLD()并传入上一步创建的DIALOG资源即可执行此通知; 其二,如果需要在执行之前调用其他方法,则必须首先调用PrepareLC(),然后调用其他方法,最后调用RunLD()。

关于音调和超时值的选择:
enum TTone {
/// No tone is played
    ENoTone = 0,  
/// A confirmation tone is played
    EConfirmationTone = EAvkonSIDConfirmationTone,
/// A warning tone is played
    EWarningTone = EAvkonSIDWarningTone,     
/// An error tone is played
    EErrorTone = EAvkonSIDErrorTone        
    };
       
enum TTimeout {
/// Deprecated (not used)
EUndefinedTimeout = 0,  
/// No timeout
    ENoTimeout = 0,        
/// 1.5 seconds
    EShortTimeout = 1500000,
/// 3 seconds
    ELongTimeout = 3000000  
    };

等待通知(wait note) 用于告知用户处理正在进行,但不对处理所需的时间作任何说明。

等待通知的使用需要以下步骤
1. 在资源中定义等待通知,方式和自定义通知类似
RESOURCE DIALOG r_waitnote_saving_game_note
{
flags=EAknWaitNoteFlags;
items =
   {
   DLG_LINE
    {
    type = EAknCtNote;
    id = ENoteEx1DlgCIdSavingNote;
    control = AVKON_NOTE
     {
     layout = EWaitLayout;
     singular_label = SAVING_GAME_TEXT;
     imagefile = "z://system/data/avkon.mbm";
     imageid = EMbmAvkonQgn_note_progress;
     imagemask = EMbmAvkonQgn_note_progress_mask;
     animation = R_QGN_GRAF_WAIT_BAR_ANIM;
     };
    }
   };
}

把此对话框的flags设置为EAknWaitNoteFlags。
对于AVKON_NOTE,应该:
* 把layout设置为EWaitLayout
* 使用animation字段为等待条添加动画效果。把此字段设置为R_QGN_GRAF_WAIT_BAR_ANIM,获得标准动画

2. 构建和执行等待通知包装器对象
构建和执行等待通知包装器与其他对话框不同。等待通知包装器实际上是包装在活动对象中的等待通知,因此和其他对话框的行为不同。可以使用CAknWaitDialog实现相同的功能,但这要编写一个活动对象,所以略微负责些。
使用等待通知包装器的NewL()和ExecuteL()方法构建和执行它。

void CWaitNoteContainer::SaveGameL()
{
CAknWaitNoteWrapper* waitNoteWrapper = CAknWaitNoteWrapper::NewL();

// Required reinterpret_cast as CAknWaitNoteWrapper inherits privately from CActive
CleanupStack::PushL(reinterpret_cast<CBase*>(waitNoteWrapper));

// this is a blocking call, remember the wrapper isn't a dialog,
// so it doesn't need the EEikDialogFlagWait flag to make it blocking

if (! waitNoteWrapper->ExecuteL(R_WAITNOTE_SAVING_GAME_NOTE, *this))
   CancelGameSave();

CleanupStack::PopAndDestroy(waitNoteWrapper);
}

必须为ExecuteL()函数提供一个DIALOG资源和一个对MAknBackgroundProcess对象的引用。在这里,容器类实现了 MAknBackgroundProcess混合类,因此传递*this。ExecuteL()在处理结束前将阻塞,并最终返回一个TBool,说明处理 已完成(ETrue)或被用户取消(EFalse)。

与其他对话框不同,等待通知不会在执行结束时删除,而必须显式地删除它们

注意:如果通知包装器不是某个类的成员数据,则在把它放入清除栈时应使用强制类型转换,把它强制转换为一个CBase指针。不能直接把它放入清除栈,因为改对象私有继承自CActive,这表示它不能隐式转换成CBase*。

3. 创建MAknBackgroundProcess派生类
为了能够实例化包装器,需要实现一个MAknBackgroundProcess类,该工作由容器类完成。
class CWaitNoteContainer : public CCoeControl, public MAknBackgroundProcess
{
private: // from MAknBackgroundProcess

void DialogDismissedL(TInt /*aButtonId*/);
TBool IsProcessDone() const;
void ProcessFinished();
void StepL();
// ...
};

MAknBackgroundProcess封装了显示等待通知时发生的处理。等待通知包装器封装了一个活动对象,该活动对象在等待通知包装器运行时调用MAknBackgroundProcess中的方法。


CAknBackgroundProcess是一个活动对象,因此调用ExecuteL()将导致活动规划器发出一条服务请求。该请求被处理之后,调用 MAknBackgroundProcess::IsProcessDone()判断处理的所有步骤是否都已执行。如果尚未完成,则返回EFalse,之 后调用MAknBackgroundProcess::StepL()执行处理的下一个步骤。
如果处理可以结束(即用户未取消此对话框),则框架依次调用MAknBackgroundProcess::ProcessFinished()和 MAknBackgroundProcess::DialogDismissedL()。如果用户终止了该处理,则框架首先调用 DialogDismissedL(),然后调用IsProcessDone()检查处理是否结束,最后调用ProcessFinished()。
StepL()方法同步执行。因此,它应该迅速处理,否则将无法取消通知。此线程将阻塞,并且在显示通知时会有严重的延迟,因为直到一个步骤完成时才能显示通知。

进度通知 与等待通知类似,但会向用户可视化说明处理的哪些部分尚未执行。

基本步骤如下:
1. 声明进度通知
进度通知包含一个进度条。执行处理过程中,必须以均匀的间隔递增和重绘此进度条。处理应分为小步骤异步运行,最后使用一个活动对象。否则,线程将被阻塞,通知无法更新,甚至可能直到处理完成都不会显示。
采用通常的方式,通过从CActive派生一个创建一个活动对象
class CProgressNoteGameSaverAO : public CActive
{
// ...
private: // from CActive
void RunL();
void DoCancel();

private: //data
CAknProgressDialog* iProgressDialog;
// ...
};
进度通知是非等待性的对话框。即在对话框执行过程中,应用程序可以继续执行后台的处理过程,因此应该将进度条声明为成员数据,然后在析构函数中删除它。

2. 为长度可变的处理创建进度通知
进度通知在长时间的处理将要开始时创建,通常在一个活动对象内构建。
iProgressDialog = new (ELeave) CAknProgressDialog (reinterpret_cast<CEikDialog**>(&iProgressDialog));
有两个构造函数用于创建长度可变的进度通知。这里使用的构造函数所创建的进度通知在处理开始后1.5秒开始显示,并显示至少1.5秒。如果处理在最初的 1.5秒内完成,将不会显示通知。这样对于处理较短的情况,通知不会在屏幕上闪烁一下就消失。另一个构造函数带有一个TBool参数,可以把它设置为 ETrue以避免延迟。应该只在确信处理至少需要1.5秒时才使用它。
两个构造函数都带有一个参数,文档称它是一个自身指针。但这实际上是通知的成员数据指针的地址,在传递时需要转换该参数。

3. 执行进度通知
构建进度条之后,即可准备和运行它。
iProgressDialog->PrepareLC(R_PROGRESSNOTE_SAVING_GAME_NOTE);
iProgressDialog->SetCallback (this); // calls DialogDismissL on completion
CEikProgressInfo* progressBar = iProgressDialog->GetProgressInfoL(); // not taking ownership
progressBar->SetFinalValue(KFinalValue); // Set final value of progress bar
iProgressDialog->RunLD(); // this doesn't actually delete the dialog despite the 'D' suffix
SaveGamePartToFile(); // make a synchronous request
progressBar->IncrementAndDraw(KIncrement); // increment the progress bar
SetActive(); // set the active object to be active

首先调用PrepareLD()并传入资源,准备使用对话框。进度条通知默认为非等待的。非等待进度通知在执行结束时不会返回任何值,因此无法根据返回值 判断处理是否正常结束。而必须通过调用CAknProgressDialog::SetCallback()并传入一个 MProgressDialogCallback对象,在通知上设置回调。对话框关闭时,在回调对象上调用DialogDismissedL()。
进度条将显示任务完成的比例,所以有必要设置进度条内独立单元的数量。可以通过调用对话框的GetProgressInfoL()获取进度条,然后调用CEikProgressInfo::SetFinalValue()设置进度条表示的单元数。
使用RunLD()实例化通知,该方法立即返回,允许处理过程开始执行。RunLD()方法带有的“D”后缀,但与其他非等待对话框一致,此通知不会在 RunLD()返回时删除,而是在调用ProcessFinishedL()时删除;或者,如果用户关闭了通知,则在调用 DialogDismissedL()方法(由OkToExitL()调用)后删除。

4. 在处理过程执行的过程中更新进度通知
在处理过程执行的过程中,必须定期更新进度条,并在处理结束时关闭它,这通常在活动对象的RunL()中完成。
void CProgressNoteGameSaverAO::RunL()
{
if (!IsProcessDone())
   {
   SaveGamePartToFile();
   iProgressDialog->GetProgressInfoL()->IncrementAndDraw(KIncrement);
   SetActive();
   }
else
   {
   iProgressDialog->ProcessFinishedL();
   }
}

RunL()方法首先应检查所有处理过程是否已经完成。
如果处理完成,则调用进度通知的ProcessFinishedL()方法通知它,然后进度通知会调用DialogDismissedL()方法并删除自己,同时把自身指针设置为NULL。
如果处理尚未完成,则反复执行下列步骤直到处理过程完成:
* 执行处理过程的一个步骤
* 使用IncrementAndDraw()方法相应地更新进度条
* 把活动对象设置为活动状态。这将再次调用RunL()以完成下一个步骤。一旦递增到终值,进度通知将自动关闭。应该谨慎地选择终值和增量,以确保进度通知不会在处理结束前关闭。

5. 进度通知的完成和用户取消
进度对话框关闭时调用MProgressCallback::DialogDismissedL()。可以在该方法中执行所有的清除工作(对于用户取消的情况),或是在成功结束后执行进一步的处理。
void CProgressNoteGameSaverAO::DialogDismissedL(TInt /*aButtonId*/)
{
if (!IsProcessDone())
   {
   CancelGameSave();
   }
else
   {
   CompleteGameSave();
   }
iStepsCompleted = 0;
}

6. 周期固定的进度通知
如果处理过程所需时间的长度已知,可以实例化一个能够自动更新显示的进度对话框。同样,此任务在活动对象内执行。但通知对象本身会自动递增和重绘进度条,所以不需要在代码中执行这些工作。

const TInt KFinalValue = 5;
const TInt KInterval = 100;
const TInt KIncrement = 1;

SaveGamePartToFile();
SetActive();

iProgressDialog = new (ELeave) CAknProgressDialog(KFinalValue, KIncrement, KInterval, reinterpret_cast<CEikDialog**>(&iProgressDialog));

iProgressDialog->ExecuteLD(R_PROGRESSNOTE_SAVING_GAME_NOTE);

需要提供以下三个参数。它们将决定进度条递增的方式和处理过程的长度:
终值 - 决定了进度条中的单元数
递增 - 进度条递增时进度移动的单元个数
间隔 - 进度条递增的频率,单位为百分之一秒

全局通知 对话框总会显示在屏幕上,即使拥有它的应用程序当前不拥有焦点。用于显示全局通知的代码十分简单,但应该谨慎地使用它。全局通知不需要在资源中定义,但可以在资源结构中自定义全局通知。


使用NewL()和ShowNoteL()方法构建和执行全局通知。需要为ShowNoteL()方法提供通知的类型和希望显示的文本。<aknnotifystd.h>在TAknGlobalNoteType枚举中定义了可能的通知类型:
enum TAknGlobalNoteType
{
EAknGlobalInformationNote = 1,
EAknGlobalWarningNote,
EAknGlobalConfirmationNote,
EAknGlobalErrorNote,
EAknGlobalChargingNote,
EAknGlobalWaitNote,
EAknGlobalPermanentNote,
EAknGlobalNotChargingNote,
EAknGlobalBatteryFullNote,
EAknGlobalBatteryLowNote,
EAknGlobalRechargeBatteryNote,
EAknCancelGlobalNote,
EAknGlobalTextNote
};

下面为示例全局通知的使用:

HBufC* noteText;

noteText = StringLoader::LoadLC(R_GLOBAL_NOTE_TEXT);

CAknGlobalNote* globalNote = CAknGlobalNote::NewLC ();

iNoteId = globalNote->ShowNoteL (EAknGlobalPermanentNote, *noteText);

CleanupStack::PopAndDestroy(globalNote);

CleanupStack::PopAndDestroy(noteText);

所有全局通知都有一个CancelNoteL() 方法,可以调用该方法关闭它们。该方法需要希望取消的通知的ID,即调用ShowNoteL()方法时返回的ID。这种永久性的通知不会超时,也不能被用户关闭,而必须在程序中调用CancelNoteL()取消。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值