原本是想做一个自定义的带输入框的对话框控件,开始的思路是用继承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 //自己定义的枚举,用来保存输入法的模式,方便识别
{
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.获取输入法时。不识别abc和ABC状态。当时直接使用的是CEikEdwin的TInt nTemp = AknEditorCurrentInputMode()这个方法。
这个方法在abc,Abc和ABC状态时都返回1.
2.在中文输入法的时候,当选择中文字的时候,点取消,这个时候不好识别时关闭控件,还是取消汉字的选择。经过长时间的尝试,发现当点击取消汉字的选择时,控件的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"));
}