Displaying controls in Symbian exe programs
From Forum Nokia Wiki
If we now wanted to create and display a CCoeControl, we’d need to have a CONE environment (CCoeEnv) as a minimum, as this class is used internally by the control. This makes things easier, given that CCoeEnv, as its name implies, creates a whole environment for us, thus limiting our task to the proper control creation:
#include <coedef.h> // TCoeWinPriority #include <e32base.h> // CTrapCleanup #include <w32std.h> // RWsSession #include <coecntrl.h> // CCoeControl #include <coemain.h> // CCoeEnv class CMyControl : public CCoeControl { public: void ConstructL(const TRect& aRect); private: void Draw(const TRect& aRect) const; }; void CMyControl::ConstructL(const TRect& aRect) { CreateWindowL(); SetRect(aRect); ActivateL(); } void CMyControl::Draw(const TRect& aRect) const { // Just paint it blue CWindowGc& gc = SystemGc(); gc.SetBrushStyle(CGraphicsContext::ESolidBrush); gc.SetBrushColor(KRgbBlue); gc.SetPenStyle(CGraphicsContext::ENullPen); gc.Clear(aRect); } // S60 screen size const TUint screenWidth = 176; const TUint screenHeight = 208; LOCAL_C void ExeMainL() { CCoeEnv::Static()->RootWin().SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront); CMyControl* ctrl = new(ELeave) CMyControl; CleanupStack::PushL(ctrl); ctrl->ConstructL(TRect(0, 0, screenWidth, screenHeight)); ctrl->DrawNow(); CCoeEnv::Static()->WsSession().Flush(); CleanupStack::PopAndDestroy(ctrl); } GLDEF_C TInt E32Main() { #if defined(__WINS__) // WINS already creates environment for us CCoeEnv* coe = CCoeEnv::Static(); #else CCoeEnv* coe = new CCoeEnv; TRAPD(err, coe->ConstructL()); __ASSERT_ALWAYS(!err, User::Panic(_L("EXECTRL"), err)); #endif TRAPD(error, ExeMainL()); __ASSERT_ALWAYS(!error, User::Panic(_L("EXECTRL"), error)); User::After(3*1000*1000); #if !defined(__WINS__) coe->DestroyEnvironment(); #endif return 0; } #if defined(__WINS__) EXPORT_C TInt WinsMain() { E32Main(); User::Exit(0); return KErrNone; } TInt E32Dll(TDllReason) { return KErrNone; } #endif
Note that the emulator creates on our behalf an environment when loading an exedll/epocexe as .app, so we have to avoid creating a new environment on emulator builds, otherwise, we’d get a CONE 2 panic (Environment already exists)
Now moving a step further, we’d like to use existing controls, such as listboxes, dialogs, etc. In most cases, a CONE environment won’t be enough, so we’ll have to resort on the Eikon environment:
#include <coedef.h> // TCoeWinPriority #include <e32base.h> // CTrapCleanup #include <w32std.h> // RWsSession #include <coecntrl.h> // CCoeControl #include <eikenv.h> // CEikonEnv #include <eiktxlbx.h> // CEikTextListBox #include <eiktxlbm.h> // CTextListBoxModel class CMyControl : public CCoeControl { public: void ConstructL(const TRect& aRect); ~CMyControl(); private: void SizeChanged(); TInt CountComponentControls() const; CCoeControl* ComponentControl(TInt aIndex) const; void Draw(const TRect& aRect) const; private: CEikTextListBox* iListBox; }; void CMyControl::ConstructL(const TRect& aRect) { CreateWindowL(); // You may use CAknSingleStyleListBox, etc for Series 60.. iListBox = new(ELeave) CEikTextListBox; iListBox->SetContainerWindowL(*this); // iListBox->SetMopParent(this); iListBox->ConstructL(this); CDesCArray* items = static_cast<CDesCArray*> (iListBox->Model()->ItemTextArray()); _LIT(KItem1, "First"); items->AppendL(KItem1); _LIT(KItem2, "Second"); items->AppendL(KItem2); iListBox->HandleItemAdditionL(); iListBox->SetFocus(ETrue); // iListBox->CreateScrollBarFrameL(); // iListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto); SetRect(aRect); ActivateL(); } CMyControl::~CMyControl() { delete iListBox; } void CMyControl::SizeChanged() { iListBox->SetRect(Rect()); } TInt CMyControl::CountComponentControls() const { return 1; } CCoeControl* CMyControl::ComponentControl(TInt aIndex) const { switch (aIndex) { case 0: return iListBox; default: return 0; } } void CMyControl::Draw(const TRect& aRect) const { CWindowGc& gc = SystemGc(); gc.Clear(aRect); } // S60 screen size const TUint screenWidth = 176; const TUint screenHeight = 208; LOCAL_C void ExeMainL() { CCoeEnv::Static()->RootWin().SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront); CMyControl* ctrl = new(ELeave) CMyControl; CleanupStack::PushL(ctrl); ctrl->ConstructL(TRect(0, 0, screenWidth, screenHeight)); ctrl->DrawNow(); CCoeEnv::Static()->WsSession().Flush(); CleanupStack::PopAndDestroy(ctrl); } GLDEF_C TInt E32Main() { #if defined(__WINS__) // WINS already creates environment for us CEikonEnv* coe = CEikonEnv::Static(); #else CEikonEnv* coe = new CEikonEnv; TRAPD(err, coe->ConstructL()); __ASSERT_ALWAYS(!err, User::Panic(_L("EXECTRL"), err)); #endif TRAPD(error, ExeMainL()); __ASSERT_ALWAYS(!error, User::Panic(_L("EXECTRL"), error)); User::After(3*1000*1000); #if !defined(__WINS__) delete coe; #endif return 0; } #if defined(__WINS__) EXPORT_C TInt WinsMain() { E32Main(); User::Exit(0); return KErrNone; } TInt E32Dll(TDllReason) { return KErrNone; } #endif
The example above shows a pretty simple compound control, consisting of just one lodger control, a text listbox. But to make this a bit more useful, we’d need to receive events (such as key presses) and pass them to the control. The example bellow shows a simple implementation. Actually, it mimics somehow CCoeEnv::ExecuteD() functionality, which basically starts the active scheduler and waits for events from the window server (note that CCoeEnv is a CActive)
LOCAL_C void ExeMainL() { CCoeEnv* coeEnv = CCoeEnv::Static(); coeEnv->RootWin().SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront); CMyControl* ctrl = new(ELeave) CMyControl; CleanupStack::PushL(ctrl); ctrl->ConstructL(TRect(0, 0, screenWidth, screenHeight)); ctrl->DrawNow(); coeEnv->WsSession().Flush(); // Create a basic UI and set control to receive events CMyAppUi* appUi = new(ELeave) CMyAppUi; appUi->SetRootControl(ctrl); coeEnv->SetAppUi(appUi); // takes ownership for (;;) { // Wait synchronously for event TRequestStatus status; coeEnv->WsSession().EventReady(&status); User::WaitForRequest(status); if (status.Int() == KErrNone) { TWsEvent event; coeEnv->WsSession().GetEvent(event); // Check exit key if (event.Key()->iCode == EKeyDevice3) break; // Pass event to control appUi->HandleWsEventL(event, ctrl); } } CleanupStack::PopAndDestroy(ctrl); }
You May Download the examples here:
ExeCtrl.zip (CONE environment)
ExeCtrl.zip (Eikon environment)
Tags: exe, nokia, programming, symbian