symbian 自定义控件
学习了一下自定义控件,及复合控件,自定义控件从 CCoeControl 继承过来,要实现 CCoeControl 的
void SizeChange() , void Draw(const TRect& aRect,const CCoeControl* aParent) 这两个虚方法,
自定义控件要用两阶构造方法,所以要添加 NewL 及 NewLC 方法,由于 Draw 方法需要用到两个参数,所以
在 NewL 时把两个参数要传入,下面是自定义控件的代码
头文件
class CSimControl : public CCoeControl
{
public:
static CSimControl* NewL(const TRect& aRect,const CCoeControl* aParent);
static CSimControl* NewLC(const TRect& aRect,const CCoeControl* aParent);
public:
CSimControl();
virtual ~CSimControl();
void Draw(const TRect& aRect) const;
void SizeChanged();
private:
void ConstructL(const TRect& aRect,const CCoeControl* aParent );
};
代码文件
//
// Construction/Destruction
//
CSimControl::CSimControl()
{
}
CSimControl::~CSimControl()
{
}
CSimControl* CSimControl::NewL( const TRect& aRect,const CCoeControl* aParent )
{
CSimControl* self = CSimControl::NewLC(aRect,aParent);
CleanupStack::Pop();
return self;
}
CSimControl* CSimControl::NewLC( const TRect& aRect,const CCoeControl* aParent )
{
CSimControl* self = new(ELeave)CSimControl();
CleanupStack::PushL(self);
self->ConstructL(aRect,aParent);
return self;
}
void CSimControl::Draw( const TRect& aRect ) const
{
CWindowGc& gc = SystemGc();
gc.Clear(aRect);
gc.SetPenStyle(CGraphicsContext::ESolidPen);
gc.SetPenColor(KRgbBlack);
gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
gc.SetBrushColor(KRgbBlack);
gc.DrawEllipse(aRect);
}
void CSimControl::SizeChanged()
{
}
void CSimControl::ConstructL(const TRect& aRect,const CCoeControl* aParent )
{
if (aParent == NULL)
{
CreateWindowL();
} else
{
SetContainerWindowL(*aParent);
}
SetRect(aRect);
ActivateL();
}这里曾犯过一个错误,上面的代码 if(aParent ==NULL) 写成 if(aParent !=NULL) ,结果一直报错
在传统模式下调用代码
// INCLUDE FILES |
上面加粗的代码是该控件的代码,注释起来是因为测试复合控件时才注释起来
需要注意的是 SizeChange 方法,一定要写上 iSimControl->SetExtent(TPoint(10,10),iSimControl->MinimumSize());
否则显示不出来
复合控件代码
头文件
#include <coecntrl.h> #include "SimControl.h" class CCompoundControl : public CCoeControl { public: static CCompoundControl* NewL(const TRect& aRect,const CCoeControl* aParent); static CCompoundControl* NewLC(const TRect& aRect,const CCoeControl* aParent); ~CCompoundControl(); public: CCompoundControl(); private: void ConstructL(const TRect& aRect,const CCoeControl* aParent); // 继承的方法 TInt CountComponentControls() const; CCoeControl* ComponentControl(TInt aIndex) const; void Draw(const TRect& aRect) const; void SizeChanged(); private: void CalculateRects(); private: //定义两个自定义控件 CSimControl* iTop; CSimControl* iBottom; TRect iTopRect; TRect iBottomRect; private: enum TComponentControls { ETop = 0,EBottom,ENumberOfControls }; }; |
代码文件
#include "CompoundControl.h" // // Construction/Destruction // CCompoundControl::CCompoundControl() { } CCompoundControl::~CCompoundControl() { delete iTop; delete iBottom; } CCompoundControl* CCompoundControl::NewL( const TRect& aRect,const CCoeControl* aParent ) { CCompoundControl* self = CCompoundControl::NewLC(aRect,aParent); CleanupStack::Pop(); return self; } CCompoundControl* CCompoundControl::NewLC( const TRect& aRect,const CCoeControl* aParent ) { CCompoundControl* self = new (ELeave) CCompoundControl(); CleanupStack::PushL(self); self->ConstructL(aRect,aParent); return self; } TInt CCompoundControl::CountComponentControls() const { return ENumberOfControls; } CCoeControl* CCompoundControl::ComponentControl( TInt aIndex ) const { switch(aIndex) { case ETop: return iTop; break; case EBottom: return iBottom; break; default: return NULL; break; } } void CCompoundControl::Draw( const TRect& aRect ) const { CWindowGc& gc = SystemGc(); gc.Clear(aRect); } void CCompoundControl::CalculateRects() { TRect outerRect = Rect(); const TInt innerRectWidth = outerRect.Width(); const TInt innerRectHeight = outerRect.Height()/2; iTopRect.SetRect(outerRect.iTl,TSize(innerRectWidth,innerRectHeight)); iBottomRect = iTopRect; iBottomRect.Move(0,innerRectHeight); } void CCompoundControl::ConstructL(const TRect& aRect,const CCoeControl* aParent) { if (aParent==NULL) { CreateWindowL(); }else { SetContainerWindowL(*aParent); } CalculateRects(); iTop = CSimControl::NewL(aRect,this); iBottom = CSimControl::NewL(aRect,this); SetRect(aRect); ActivateL(); } void CCompoundControl::SizeChanged() { CalculateRects(); iTop->SetRect(iTopRect); iBottom->SetRect(iBottomRect); } |
复合控件也是从 CCoeControl 继承过来
上面已有的代码中写有把复合控件添加到传统模式的代码
下面是把自定义控件添加到View模式下
添加到 view 模式下时,需要把 appUi 从 CAknViewAppUi 继承,传统模式下是从 CAknAppUi 继承,然后还需要写一个 从CAknView继承来的类,在 AppUi中添加该类的成员,并创建该类的实例,下面是一个view类的代码
头文件:
#include <aknview.h> #include <SimControl.h> #include <e32std.h> #include <aknviewappui.h> class CSimControlView : public CAknView { public: static CSimControlView* NewL(); static CSimControlView* NewLC(); ~CSimControlView(); private: TUid Id() const; void HandleCommandL(TInt aCommand); void DoActivateL( const TVwsViewId& aPrevViewId, TUid aCustomMessageId, const TDesC8& aCustomMessage); void DoDeactivate(); private: CSimControlView(); void ContructL(); private: CSimControl* iSimControl; TUid iId; }; |
从CAknView 继承时一定要重写 Id() ,DoActivateL(),DoDeactivate() 方法,Id()用于返回一个 view 的ID,DoActivateL是激活view时,DoDeactivate是不激活(由活动变成非活动)
代码文件:
#include "SimControlView.h" #include "SIMPLECONTROLLX.RSG" #include "sc.hrh" #include "avkon.hrh" // // Construction/Destruction // CSimControlView::CSimControlView() { } CSimControlView::~CSimControlView() { if (iSimControl) { delete iSimControl; iSimControl = NULL; } } CSimControlView* CSimControlView::NewL() { CSimControlView* self = CSimControlView::NewLC(); CleanupStack::Pop(); return self; } CSimControlView* CSimControlView::NewLC() { CSimControlView* self = new(ELeave) CSimControlView(); CleanupStack::PushL(self); self->ContructL(); return self; } /* 返回视图的 id ,在视图切换时会用到此函数,一般都采用获取视图 id 的方式访问视图 ESimpleControlViewId ,是定义在 hrh 文件中的一个枚举值,也可以定义一个全局TUid 变量 */ TUid CSimControlView::Id() const { return TUid::Uid(ESimpleControlViewId); } /* 这里一般都调用 appUi 的 HandleCommandL*/ void CSimControlView::HandleCommandL( TInt aCommand ) { switch(aCommand) { case EAknSoftkeyBack: AppUi()->HandleCommandL(EEikCmdExit); break; default: AppUi()->HandleCommandL(aCommand); break; } } void CSimControlView::DoActivateL( const TVwsViewId& aPrevViewId, TUid aCustomMessageId, const TDesC8& aCustomMessage ) { if (!iSimControl) { this->iSimControl = CSimControl::NewL(ClientRect(),NULL); iSimControl->SetMopParent(this); AppUi()->AddToStackL(*this,iSimControl); } } void CSimControlView::DoDeactivate() { if (iSimControl) { AppUi()->RemoveFromStack(iSimControl); delete iSimControl; iSimControl = NULL; } } void CSimControlView::ContructL() { //this->BaseConstructL(R_CONTROLS_VIEW1); // 这里不太清楚为什么要传入一个资源 id // 去掉这句也运行正常 //BaseConstructL(); } |
下面是 appui的代码
头文件:
class
CscAppUi :
public
CAknViewAppUi
{ public : // // Constructors and destructor /* * * EPOC default constructor. */ void ConstructL(); /* * * Destructor. */ ~ CscAppUi(); public : // New functions public : // Functions from base classes private : // From MEikMenuObserver void DynInitMenuPaneL(TInt aResourceId,CEikMenuPane * aMenuPane); private : /* * * From CEikAppUi, takes care of command handling. * @param aCommand command to be handled */ void HandleCommandL(TInt aCommand); /* * * From CEikAppUi, handles key events. * @param aKeyEvent Event to handled. * @param aType Type of the key event. * @return Response code (EKeyWasConsumed, EKeyWasNotConsumed). */ virtual TKeyResponse HandleKeyEventL( const TKeyEvent & aKeyEvent,TEventCode aType); private : // Data CscContainer * iAppContainer; CSimControlView * iSimControlView; CCompoundControlView * iCompoundControl; CAknNavigationControlContainer * iNaviPanel; CAknTabGroup* iTabGroup; CAknNavigationDecorator* iDecoratedTabGroup; // decorated 修饰的意思 }; |
上面加粗部分的是 tab控件信息
代码文件:
//
INCLUDE FILES
#include " scAppui.h " #include " scContainer.h " #include < sc.rsg > #include " sc.hrh " #include < avkon.hrh > // ================= MEMBER FUNCTIONS ======================= // // ---------------------------------------------------------- // CscAppUi::ConstructL() // // ---------------------------------------------------------- // void CscAppUi::ConstructL() { BaseConstructL(); /* iAppContainer = new (ELeave) CscContainer; iAppContainer->SetMopParent( this ); iAppContainer->ConstructL( ClientRect() ); AddToStackL( iAppContainer ); */ // 应该是取得状态面板 CEikStatusPane * sp = StatusPane(); iNaviPanel = (CAknNavigationControlContainer * )sp -> ControlL(TUid::Uid(EEikStatusPaneUidNavi)); this -> iDecoratedTabGroup = iNaviPanel -> ResourceDecorator(); if (iDecoratedTabGroup) { iTabGroup = (CAknTabGroup * )iDecoratedTabGroup -> DecoratedControl(); } iSimControlView = CSimControlView::NewL(); AddViewL(iSimControlView); /* */ /* */ iCompoundControl = CCompoundControlView::NewL(); AddViewL(iCompoundControl); // SetDefaultViewL(*iCompoundControl); SetDefaultViewL( * iSimControlView); } // ---------------------------------------------------- // CscAppUi::~CscAppUi() // Destructor // Frees reserved resources // ---------------------------------------------------- // CscAppUi:: ~ CscAppUi() { if (iAppContainer) { RemoveFromStack( iAppContainer ); delete iAppContainer; } } // ------------------------------------------------------------------------------ // CscAppUi::DynInitMenuPaneL(TInt aResourceId,CEikMenuPane* aMenuPane) // This function is called by the EIKON framework just before it displays // a menu pane. Its default implementation is empty, and by overriding it, // the application can set the state of menu items dynamically according // to the state of application data. // ------------------------------------------------------------------------------ // void CscAppUi::DynInitMenuPaneL( TInt /* aResourceId */ ,CEikMenuPane * /* aMenuPane */ ) { } // ---------------------------------------------------- // CscAppUi::HandleKeyEventL( // const TKeyEvent& aKeyEvent,TEventCode /*aType*/) // takes care of key event handling // ---------------------------------------------------- // TKeyResponse CscAppUi::HandleKeyEventL( const TKeyEvent & aKeyEvent,TEventCode aType) { if ( ! iTabGroup) { return EKeyWasNotConsumed; } TInt active = iTabGroup -> ActiveTabIndex(); TInt count = iTabGroup -> TabCount(); switch (aKeyEvent.iCode) { case EKeyLeftArrow: if (active) { active -- ; iTabGroup -> SetActiveTabByIndex(active); ActivateLocalViewL(TUid::Uid(iTabGroup -> TabIdFromIndex(active))); } break ; case EKeyRightArrow: if (active + 1 < count) { active ++ ; iTabGroup -> SetActiveTabByIndex(active); ActivateLocalViewL(TUid::Uid(iTabGroup -> TabIdFromIndex(active))); } break ; default : return EKeyWasNotConsumed; break ; } return EKeyWasConsumed; } // ---------------------------------------------------- // CscAppUi::HandleCommandL(TInt aCommand) // takes care of command handling // ---------------------------------------------------- // void CscAppUi::HandleCommandL(TInt aCommand) { switch ( aCommand ) { case EAknSoftkeyBack: case EEikCmdExit: { Exit(); break ; } case EscCmdAppTest: { iEikonEnv -> InfoMsg(_L( " test " )); break ; } // TODO: Add Your command handling code here default : break ; } } // End of File |
核心代码是:
iSimControlView = CSimControlView::NewL(); AddViewL(iSimControlView); /* */ /* */ iCompoundControl = CCompoundControlView::NewL(); AddViewL(iCompoundControl); //SetDefaultViewL(*iCompoundControl); SetDefaultViewL(*iSimControlView); |
这几句,创建一个 view 对像,然后通过 AddViewL 添加,如果去掉 tab 控件的代码,添加一个 view ,则效果和传统开发的效果一样
花了两天的时间终于把自定义控件搞好了,其中遇到不少问题,也都一一解决了,好不容易,又走了一步。
代码下载:http://files.cnblogs.com/zziss/sc.rar
安平2009@原创
qi_jianzhou@126.com