自定义控件
摘自网上:
一、定义
概述
Symbian OS提供了大量现成的控件,但是有时还不够用。你可以通过从CCoeControl基类派生构造你自己的UI控件。
本例演示如何定义你自己的有一个CEikLabel的简单自定义控件。 派生自CCoeControl 并实现下述基本方法:
- 构造
- 布局
- 大小
- 绘制控件
- 被包含的控件(若有的话)
class CMyControl : public CCoeControl
static CMyControl* NewL(const TRect& aRect,const CCoeControl* aParent=NULL);
static CMyControl* NewLC(const TRect& aRect,const CCoeControl* aParent=NULL);
void Draw(const TRect& aRect) const;
void ConstructL(const TRect& aRect,const CCoeControl* aParent = NULL);
CMyControl* CMyControl::NewL(const TRect& aRect,const CCoeControl* aParent)
CMyControl* self = CMyControl::NewLC(aRect,aParent);
CMyControl* CMyControl::NewLC(const TRect& aRect,const CCoeControl* aParent)
CMyControl* self = new(ELeave) CMyControl();
self->ConstructL(aRect,aParent);
// NOTE: Does not delete iStatusText because we do not own it
void CMyControl::ConstructL(const TRect& aRect,const CCoeControl* aParent)
// No owner, so create an own window
// This is component in a compound control
SetContainerWindowL(*aParent);
iStatusText = new (ELeave) CEikLabel;
iStatusText->SetContainerWindowL(*this);
iStatusText->SetTextL(_L("HelloWorld"));
// Store component to component array
Components().AppendLC(iStatusText);
CleanupStack::Pop(iStatusText);
//SetExtentToWholeScreen(); //NOTE: Can not see CBA buttons
// The application should call this function on
// all controls that are not components in a compound control
TSize CMyControl::MinimumSize()
// Get CEikLabel minium size and grow it
// that is this control MinimumSize.
// Custom control also needs a few other methods so it can be laid out
// and drawn. For example, custom controls usually implement MinimumSize(),
// SizeChanged() and Draw() methods.
// When using control in container control, set the minium size very small
TRect rect = iStatusText->MinimumSize();
// When using the control in a dialog, set the control size large
void CMyControl::SizeChanged()
// Responds to size changes to set the size and position of the contents
// of this control. For a simple control this might include text or
// graphics. For a compound control this sets the size and position of the
// component. It has an empty default implementation and should be
// implemented by the CCoeControl-derived class.
// The function is called whenever SetExtent(), SetSize(), SetRect(),
// SetCornerAndSize(), or SetExtentToWholeScreen() are called on
iStatusText->SetRect(labelRect);
void CMyControl::Draw(const TRect& /*aRect*/) const
自定义控件CMyControl被添加到了MultiViews例子(S60 3rd FP1)中,在.cpp中作如下修改:
void CMultiViewsView1::DoActivateL( const TVwsViewId& /*aPrevViewId*/,
const TDesC8& /*aCustomMessage*/)
iControl = CMyControl::NewL(ClientRect());
void CMultiViewsView1::DoDeactivate()
AppUi()->RemoveFromStack(iControl);
void CMultiViewsView1::HandleSizeChange( TInt aType )
iControl->HandleResourceChange( aType );
if ( aType==KEikDynamicLayoutVariantSwitch )
AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, rect);
CMyControl可以放在另一个CCoeControl里(复合控件),或作为单独的控件而没有父控件。
这个代码片段演示如何从资源创建CCoeControl。本例扩展了代码片段自定义控件: 定义(一)。
下面的能力(capabilities)和库(libraries)是必须的:
LIBRARY bafl.lib //TResourceReader
添加一个当从资源创建类时被调用的新函数,以及添加BARSREAD.H包含头文件。缺省构造函数CMyControl()应被移至public范围。
void ConstructFromResourceL(TResourceReader& aReader);
void CMyControl::ConstructFromResourceL(TResourceReader& aReader)
// No parent owner, so create an own window
iStatusText = new (ELeave) CEikLabel;
iStatusText->SetContainerWindowL(*this);
TPtrC label = aReader.ReadTPtrC16();
// Store component to component array
Components().AppendLC(iStatusText);
CleanupStack::Pop(iStatusText);
// Set component rect to CMultiViewsAppUi::ClientRect()
CMultiViewsAppUi* appui = (static_cast<CMultiViewsAppUi*>(iEikonEnv->AppUi()));
CMyControl部件资源customcontrol.rh文件
对Multiviews样例应用资源文件作如下变更: multiviews.rss.
// New include that is our own component resource config
// Defining resource for our component.
RESOURCE CUSTOMCONTROL r_custom_control
txt = STRING_r_custom_control;
STRING_r_custom_control定义在multiviews.rls中.
创建资源读取器,经由缺省构造函数创建部件,然后调用ConstructFromResourceL():
// Creating control from resource
iEikonEnv->CreateResourceReaderLC(reader, R_CUSTOM_CONTROL);
iContainer2 = new (ELeave) CMyControl;
iContainer2->ConstructFromResourceL(reader);
iContainer2->SetRect(ClientRect());
CleanupStack::PopAndDestroy(); // reader
这个代码片段演示如何创建一个拥有自定义控件的容器控件。例子演示如何用一个矩形框聚焦第一个部件及如何改变焦点。
本例扩展已存代码片段自定义控件: 定义(一); 容器控件存储其控件到CCoeControlArray中。
class CMyContainerControl : public CCoeControl
static CMyContainerControl* NewL(const TRect& aRect);
static CMyContainerControl* NewLC(const TRect& aRect);
virtual ~CMyContainerControl();
void Draw(const TRect& aRect) const;
// NOTE: Transfer ownership to CMyContainerControl
void AddControlL(CCoeControl* aControl,TInt aControlId);
void ConstructL(const TRect& aRect);
CMyContainerControl* CMyContainerControl::NewL(const TRect& aRect)
CMyContainerControl* self = CMyContainerControl::NewLC(aRect);
CMyContainerControl* CMyContainerControl::NewLC(const TRect& aRect)
CMyContainerControl* self = new(ELeave) CMyContainerControl();
CMyContainerControl::CMyContainerControl()
CMyContainerControl::~CMyContainerControl()
void CMyContainerControl::ConstructL(const TRect& aRect)
// No parent owner, so create an own window
void CMyContainerControl::SizeChanged()
void CMyContainerControl::UpdateControls()
// Goes through all components of this container control
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
// If control is not visible, do not set it's position
TSize size = ctrl->MinimumSize();
size.SetSize(Rect().Width(),size.iHeight);
if (position.iY >= Rect().iBr.iY)
void CMyContainerControl::Draw(const TRect& /*aRect*/) const
void CMyContainerControl::AddControlL(CCoeControl* aControl,TInt aControlId)
// NOTE: Transfer ownership of CCoeControl to CMyContainerControl
// Add control into container control
Components().AppendLC(aControl,aControlId);
当CMyContainerControl的大小改变时(例如: 当SetRect()被调用时),部件的位置必须再次计算。
void CMyContainerControl::SizeChanged()
// Sets new position of the components
void CMyControl::Draw(const TRect& aRect) const
void CMyControl::DrawFocusFrame(const TRect& aRect) const
// Nothing to draw if not focused
gc.SetPenStyle( CGraphicsContext::ESolidPen );
gc.SetPenSize( TSize(KFocusFrameWidth,KFocusFrameWidth) );
gc.SetBrushStyle( CGraphicsContext::ENullBrush );
gc.SetPenColor( KRgbDarkGray );
gc.DrawRoundRect( aRect, TSize( KFrameRoundRadius, KFrameRoundRadius ) );
CMyContainerControl容器在列表中有一些CMyControl自定义控件。
这个代码片段演示如何添加摁键事件处理到自定义的容器控件以及如何改变所选部件的焦点。
本例扩展已存代码片段自定义控件: 容器控件(三)。查看本文的"参见部分"以了解自定义控件系列的其它代码片段。
给CMyContainerControl部件的头文件添加三个方法以便接收摁键事件和改变焦点。
TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
CMyContainerControl必须加到控件栈中以便接收摁键事件AppUi()->AddToStackL().
iContainerControl = CMyContainerControl::NewL(ClientRect());
// Create control to the compound container
CMyControl* control1 = CMyControl::NewLC(ClientRect(),iContainerControl);
iContainerControl->AddControlL(control1,1);
CleanupStack::Pop(); //control 1
// Add the control to the control stack
AppUi()->AddToStackL(iContainerControl);
TKeyResponse CMyContainerControl::OfferKeyEventL
(const TKeyEvent& aKeyEvent,TEventCode /*aType*/)
DrawNow(); // Draw components again
DrawNow(); // Draw components again
void CMyContainerControl::MoveFocusUp()
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
// Set focus to previous control
break; // First control is already focused
void CMyContainerControl::MoveFocusDown()
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
nextCtrl = cursor.Control<CCoeControl>();
break; // Last control is already focused
CMyContainerControl接受击键事件并显示活动部件焦点。
这个代码片段演示如何给有自定义控件的容器控件添加滚动条,以及如何只显示可见部件并在视图的顶部和底部搜查更多的可视部件。
本例扩展了已存代码片段自定义控件: 聚焦(四)。查看本文的"参见"部分以了解自定义控件系列的其它代码片段。
添加这些方法和成员数据到CMyContainerControl部件的头文件中。
CEikScrollBarFrame* iScrollBarFrame;
TAknDoubleSpanScrollBarModel iHDsSbarModel;
TAknDoubleSpanScrollBarModel iVDsSbarModel;
在CMyContainerControl::ConstructL()中创建滚动条:
iScrollBarFrame = new ( ELeave ) CEikScrollBarFrame( this, NULL );
iScrollBarFrame->CreateDoubleSpanScrollBarsL( ETrue, EFalse );
iScrollBarFrame->SetTypeOfVScrollBar( CEikScrollBarFrame::EDoubleSpan );
iScrollBarFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff,
void CMyContainerControl::UpdateScrollBarFrameL()
TInt controlsHeight = 0; // Height of the controls
TInt height = 0; // This view height
// Calculate components height
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
controlsHeight += ctrl->MinimumSize().iHeight;
// Set teh scrollbar visible if fields do not fit the screen
if( controlsHeight > height &&
iScrollBarFrame->VScrollBarVisibility() ==
iScrollBarFrame->SetScrollBarVisibilityL(
CEikScrollBarFrame::EOff, // horizontal
CEikScrollBarFrame::EOn); // vertical
// Hide the scrollbar if fields fit the screen
else if ( controlsHeight <= height &&
iScrollBarFrame->VScrollBarVisibility() ==
iScrollBarFrame->SetScrollBarVisibilityL(
CEikScrollBarFrame::EOff, // horizontal
CEikScrollBarFrame::EOff); // vertical
iVDsSbarModel.SetScrollSpan(Components().Count());
iVDsSbarModel.SetWindowSize(1);
iVDsSbarModel.SetFocusPosition(iFocusedIndex);
TEikScrollBarFrameLayout layout;
layout.iTilingMode = TEikScrollBarFrameLayout::EInclusiveRectConstant;
iScrollBarFrame->TileL(&iHDsSbarModel,&iVDsSbarModel,rect,rect,layout);
iScrollBarFrame->SetVFocusPosToThumbPos(iVDsSbarModel.FocusPosition());
CMyContainerControl::MoveFocusUpL()移动活动部件焦点,以及若达到屏幕顶部就请求显示更多部件。
void CMyContainerControl::MoveFocusUpL()
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
// Set focus to previous control
if (iFocusedIndex > 0 && !prevCtrl->IsVisible())
break; // First control is already focused
CMyContainerControl::MoveFocusDownL()移动活动部件焦点,以及若焦点到达屏幕底部就请求显示更多部件。
void CMyContainerControl::MoveFocusDownL()
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
if (ctrl && ctrl->IsFocused())
nextCtrl = cursor.Control<CCoeControl>();
break; // Last control is already focused
void CMyContainerControl::ShowNextItem()
// Goes throught all components of this container control
CCoeControlArray::TCursor cursor = Components().Begin();
while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
if (ctrl && ctrl->IsFocused())
TSize size = ctrl->MinimumSize();
size.SetSize(Rect().Width(),size.iHeight);
if ((position.iY + size.iHeight) >= Rect().iBr.iY)
focusedFound = EFalse; // Let rest components be MakeVisible(EFalse)
// Store position of last component
void CMyContainerControl::ShowPrevItem()
// Goes throught all components from the last -> to the first one
CCoeControlArray::TCursor cursor = Components().End();
ctrl = cursor.Control<CCoeControl>();
if (ctrl && ctrl->IsFocused())
TSize size = ctrl->MinimumSize();
size.SetSize(Rect().Width(),size.iHeight);
if ((position.iY) <= Rect().iTl.iY-2)
focusedFound = EFalse; // Let rest components be MakeVisible(EFalse)
自定义控件有滚动条演示视图中焦点的位置。当达到视图的底部或顶部将显示更多部件。
这个例子扩展了自定义控件例子自定义控件: 定义(一)。在本代码片段,CMyControl自定义控件添加到CAknDialog。
定义一个实现CEikDialog::CreateCustomControlL()方法的自定义对话框。
CMyDialog对话框资源在multiviews.rss中:
flags = EAknDialogGenericFullScreen;
buttons = R_AVKON_SOFTKEYS_OK_BACK;
// CMyControl custom control type (defined in multiviews.hrh)
// CMyControl custom control id (defined in multiviews.hrh)
txt = STRING_r_custom_control_dialog;
CMyDialog 对话框头文件定义了所需的CreateCustomControlL()方法:
class CMyDialog : public CAknDialog
SEikControlInfo CreateCustomControlL(TInt aControlType);
CMyDialog* dlg = new (ELeave) CMyDialog;
return dlg->ExecuteLD(R_DIALOG);
void CMyDialog::PreLayoutDynInitL()
CMyControl* control = (CMyControl*)Control(KMyCustomCtlId);
// TODO: tune components if needed
SEikControlInfo CMyDialog::CreateCustomControlL(TInt aControlType)
controlInfo.iTrailerTextId = 0 ;
// CMyControl custom control type (defined in multiviews.hrh)
controlInfo.iControl = new(ELeave)CMyControl();
// CMyControl custom control type in resource file
enum {KMyCustomCtl = KAknCtLastControlId };
// CMyControl custom control id in resource file