一、定义 概述 Symbian OS提供了大量现成的控件,但是有时还不够用。你可以通过从CCoeControl基类派生构造你自己的UI控件。 本例演示如何定义你自己的有一个CEikLabel的简单自定义控件。 派生自CCoeControl 并实现下述基本方法:
MMP文件 下面的库文件是必须的: LIBRARY euser.lib LIBRARY apparc.lib LIBRARY cone.lib LIBRARY eikcore.lib LIBRARY avkon.lib LIBRARY commonengine.lib LIBRARY eikcoctl.lib LIBRARY gdi.lib 头文件 #include <coecntrl.h> #include <eiklabel.h>
class CMyControl : public CCoeControl { public: static CMyControl* NewL(const TRect& aRect,const CCoeControl* aParent=NULL); static CMyControl* NewLC(const TRect& aRect,const CCoeControl* aParent=NULL); virtual ~CMyControl();
public: // from CCoeControl TSize MinimumSize();
private: // from CCoeControl void Draw(const TRect& aRect) const; void SizeChanged();
private: // own methods CMyControl(); void ConstructL(const TRect& aRect,const CCoeControl* aParent = NULL);
private: // data CEikLabel* iStatusText; }; 源代码 CMyControl* CMyControl::NewL(const TRect& aRect,const CCoeControl* aParent) { CMyControl* self = CMyControl::NewLC(aRect,aParent); CleanupStack::Pop(self); return self; }
CMyControl* CMyControl::NewLC(const TRect& aRect,const CCoeControl* aParent) { CMyControl* self = new(ELeave) CMyControl(); CleanupStack::PushL(self); self->ConstructL(aRect,aParent); return self; }
CMyControl::CMyControl() { }
CMyControl::~CMyControl() { // 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 if(aParent == NULL) { CreateWindowL(); } // Use Parent's window else { // This is component in a compound control SetContainerWindowL(*aParent); }
// Initialize component array InitComponentArrayL();
// Create contained controls iStatusText = new (ELeave) CEikLabel; iStatusText->SetContainerWindowL(*this); iStatusText->SetTextL(_L("HelloWorld"));
// Store component to component array Components().AppendLC(iStatusText); CleanupStack::Pop(iStatusText);
SetRect(aRect); // or //SetExtentToWholeScreen(); //NOTE: Can not see CBA buttons
// The application should call this function on // all controls that are not components in a compound control if(aParent == NULL) { ActivateL(); } }
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(); rect.Grow(TSize(2,2)); return rect.Size();
// When using the control in a dialog, set the control size large //return Rect().Size(); }
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 // the control. if (iStatusText) { TRect labelRect(Rect()); labelRect.Shrink(TSize(5,2)); iStatusText->SetRect(labelRect); } }
void CMyControl::Draw(const TRect& /*aRect*/) const { CWindowGc& gc = SystemGc(); gc.SetBrushColor(KRgbBlue); gc.Clear(Rect()); }
使用CCoeControl 自定义控件CMyControl被添加到了MultiViews例子(S60 3rd FP1)中,在.cpp中作如下修改: void CMultiViewsView1::DoActivateL( const TVwsViewId& /*aPrevViewId*/, TUid /*aCustomMessageId*/, const TDesC8& /*aCustomMessage*/) { iControl = CMyControl::NewL(ClientRect()); }
void CMultiViewsView1::DoDeactivate() { if (iControl) { AppUi()->RemoveFromStack(iControl); delete iControl; iControl = NULL; } }
void CMultiViewsView1::HandleSizeChange( TInt aType ) { if( iControl ) { iControl->HandleResourceChange( aType ); if ( aType==KEikDynamicLayoutVariantSwitch ) { TRect rect; AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, rect); iControl->SetRect(rect); } } }
后置条件 CMyControl可以放在另一个CCoeControl里(复合控件),或作为单独的控件而没有父控件。
从资源构造: 概要 这个代码片段演示如何从资源创建CCoeControl。本例扩展了代码片段自定义控件: 定义(一)。 CMyControl::ConstructFromResourceL()用与CMyControl::ConstructL()同样的方式初始化控件,但参数从TResourceReader获得。资源读取器是一个从资源文件流读取字节的工具类;因此,读取必须以同样的顺序且数据大小必须与那些定义在资源结构声明中的相匹配。 MMP 文件 下面的能力(capabilities)和库(libraries)是必须的: LIBRARY bafl.lib //TResourceReader 头文件 添加一个当从资源创建类时被调用的新函数,以及添加BARSREAD.H包含头文件。缺省构造函数CMyControl()应被移至public范围。 #include <BARSREAD.H>
public: CMyControl(); void ConstructFromResourceL(TResourceReader& aReader); 源代码 这段代码为CEikLabel从资源读取文本。 void CMyControl::ConstructFromResourceL(TResourceReader& aReader) { // No parent owner, so create an own window CreateWindowL();
// Initialize component array InitComponentArrayL();
// Create contained controls iStatusText = new (ELeave) CEikLabel; iStatusText->SetContainerWindowL(*this);
// Read label from resource TPtrC label = aReader.ReadTPtrC16(); iStatusText->SetTextL(label);
// Store component to component array Components().AppendLC(iStatusText); CleanupStack::Pop(iStatusText);
// Set component rect to CMultiViewsAppUi::ClientRect() CMultiViewsAppUi* appui = (static_cast<CMultiViewsAppUi*>(iEikonEnv->AppUi())); appui->ClientRect(); if (appui) { SetRect(appui->ClientRect()); }
ActivateL(); } CMyControl部件资源customcontrol.rh文件 CMyControl部件的资源配置参数: STRUCT CUSTOMCONTROL { LTEXT txt; } 资源.rss文件 对Multiviews样例应用资源文件作如下变更: multiviews.rss. // New include that is our own component resource config #include "customcontrol.rh"
// 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 TResourceReader reader; iEikonEnv->CreateResourceReaderLC(reader, R_CUSTOM_CONTROL); iContainer2 = new (ELeave) CMyControl; iContainer2->ConstructFromResourceL(reader); iContainer2->SetRect(ClientRect()); CleanupStack::PopAndDestroy(); // reader 后置条件 CMyControl通过已定义资源参数被创建。
容器控件: 概述 这个代码片段演示如何创建一个拥有自定义控件的容器控件。例子演示如何用一个矩形框聚焦第一个部件及如何改变焦点。 本例扩展已存代码片段自定义控件: 定义(一); 容器控件存储其控件到CCoeControlArray中。 头文件 class CMyContainerControl : public CCoeControl { public: static CMyContainerControl* NewL(const TRect& aRect); static CMyContainerControl* NewLC(const TRect& aRect); virtual ~CMyContainerControl();
private: // from CCoeControl void Draw(const TRect& aRect) const; void SizeChanged();
public: // own methods // NOTE: Transfer ownership to CMyContainerControl void AddControlL(CCoeControl* aControl,TInt aControlId); void UpdateControls();
private: // own methods CMyContainerControl(); void ConstructL(const TRect& aRect); };
源代码 CMyContainerControl* CMyContainerControl::NewL(const TRect& aRect) { CMyContainerControl* self = CMyContainerControl::NewLC(aRect); CleanupStack::Pop(self); return self; }
CMyContainerControl* CMyContainerControl::NewLC(const TRect& aRect) { CMyContainerControl* self = new(ELeave) CMyContainerControl(); CleanupStack::PushL(self); self->ConstructL(aRect); return self; }
CMyContainerControl::CMyContainerControl() { }
CMyContainerControl::~CMyContainerControl() { }
void CMyContainerControl::ConstructL(const TRect& aRect) { // No parent owner, so create an own window CreateWindowL();
// Initialize component array InitComponentArrayL();
SetRect(aRect);
ActivateL(); }
void CMyContainerControl::SizeChanged() { UpdateControls(); }
void CMyContainerControl::UpdateControls() { TPoint position;
// Goes through all components of this container control CCoeControlArray::TCursor cursor = Components().Begin(); CCoeControl* ctrl = NULL; while ((ctrl = cursor.Control<CCoeControl>()) != NULL) { // If control is not visible, do not set it's position if (!ctrl->IsVisible()) { cursor.Next(); continue; }
// Set position ctrl->SetPosition(position);
// Set size TSize size = ctrl->MinimumSize(); size.SetSize(Rect().Width(),size.iHeight); ctrl->SetSize(size);
// Calculate position position.iY += size.iHeight;
// Does control fit to view? if (position.iY >= Rect().iBr.iY) { ctrl->MakeVisible(EFalse); } else { ctrl->MakeVisible(ETrue); }
cursor.Next(); } }
void CMyContainerControl::Draw(const TRect& /*aRect*/) const { CWindowGc& gc = SystemGc(); gc.SetBrushColor(KRgbBlack); gc.Clear(Rect()); }
void CMyContainerControl::AddControlL(CCoeControl* aControl,TInt aControlId) { // NOTE: Transfer ownership of CCoeControl to CMyContainerControl // Add control into container control Components().AppendLC(aControl,aControlId); CleanupStack::Pop(aControl);
// Focus first component if (Components().Count()==1) { aControl->SetFocus(ETrue); }
// Update control's position UpdateControls(); } SizeChanged函数 当CMyContainerControl的大小改变时(例如: 当SetRect()被调用时),部件的位置必须再次计算。 void CMyContainerControl::SizeChanged() { // Sets new position of the components UpdateControls(); } 聚焦部件 对CMyControl部件做如下变更:
void CMyControl::Draw(const TRect& aRect) const { CWindowGc& gc = SystemGc(); gc.SetBrushColor(KRgbBlue); gc.Clear(Rect());
DrawFocusFrame(aRect); |
|