symbian 自定义控件
学习了一下自定义控件,及复合控件,自定义控件从 CCoeControl 继承过来,要实现 CCoeControl 的
void SizeChange() , void Draw(const TRect& aRect,const CCoeControl* aParent) 这两个虚方法,
自定义控件要用两阶构造方法,所以要添加 NewL 及 NewLC 方法,由于 Draw 方法需要用到两个参数,所以
在 NewL 时把两个参数要传入,下面是自定义控件的代码
头文件
#include <coecntrl.h> 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 ); }; |
代码文件
#include "SimControl.h" ////////////////////////////////////////////////////////////////////// // 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(); } |
在传统模式下调用代码
// 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 ,则效果和传统开发的效果一样
花了两天的时间终于把自定义控件搞好了,其中遇到不少问题,也都一一解决了,好不容易,又走了一步。
代码下载:https://files.cnblogs.com/zziss/sc.rar
安平2009@原创
qi_jianzhou@126.com