原本是想做一個自訂的帶輸入框的對話方塊控制項,開始的思路是用繼承CAknDilog來做的,但是後來發現,這麼做的時候,對話方塊的CBA不好出來,雖然可以可以通過方法隱藏,當時當隱藏CBA後,對話方塊的按鍵就不好處理,所以想了一個代替的方法。
控制項繼承於CCoeControl的。同時還繼承於MAknEditingStateIndicator,MAknEditingStateIndicator這個主要是為了擷取編輯框當前的輸入狀態。具體的作用自己查SDK吧。廢話不多說先貼代碼,在講思路。
.h檔案
/*
============================================================================
Name : NewDilog.h
Author :
Version : Barrett
Copyright : Your copyright notice
Description : CNewDilog declaration
============================================================================
*/
#ifndef __NEWDILOG_H__
#define __NEWDILOG_H__
// INCLUDES
#include <e32std.h>
#include <eikedwin.h>
#include <akneditstateindicator.h> // for MAknEditingStateIndicator
#include "MEventObserver.h"
// CLASS DECLARATION
class CClientEventExample;
/**
* CNewDilog
*
*/
class CNewDilog : public CCoeControl,public MAknEditingStateIndicator
{
public: // Constructors and destructor
enum EInputMode //自己定義的枚舉,用來儲存IME的模式,方便識別
{
EUnknown,
EABC,
Eabc,
EAbc,
E123,
EPinYin,
EBiHua
};
/**
* Destructor.
*/
~CNewDilog();
/**
* Two-phased constructor.
*/
static CNewDilog* NewL(MInputDilogObserver &aObserver,CCoeControl *aParent);
/**
* Two-phased constructor.
*/
static CNewDilog* NewLC(MInputDilogObserver &aObserver,CCoeControl *aParent);
TKeyResponse OfferKeyEventL(const TKeyEvent &aKeyEvent, TEventCode aType);
private:
/**
* Constructor for performing 1st stage construction
*/
CNewDilog(MInputDilogObserver &aObserver);
/**
* EPOC default constructor for performing 2nd stage construction
*/
void ConstructL(CCoeControl *aParent);
void Draw( const TRect& aRect ) const;
void SetState(TAknEditingState aState); //這個函數以及下面一個函數,是MAknEditingStateIndicator的兩個純虛方法
CAknIndicatorContainer* IndicatorContainer();
CEikEdwin *iEditor;
TInt CountComponentControls() const;
CCoeControl* ComponentControl( TInt aIndex ) const;
private:
TRect iRect;
TRect iEditorRect;
MInputDilogObserver &iObserver;
//儲存editor的狀態
TBool iStatus;
CCoeControl *iParent;
//輸入狀態
EInputMode iCurInputMode;
//輸入狀態對應的名字
TBuf<8> iCurModeName;
//擷取輸入狀態
void GetInputMode();
public:
void MakeVisible(TBool aVisible);
void SetDilogRect(TRect aRect,TRect aEditorRect);
TBool IsFocus();
void ConvGbk2Uni(TDesC8& original, TDes& res);
};
struct S_uid: public TUid
{
S_uid(int i)
{
iUid = i;
}
};
#endif //__NEWDILOG_H__
控制項的觀察者 MEventObserver.h檔案
#ifndef __MEVENTOBSERVER_H__
#define __MEVENTOBSERVER_H__
/***********************************************************
* 輸入對話方塊的觀察者
***********************************************************/
class MInputDilogObserver
{
public:
virtual void GetContent(TDesC &aText,TBool aStatus) = 0;
};
#endif
// End of File
.cpp檔案
/*
============================================================================
Name :NewDilog.cpp
Author :
Version : Barrett
Copyright : Your copyright notice
Description : CNewDilog implementation
============================================================================
*/
#include "NewDilog.h"
#include <EIKENV.H>
#include <aknenv.h>
#include <aknindicatorcontainer.h>
#include <avkon.hrh>
#include <CHARCONV.H>
#include "InputDilog.h"
CNewDilog::CNewDilog(MInputDilogObserver &aObserver):iObserver(aObserver)
{
// No implementation required
iStatus = ETrue;
}
CNewDilog::~CNewDilog()
{
delete iEditor;
}
CNewDilog* CNewDilog::NewLC(MInputDilogObserver &aObserver,CCoeControl *aParent)
{
CNewDilog* self = new (ELeave)CNewDilog(aObserver);
CleanupStack::PushL(self);
self->ConstructL(aParent);
return self;
}
CNewDilog* CNewDilog::NewL(MInputDilogObserver &aObserver,CCoeControl *aParent)
{
CNewDilog* self=CNewDilog::NewLC(aObserver,aParent);
CleanupStack::Pop(); // self;
return self;
}
void CNewDilog::ConstructL(CCoeControl *aParent)
{
// iRect = TRect(TPoint(0,160),TSize(240,160));
iCurModeName.Copy(_L("Abc"));
iParent = aParent;
// CEikEdwin::ConstructL(EAknEditorFlagDefault | EEikEdwinNoAutoSelection | EEikEdwinJustAutoCurEnd, 0, 10, 1);//調用系統控制項的二段建構函式
}
TKeyResponse CNewDilog::OfferKeyEventL(const TKeyEvent &aKeyEvent, TEventCode aType)
{
GetInputMode();
// if(aType == EEventKey && aKeyEvent.iScanCode == EStdKeyDevice0)
// {
// TBuf<100> TextBuf;
// iEditor->GetText(TextBuf);
// iObserver.GetContent(TextBuf,ETrue);
// }
// else if(aType == EEventKey && aKeyEvent.iScanCode == EStdKeyDevice1)
// {
// TBuf<100> TextBuf;
// iEditor->GetText(TextBuf);
// iObserver.GetContent(TextBuf,EFalse);
// }
// else
// {
iEditor->OfferKeyEventL(aKeyEvent,aType);
// }
return iEditor->OfferKeyEventL(aKeyEvent,aType);
}
void CNewDilog::Draw( const TRect& aRect ) const
{
CWindowGc& gc = SystemGc();
if(iStatus) //是否畫控制項
{
gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
gc.SetBrushColor(KRgbGreen);
gc.DrawRect(iRect); //背景色
gc.SetBrushColor(KRgbWhite);
gc.DrawRect(TRect(TPoint(iEditorRect.iTl.iX-1,iEditorRect.iTl.iY-1),TSize(iEditorRect.Width()+2,iEditorRect.Height()+2))); //畫editor矩形框
gc.SetBrushStyle(CGraphicsContext::ENullBrush);
const CFont *font = CEikonEnv::Static()->DenseFont();
gc.UseFont(font);
gc.SetPenColor(KRgbBlack);
gc.DrawText(iCurModeName,TPoint(iEditorRect.iTl.iX,iEditorRect.iTl.iY+font->HeightInPixels()+iEditorRect.Height() ));
gc.DiscardFont();
iEditor->TextView()->DrawL(iEditorRect); //解決控制項重新整理時,可能前面輸入的都不顯示了,
}
}
void CNewDilog::MakeVisible(TBool aVisible)
{
iStatus = aVisible;
iEditor->SetFocus(aVisible);
iEditor->MakeVisible(aVisible);
}
void CNewDilog::SetDilogRect(TRect aRect,TRect aEditorRect)
{
iRect = aRect;
iEditorRect = aEditorRect;
iEditor = new(ELeave) CEikEdwin;
iEditor->SetContainerWindowL(*iParent);
iEditor->ConstructL(EAknEditorFlagDefault | EEikEdwinNoAutoSelection | EEikEdwinJustAutoCurEnd, 0, 100, 1);//調用系統控制項的二段建構函式
iEditor->SetExtent(iEditorRect.iTl,iEditorRect.Size());
iEditor->MakeVisible(EFalse);
}
TBool CNewDilog::IsFocus()
{
return iStatus;
}
void CNewDilog::SetState(TAknEditingState aState)
{
}
CAknIndicatorContainer* CNewDilog::IndicatorContainer()
{
return NULL;
}
void CNewDilog::GetInputMode()
{
MAknEditingStateIndicator* ei = CAknEnv::Static()->EditingStateIndicator() ;
if (!ei) return;
CAknIndicatorContainer* ic = ei->IndicatorContainer();
if (!ic) return;
iCurModeName.Zero();
if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorPinyin)))
{
iCurInputMode = EPinYin;
TBuf8<20> msg8 ;
msg8.Format(_L8("拼音"));
ConvGbk2Uni(msg8, iCurModeName) ;
}
if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorStroke)))
{
iCurInputMode = EBiHua;
TBuf8<20> msg8 ;
msg8.Format(_L8("筆畫"));
ConvGbk2Uni(msg8, iCurModeName) ;
}
else if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorLowerCase)))
{
iCurInputMode = Eabc;
iCurModeName.Copy(_L("abc"));
}
else if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorUpperCase)))
{
iCurInputMode = EABC;
iCurModeName.Copy(_L("ABC"));
}
else if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorTextCase)))
{
iCurInputMode = EAbc;
iCurModeName.Copy(_L("Abc"));
}
else if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorNumberCase)))
{
iCurInputMode = E123;
iCurModeName.Copy(_L("123"));
}
DrawNow();
// CEikEdwin::DrawNow();
}
void CNewDilog::ConvGbk2Uni(TDesC8& original, TDes& res)
{
//RFs aFileServerSession = CEikonEnv::Static()->FsSession();
RFs aFileServerSession;
aFileServerSession.Connect();
// CleanupStack::Pop();
CCnvCharacterSetConverter* converter=CCnvCharacterSetConverter::NewLC();
if(converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGbk,aFileServerSession)!=CCnvCharacterSetConverter::EAvailable)
User::Leave(KErrNotSupported);
TInt state=CCnvCharacterSetConverter::KStateDefault;
TPtrC8 str( original );
HBufC* iInfoText = HBufC::NewL( str.Length() );
TPtr16 ptr = iInfoText->Des();
if(CCnvCharacterSetConverter::EErrorIllFormedInput == converter->ConvertToUnicode(ptr, str, state))
User::Leave(KErrArgument);
res.Zero() ;
res.Copy(ptr) ;
aFileServerSession.Close();
CleanupStack::PopAndDestroy();
delete iInfoText;
}
TInt CNewDilog::CountComponentControls() const
{
// return number of controls inside this container
return 1;
// return 0;
}
CCoeControl* CNewDilog::ComponentControl( TInt aIndex ) const
{
switch(aIndex)
{
case 0:
return iEditor;
}
return NULL;
}
在container中的使用:
1.在container.h中,container需要繼承我們的觀察者代碼如是:
class CContainer:MInputDilogObserver
2.實現MInputDilogObserver的虛方法
void GetContent(TDesC &aText,TBool aStatus);
這個時候我們就直接可以在這個函數中處理返回的的控制項中返回的值和狀態了。
3.定義一個CNewDilog *iNewDilog;成員
4.初始化
iNewDilog = CNewDilog::NewL(*this,this);
iNewDilog->SetContainerWindowL(*this);
iNewDilog->SetDilogRect(TRect(TPoint(0,160),TSize(240,160)),TRect(TPoint(50,235), TSize(150,20)));
iNewDilog->SetExtent(TPoint(0,0), TSize(240,320));
iNewDilog->MakeVisible(ETrue);
5.CountComponentControls 加1 和 ComponentControl 返回控制項指標
6.在OfferKeyEventL函數中調用控制項的OfferKeyEventL函數來傳遞索引值
7.在解構函式中寫釋放函數
8.編譯運行。
總結:我們可以通過makevisible函數來讓控制項顯示和隱藏。同時當點擊確認或取消時,通過觀察者iObserver將狀態和資料返回給使用控制項的container。思路還是比較簡單的。但是遇到的問題確實不少啊~~
主題問題:
1.擷取IME時。不識別abc和ABC狀態。當時直接使用的是CEikEdwin的TInt nTemp = AknEditorCurrentInputMode()這個方法。
這個方法在abc,Abc和ABC狀態時都返回1.
2.在中文IME的時候,當選擇中文字的時候,點取消,這個時候不好識別時關閉控制項,還是取消漢字的選擇。經過長時間的嘗試,發現當點擊取消漢字的選擇時,控制項的OfferKeyEventL函數只會走一遍,就是只會走EEventKeyDown,所以可以通過這個判斷是關閉控制項還是漢字的選擇,如代碼中通過aType == EEventKey 事件來判斷關閉控制項。
4.iEditor->TextView()->DrawL(iEditorRect); 這個函數的使用。它的作用是解決控制項重新整理時,可能前面輸入的內容都不顯示了的問題。
5.複合控制項的作用類似於一個container。在控制項中添加控制項時,如果container一樣,需要寫CountComponentControls和ComponentControl函數。複合控制項的ConstructL中也像普通的複合控制項一樣,擁有視窗或者共用container的視窗。本文中用的是共用container的視窗。
昨天沒在手機上測試,幾天測了下,發現拼音和筆畫顯示不出來,今天在改下代碼把拼音和筆畫的判斷條件改為如下代碼就OK了
if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorPinyin)) || ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorPinyinPhrase)))
{
iCurInputMode = EPinYin;
TBuf8<20> msg8 ;
msg8.Format(_L8("拼音"));
ConvGbk2Uni(msg8, iCurModeName) ;
// iCurModeName.Copy(_L("PinYin"));
}
if(ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorStroke)) || ic->IndicatorState(S_uid(EAknNaviPaneEditorIndicatorStrokePhrase)))
{
iCurInputMode = EBiHua;
TBuf8<20> msg8 ;
msg8.Format(_L8("筆畫"));
ConvGbk2Uni(msg8, iCurModeName) ;
// iCurModeName.Copy(_L("BiHua"));
}