Tak jak pisałem na forum Symbianos.pl i z obserwacji początkujących największym problemem jest zrozumienie kodu aplikacji GUI dla S60 . Jest to specyficzne ze względu na to że użytkownicy Carbide.C++ już od razu chcą robić aplikacje w Designerze UI bez wcześniejszego teoretycznego przygotowania. Carbide.C++ to tylko narzędzie które trzeba dostosować do własnych potrzeb programistycznych. W praktyce to warto głównie traktować jako edytor programistyczny dla zaawansowanych programistów Symbiana.
W tej sytuacji przyjrzymy się jak powstaje aplikacja na Symbiana S60. Na początek pracujemy na kodzie w jakimś szybkim lekkim edytorze programistycznym na przykład Notepad++
Zrobimy na początek główny katalog PierwszaAplikacja z podkatalogami data, group, gfx, inc, src, sis.
Wchodzimy do katalogu inc i musimy mieć na początek identyfikator aplikacji
Z jednej strony ustalamy zmienną _UID3 w tym celu żeby w całej aplikacji potem móc zaplanować też nazewnictwo aplikacji i strukturę plików
z drugiej strony istotne jest fakt że typ ennumeratywny THelloWorldIds przechowuje informacje o poleceniach jakie będą używane w menu.
/*
============================================================================
Name : Pierwsza Aplikacja.hrh
Author : Michał Małaj
Copyright : LGPL
Description : To jest plik deklaracji identyfikatora aplikacji.
Ten plik będzie dołączany do plików zasobów podczas kompilacji.
============================================================================
*/
#ifndef __PIERWSZAAPLIKACJA_HRH__
#define __PIERWSZAAPLIKACJA_HRH__
#define _UID3 0xE82211C4
// Wyliczenie identyfikatorów dla poleceń wykonywanych z AVKONA
enum TPierwszaAplikacjaIds
{
ECommand1 = 0x6001, // pierwsza wartość musi rozpoczynać się od wartości
ECommand2
};
#endif // __PIERWSZAAPLIKACJA_HRH__
Następnie w folderze data robimy plik MojaAplikacja.rls jest to plik który zawiera informacje o innych plikach lokalizacyjnych z tłumaczeniami pod określony język, bądź inne informacje które mogą zmieniać się w przypadku zastosowania odpowiedniej wersji językowej.
/*
============================================================================
Name : PierwszaAplikacja.rls
Author : Michał Małaj
Copyright : LGPL
Description : To jest plik lokalizacyjny dla programu PierwszaAplikacja.
Ten plik zawiera informacje dla kompilatora żeby zrobił z plików
lokalizacyjnych wersje zasobów w odpowiednim języku dla wersji Symbiana.
============================================================================
*/
#ifdef LANGUAGE_SC
#include "PierwszaAplikacja_01.rls" // default U.K. English
#elif defined LANGUAGE_01
#include "PierwszaAplikacja_01.rls" // U.K. English
#elif defined LANGUAGE_27
#include "PierwszaAplikacja_27.rls" // Polish
#endif
// End of File
Istotne jest to że kod w pliku zasobów dla języka polskiego musi być kodowany w UTF-8. O tym kompilator zostaje poinformowany przez zamieszczenie makra CHARACTER_SET UTF8. Inne pliki mają być kodowane po ASCII (w praktyce i tak programujemy pod kodowanie systemu operacyjnego Windows) Oto wersja z tłumaczeniem dla języka polskiego.
/* ============================================================================
Name : PierwszaAplikacja_27.rls
Author : Michał Małaj Copyright : LGPL
Description : To jest plik lokalizacyjny w języku polskim dla programu PierwszaAplikacja
============================================================================
*/
CHARACTER_SET UTF8
// LOCALISATION STRINGS
// Tekst nagłówka aplikacji.
#define qtn_caption_string "Pierwsza Aplikacja"
// Pierwsza pozycja w menu "Options"
#define qtn_command1 "Wiadomość"
// kiedy użytkownik będzie wywoływać polecenie z menu,
// poniższy tekst zostanie pokazany
#define qtn_command1_text "Witaj Świecie!"
// trzeba podać miejsce pliku gdzie będzie przechowywany zasób
#define qtn_loc_resource_file_1 "\\resource\\apps\\PierwszaAplikacja_0xE82211C4"
// End of File
Poniżej zamieszczamy kod dla wersji w języku angielskim.
/*
============================================================================
Name : PierwszaAplikacja_01.rls
Author : Michał Małaj
Copyright : LGPL
Description : To jest plik lokalizacyjny w języku angielskim
============================================================================
*/
// Tekst nagłówka aplikacji.
#define qtn_caption_string "First Application"
// Pierwsza pozycja w menu "Options"
#define qtn_command1 "Message"
// kiedy użytkownik będzie wywoływał polecenie z menu,
// poniższy tekst zostanie pokazany
#define qtn_command1_text "Hello World!"
// trzeba podać miejsce pliku gdzie będzie przechowywany zasób
#define qtn_loc_resource_file_1 "\\resource\\apps\\PierwszaAplikacja_0xE82211C4"
// End of File
Teraz robimy plik zasobów MojaAplikacja.rss, który tak naprawdę definiuje strukturę menu w aplikacji.
/*
============================================================================
Name : PierwszaAplikacja.rss
Author : Michał Małaj
Copyright : LGPL
Description : Ten plik zawiera wszystkie dane zasobów interfejsu użytkownika
potrzebne dla programu Pierwsza Aplikacja.
============================================================================
*/
// Identyfikator zasobu
NAME PIER // jest czteroznakowy
// INCLUDES
#include <eikon.rh>
#include <avkon.rsg>
#include <avkon.rh>
#include <appinfo.rh>
// potrzebne są dane do wyliczania poleceń w programie
#include "PierwszaAplikacja.hrh"
// dołączamy plik zasobów z przetłumaczonym wyrażeniami
#include "PierwszaAplikacja.rls"
// DEFINICJE ZASOBÓW
// -----------------------------------------------------------------------------
//
// Określamy sygnaturę pliku z zasobami
//
// -----------------------------------------------------------------------------
//
RESOURCE RSS_SIGNATURE
{
}
// -----------------------------------------------------------------------------
//
// Domyślna nazwa dokumentu AVKONA
//
// -----------------------------------------------------------------------------
//
RESOURCE TBUF r_default_document_name
{
buf="PIER";
}
// -----------------------------------------------------------------------------
//
// Określamy strukturę menu i klawiszy CBA.
//
// -----------------------------------------------------------------------------
//
RESOURCE EIK_APP_INFO
{
menubar = r_menubar;
cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT;
}
// -----------------------------------------------------------------------------
//
// Zasób odpowiadający za główne menu
// r_menubar
//
//
// -----------------------------------------------------------------------------
//
RESOURCE MENU_BAR r_menubar
{
titles =
{
MENU_TITLE { menu_pane = r_menu; }
};
}
// -----------------------------------------------------------------------------
//
// r_menu
// Zasób za menu "Opcje"
//
// -----------------------------------------------------------------------------
//
RESOURCE MENU_PANE r_menu
{
items =
{
// dodajemy nową pozycję w menu Opcje
MENU_ITEM
{
command = ECommand1;
txt = qtn_command1;
}
};
}
// -----------------------------------------------------------------------------
//
// Zasoby dla komunikatów
//
// -----------------------------------------------------------------------------
//
RESOURCE TBUF32 r_caption_string { buf=qtn_caption_string; }
RESOURCE TBUF r_command1_text { buf=qtn_command1_text; }
// ----------------------------------------------------------------------------
//
// zasób odpowiadający za wersje lokalizacyjne i
// za grafikę - r_localisable_app_info
//
// ----------------------------------------------------------------------------
//
RESOURCE LOCALISABLE_APP_INFO r_localisable_app_info
{
short_caption = qtn_caption_string;
caption_and_icon =
CAPTION_AND_ICON_INFO
{
caption = qtn_caption_string;
number_of_icons = 1;
icon_file = "\\resource\\apps\\PierwszaAplikacja_0xE82211C4.mif";
};
}
// End of File
Jak widać plik zasobów już wymaga ustalenia co do informacji o strukturze menu i jak odnośnie informacji o ikonie wyświetlanej podczas działania aplikacji. Pliki o rozszerzeniu *.mif są plikami, które zawierają wszystkie odpowiednie pliki graficzne z których zasób może skorzystać.
Po kompilacji pliku zasobu plik ten przyjmuje nazwę MojaAplikacja.rsg
Aby w przyszłości nie było problemów z obsługą różnych wersji plików zasobów warto tworzyć unikalną nazwę w oparciu o UID3 czyli plik może nazywać się MojaAplikacja_0x082DDBA4.rsg
Na koniec trzeba jeszcze zrobić plik zasobów dla instalatora, tak żeby instalator wiedział jak uruchomić naszą aplikację i wyświetlił odpowiednie informacje w folderze instalacje.
/*
============================================================================
Name : PierwszaAplikacja_reg.rss
Author : Michał Małaj
Copyright : LGPL
Description : ten plik zaweira zasób potrzebny dla instalatora.
============================================================================
*/
#include "PierwszaAplikacja.hrh"
#include "PierwszaAplikacja.rls"
#include <appinfo.rh>
#include <PierwszaAplikacja_0xE82211C4.rsg>
UID2 KUidAppRegistrationResourceFile
UID3 _UID3
RESOURCE APP_REGISTRATION_INFO
{
app_file="PierwszaAplikacja_0xE82211C4";
localisable_resource_file = qtn_loc_resource_file_1;
localisable_resource_id = R_LOCALISABLE_APP_INFO;
embeddability=KAppNotEmbeddable;
newfile=KAppDoesNotSupportNewFile;
}
Teraz zajmiemy się tworzeniem i poznawaniem API szablonu aplikacji UI
Jest określona hierarchia zależności API dla graficznego interfejsu.
Nasza aplikacja jest pochodną frameworka UI Avkon wiec najpierw musimy określić co ma być uruchomione przez ten framework, więc w folderze inc mamy pliki nagłówkowe definiujące API
/*
============================================================================
Name : PierwszaAplikacjaApplication.h
Author : Michał Małaj
Copyright : LGPL
Description : Deklaracje głównej klasy aplikacji
============================================================================
*/
#ifndef __PIERWSZAAPLIKACJAAPPLICATION_H__
#define __PIERWSZAAPLIKACJAAPPLICATION_H__
// Zawiera inne deklaracje
#include <aknapp.h>
// z tego pliku pobierany będzie identyfikator aplikacji
#include "PierwszaAplikacja.hrh"
// UID dla aplikacji ;
// to powinno być tym samym identyfikatorem który będzie w pliku mmp.
const TUid KUidPierwszaAplikacjaApp =
{
_UID3
};
// Deklaracja Klasy
/**
* Klasa CPierwszaAplikacjaApplication
* Dostarcza fabrykę do tworzenia obiektu dokumentu AVKON
* Instancja klasy CPierwszaAplikacjaApplication jest
* obsługiwana przez klasy serwera aplikacyjnego AVKON
*/
class CPierwszaAplikacjaApplication : public CAknApplication
{
public:
// publiczne składowe z klasy bazowej
/**
* Zmiennia AppDllUid.
* @return Zwraca identyfikator UID aplikacji (KUidPierwszaAplikacjaApp).
*/
TUid AppDllUid() const;
protected:
// składowe chronione
/**
* From CApaApplication, CreateDocumentL.
* Tworzy obiekt dokumentu AVKONA CPierwszaAplikacjaDocument
* Zwrócoy wskażnik nie jest już zarządzany przez obiekt
* CPierwszaAplikacjaApplication
* @return Zwaraca wskażnik do utworzonrgo dokumentu AVKONA
*/
CApaDocument* CreateDocumentL();
};
#endif
// __PIERWSZAAPLIKACJAAPPLICATION_H__
// End of File
Nasza aplikacja więc najpierw pobiera identyfikator UID i tworzy dokument AVKON.
/*
============================================================================
Name : PierwszaAplikacjaDocument.h
Author : Michał Małaj
Copyright : LGPL
Description : Deklaracja klasy dokumentu AVKON
============================================================================
*/
#ifndef __PIERWSZAAPLIKACJADOCUMENT_h__
#define __PIERWSZAAPLIKACJADOCUMENT_h__
// INCLUDES
#include <akndoc.h>
// Deklarujemy jakie klasy będą używane w tym pliku
class CPierwszaAplikacjaAppUi;
class CEikApplication;
// Deklaracja klasy
/**
* Klasa CPierwszaAplikacjaDocument.
* Instancja klasy CPierwszaAplikacjaDocument jest pochodną (dziedziczy)
* od obiektów Document z frammeworka AVKON
*/
class CPierwszaAplikacjaDocument : public CAknDocument
{
public:
// Konstruktor i destruktor
/**
* NewL.
* Podwójny konstruktor
* Tworzymy dokument AVKONA dla aplikacji AVKON używając
* mechanizmu podwójnego konstruktora i
* zwraca wskaźnik dla utworzonego obiektu
* @param parametrem ma być zmienna aApp typu CEikApplication
* @return zwraca wskaźnik do utworzonej instancji obiektu
* CPierwszaAplikacjaDocument.
*/
static CPierwszaAplikacjaDocument* NewL(CEikApplication& aApp);
/**
* NewLC.
* Tworzymy dokument AVKONA dla aplikacji AVKON używając
* mechanizmu podwójnego konstruktora i
* zwraca wskaźnik dla utworzonego obiektu
* @param parametrem ma być zmienna aApp typu CEikApplication
* @return zwraca wskaźnik do utworzonej instancji obiektu
* CPierwszaAplikacjaDocument.
*/
static CPierwszaAplikacjaDocument* NewLC(CEikApplication& aApp);
/**
* ~CPierwszaAplikacjaDocument
* Wirtualny destruktor.
*/
virtual ~CPierwszaAplikacjaDocument();
public:
// Składowe z klasy bazowej CAknDocument
/**
* CreateAppUiL
* From CEikDocument, CreateAppUiL.
* Tworzy obiekt CPierwszaAplikacjaAppUi i zwraca wskaźnik do tego miejsca.
* Za ten obiekt odpowiada framework Uikon (abstrakcyjny interfejs).
* @return zwraca wskaźnik do utworzonej instancji obiektu AppUi.
*/
CEikAppUi* CreateAppUiL();
private:
// Konstruktor
/**
* ConstructL
* Drugofazowy kontruktor
*/
void ConstructL();
/**
* CPierwszaAplikacjaDocument.
* Domyślny konstruktor C++
* @param paratmetrem jest obiekt aplikacji tworzony przez
* ten document AVKONA
*/
CPierwszaAplikacjaDocument(CEikApplication& aApp);
};
#endif // __PIERWSZAAPLIKACJADOCUMENT_h__
// End of File
Warto zwrócić uwagę na podwójny konstruktor i jak nazewnictwo klas. Przyrostek C oznacza że klasa będzie tworzona na stercie, w praktyce nie wiemy ile pamięci będzie zawierać, końcówka L informuje że dana metoda może zgłosić problem podczas działania a jak to wystąpi to może wywołać "panikę" i zamknąć całą aplikację. Jak zauważyć można było że powyższa deklaracja klasy wymaga podania z jakich deklaracji innej klasy się korzysta
/*
============================================================================
Name : PierwszaAplikacjaAppUi.h
Author : Michał Małaj
Copyright : LGPL
Description : Deklarujemy klasę UI.
============================================================================
*/
#ifndef __PIERWSZAAPLIKACJAAPPUI_h__
#define __PIERWSZAAPLIKACJAAPPUI_h__
// INCLUDES
#include <aknappui.h>
// Klasa używana w tej deklaracji
// wiec trzeba poinformować kompilator że ma brać pod uwagę
// klasy które są potrzebne
// Ta klasa odpowiada za to co będzie brane w widoku UI
class CPierwszaAplikacjaAppView;
//
/**
* Klasa UI CPierwszaAplikacjaAppUi
* Odpowiada za interakcję użytkownika poprzez interfejs UI i
* komunikaty z obsługujących klas
*
*/
class CPierwszaAplikacjaAppUi : public CAknAppUi
{
public:
// Konstruktory i destruktory
/**
* ConstructL.
* Drugofazowy konstruktor
*/
void ConstructL();
/**
* CPierwszaAplikacjaAppUi.
* Domyślny konstruktor C++ to jest potrzebne
* z powodu sposobu tworzenia AppUi
*
*/
CPierwszaAplikacjaAppUi();
/**
* ~CPierwszaAplikacjaAppUi.
* Wirtualny destruktor
*/
virtual ~CPierwszaAplikacjaAppUi();
private:
// Funkcje z klasy bazowej
/**
* From CEikAppUi, HandleCommandL.
* Funkcja która obsługuje polecenia
* @param aCommand numer polecenia.
*/
void HandleCommandL(TInt aCommand);
/**
* HandleStatusPaneSizeChange.
* Wywoływana przez framework kiedy zmienia się rozmiar wyświetlacza
*/
void HandleStatusPaneSizeChange();
private:
// Dane
/**
* Widok aplikacji
* Za nią odpowiada klasa CPierwszaAplikacjaAppUi
*/
CPierwszaAplikacjaAppView* iAppView;
};
#endif // __PIERWSZAAPLIKACJAAPPUI_h__
// End of File
Jak widać obsługa konstrukcji praktycznie opiera się na kompozycji niż dziedziczeniu - dziedziczy się biblioteki odpowiedzialne za UI natomiast sami odpowiadamy za działanie naszej aplikacji. Ta deklaracja wskazuje na to że my sami odpowiadamy za obsługę menu i jak za załadowanie widoku. Poniżej kod deklaracji widoku który jest kontrolką ( bo dziedziczy od CCoeControl) która może aplikacja sobie załadować.
/*
============================================================================
Name : PierwszaAplikacjaAppView.h
Author : Michał Małaj
Copyright : LGPL
Description : Deklarujemy klasę widoku dla aplikacji
============================================================================
*/
#ifndef __PIERWSZAAPLIKACJAAPPVIEW_h__
#define __PIERWSZAAPLIKACJAAPPVIEW_h__
// pobieramy nagłówkowy odpowiedzialny za kontrolki
#include <coecntrl.h>
// Deklaracja klasy
class CPierwszaAplikacjaAppView : public CCoeControl
{
public:
// Nowe składowe
/**
* NewL.
* Dwufazozwy konstruktor.
* Tworzy obiekt CPierwszaAplikacjaAppView, który będzie siebie
* rysował do obszaru wyznaczonego przez zmienną aRect.
* @param aRect Prostokątny obszar który ma być narysowany
* @return zwraca wskaźnik do utworzonej instancji CPierwszaAplikacjaAppView.
*/
static CPierwszaAplikacjaAppView* NewL(const TRect& aRect);
/**
* NewLC.
* Dwufazozwy konstruktor.
* Tworzy obiekt CPierwszaAplikacjaAppView, który będzie siebie rysował do
* obszaru wyznaczonego przez zmienną aRect.
* @param aRect - prostokątny obszar który ma być narysowany
* @return - zwraca wskaźnik do utworzonej instancji CPierwszaAplikacjaAppView.
*/
static CPierwszaAplikacjaAppView* NewLC(const TRect& aRect);
/**
* ~CPierwszaAplikacjaAppView
* Wirtualny destruktor
*/
virtual ~CPierwszaAplikacjaAppView();
public:
// Zawiera składowe z bazowej klasy
/**
* From CCoeControl, Draw
* Rysuje CPierwszaAplikacjaAppView na ekranie.
* @param aRect obszar prostokątny który ma być przerysowany
*/
void Draw(const TRect& aRect) const;
/**
* From CoeControl, SizeChanged.
* Wirtualna metoda wywoływana przez framework kiedy
* rozmiar wyświetlania zmienia się
*/
virtual void SizeChanged();
/**
* From CoeControl, HandlePointerEventL.
* Wywołuje przez framework kiedy ktoś obsługuje dotyk
* Ta metoda jest zgodna z S60 3 edycji ale nie wykonywana
* @param aPointerEvent pobiera informację o tym gdzie kto kliknął.
*/
virtual void HandlePointerEventL(const TPointerEvent& aPointerEvent);
private:
// Konstruktory
/**
* ConstructL
* Drugi konstruktor obiektu
* CPierwszaAplikacjaAppView.
* @param aRect Obszar który ma być przerysowany
*/
void ConstructL(const TRect& aRect);
/**
* CPierwszaAplikacjaAppView.
* Domyślny konstruktor C++.
*/
CPierwszaAplikacjaAppView();
};
#endif // __PIERWSZAAPLIKACJAAPPVIEW_h__
// End of File
Zazwyczaj kod aplikacji jest taki że po plikach z deklaracją trzeba napisać ich implementacje. Pliki implementacji trzymamy w folderze src
Tak naprawdę całą aplikacja zostaje uruchomiona przez metodę E32Main() w pliku
PierwszaAplikacja.cpp
/*
============================================================================
Name : PierwszaAplikacja.cpp
Author : Michał Małaj
Copyright : LGPL
Description : Główna klasa do uruchomienia
============================================================================
*/
// INCLUDE FILES
#include <eikstart.h>
#include "PierwszaAplikacjaApplication.h"
LOCAL_C CApaApplication* NewApplication()
{
return new CPierwszaAplikacjaApplication;
}
GLDEF_C TInt E32Main()
{
return EikStart::RunApplication(NewApplication);
}
Tak więc ten kod uruchamia nową instancję klasy CPierwszaAplikacjaApplication a co za tym idzie ta instancja, utworzy następnie instancję klasy CPierwszaAplikacjaDocument, który uruchomi z kolei instancję klasy CPierwszaAplikacjaAppUi odpowiedzialną za interfejs UI, a ta klasa uruchomi instancję klasy CPierwszaAplikacjaAppView z widokiem z kontrolkami w samym UI.
/*
============================================================================
Name : PierwszaAplikacjaDocument.cpp
Author : Michał Małaj
Copyright : LGPL
Description : Implementacja klasy dokumentu CPierwszaAplikacjaDocument
============================================================================
*/
// INCLUDE FILES
#include "PierwszaAplikacjaAppUi.h"
#include "PierwszaAplikacjaDocument.h"
// ============================ Składowe funkcje ===============================
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaDocument::NewL()
// Dwufazowy konstruktor
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaDocument* CPierwszaAplikacjaDocument::NewL(CEikApplication& aApp)
{
//wywołujemy siebie samego
CPierwszaAplikacjaDocument* self = NewLC(aApp);
//wysyłamy na stos
CleanupStack::Pop(self);
//zwracamy siebie samą
return self;
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaDocument::NewLC()
// Dwufazowy konstruktor
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaDocument* CPierwszaAplikacjaDocument::NewLC(CEikApplication& aApp)
{
// Tworzymy instancję obiektu i rzutując go jako typ ELeave
CPierwszaAplikacjaDocument* self = new (ELeave) CPierwszaAplikacjaDocument(aApp);
// wrzucamy go na stos obiektów typu Leave
CleanupStack::PushL(self);
// wykonujemy metodę dla tego obiektu
self->ConstructL();
// zwracamy siebie samą
return self;
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaDocument::ConstructL()
// To jest drugofazowy konstruktor może obsłużyć
// problemy w tworzeniu instancji
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaDocument::ConstructL()
{
// żadna implementacja jest wymagana,
// bo podczas wycieku nie powinny być
// wykonywane dodatkowe obliczenia
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaDocument::CPierwszaAplikacjaDocument()
// Domyślny konstruktor C++
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaDocument::CPierwszaAplikacjaDocument(CEikApplication& aApp) : CAknDocument(aApp)
{
// Nie wymaga implementacji
}
// ---------------------------------------------------------------------------
// CPierwszaAplikacjaDocument::~CPierwszaAplikacjaDocument()
// Dekonstruktor
// ---------------------------------------------------------------------------
//
CPierwszaAplikacjaDocument::~CPierwszaAplikacjaDocument()
{
// nie wymaga implementacji
}
// ---------------------------------------------------------------------------
// CPierwszaAplikacjaDocument::CreateAppUiL()
// Tworzymy nowy obiekt CreateAppUi.
// ---------------------------------------------------------------------------
//
CEikAppUi* CPierwszaAplikacjaDocument::CreateAppUiL()
{
// Tworzymy interfejs użytkownika aplikacji i zwracamy wskaźnik do tego
// framework UiKon przejmuje odpowiedzialność za ten obiekt
return new (ELeave) CPierwszaAplikacjaAppUi;
}
// End of File
Celem dokumentu AVKONA jest pilnowanie integralności aplikacji, bo ta klasa trzyma dostęp do UID aplikacji. Logikę aplikacji zazwyczaj zamieszczamy w pliku
PierwszaAplikacjaAppUi.cpp
/*
============================================================================
Name : PierwszaAplikacjaAppUi.cpp
Author : Michał Małaj
Copyright : LGPL
Description : Implementacja klasy CPierwszaAplikacjaAppUi
============================================================================
*/
// INCLUDE FILES
#include <avkon.hrh>
#include <aknmessagequerydialog.h>
#include <aknnotewrappers.h>
#include <stringloader.h>
#include <f32file.h>
#include <s32file.h>
#include <hlplch.h>
#include <PierwszaAplikacja_0xE82211C4.rsg>
#include "PierwszaAplikacja.hrh"
#include "PierwszaAplikacja.pan"
#include "PierwszaAplikacjaApplication.h"
#include "PierwszaAplikacjaAppUi.h"
#include "PierwszaAplikacjaAppView.h"
// ============================ Składowe ===============================
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppUi::ConstructL()
// Drugofazowy konstruktor
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppUi::ConstructL()
{
// Inicjalizacja API UI z obsługą zastosowanego motywu
BaseConstructL(CAknAppUi::EAknEnableSkin);
// Tworzymy obiekt widoku
iAppView = CPierwszaAplikacjaAppView::NewL(ClientRect());
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppUi::CPierwszaAplikacjaAppUi()
// Domyślny konstruktor C++ nie może zawierać dowolnego kodu
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaAppUi::CPierwszaAplikacjaAppUi()
{
// Nie wymaga implementacji
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppUi::~CPierwszaAplikacjaAppUi()
// dekonstruktor sprząta też po widoku
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaAppUi::~CPierwszaAplikacjaAppUi()
{
if (iAppView)
{
delete iAppView;
iAppView = NULL;
}
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppUi::HandleCommandL()
// Obsługa poleceń menu
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppUi::HandleCommandL(TInt aCommand)
{
switch (aCommand)
{
case EEikCmdExit:
case EAknSoftkeyExit:
Exit();
break;
case ECommand1:
{
// Ładujemy ciąg znaków z pliku zasobów i wyświetlamy go
HBufC* textResource = StringLoader::LoadLC(R_COMMAND1_TEXT);
CAknInformationNote* informationNote;
informationNote = new (ELeave) CAknInformationNote;
// pokazujemy okno dialogowe informacyjne z tekstem z
// załadowanym z treścią z StringLoader.
informationNote->ExecuteLD(*textResource);
// wyrzucamy HBuf z CleanUpStack i niszczymy to z pamięci
CleanupStack::PopAndDestroy(textResource);
}
break;
default:
// gdy wybierze się inne polecenie niż te które
// mamy opisane to zamykamy aplikację
Panic(EPierwszaAplikacjaUi);
break;
}
}
// -----------------------------------------------------------------------------
// Wywoływane przez framework kiedy zmieni sie położenie rozmiarów.
// Przekazuje nowy obszar rozmiaru aplikacji do AppView.
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppUi::HandleStatusPaneSizeChange()
{
iAppView->SetRect(ClientRect());
}
// End of File
Do tego jeszcze dochodzi plik klasy z widokiem
/*
============================================================================
Name : PierwszaAplikacjaAppView.cpp
Author : Michał Małaj
Copyright : LGPL
Description : Implementacja widoku aplikacji.
============================================================================
*/
// INCLUDE FILES
#include <coemain.h>
#include "PierwszaAplikacjaAppView.h"
// ============================ Składowe ===============================
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::NewL()
// Dwufazowy konstruktor
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaAppView* CPierwszaAplikacjaAppView::NewL(const TRect& aRect)
{
CPierwszaAplikacjaAppView* self = CPierwszaAplikacjaAppView::NewLC(aRect);
CleanupStack::Pop(self);
return self;
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::NewLC()
// Dwufazowy konstruktor
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaAppView* CPierwszaAplikacjaAppView::NewLC(const TRect& aRect)
{
CPierwszaAplikacjaAppView* self = new (ELeave) CPierwszaAplikacjaAppView;
CleanupStack::PushL(self);
self->ConstructL(aRect);
return self;
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::ConstructL()
// Drugi konstruktor może pozwolić na wywołanie "paniki"
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppView::ConstructL(const TRect& aRect)
{
// wywołujemy metodę na tworzenie okna w tej aplikacji
CreateWindowL();
// ustawiamy rozmiary okna
SetRect(aRect);
// aktywujemy okno, które przerysowane na wyświetlaczu
ActivateL();
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::CPierwszaAplikacjaAppView()
// Domyślny konstruktor C++ nie zawiera kodu
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaAppView::CPierwszaAplikacjaAppView()
{
// Brak kodu
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::~CPierwszaAplikacjaAppView()
// Dekonstruktor
// -----------------------------------------------------------------------------
//
CPierwszaAplikacjaAppView::~CPierwszaAplikacjaAppView()
{
// Brak kodu
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::Draw()
// Przerysowujemy wyświetlać
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppView::Draw(const TRect& /*aRect*/) const
{
// pobieramy kontekst graficzny
CWindowGc& gc = SystemGc();
// pobieramy rozmiary do przerysowania
// rysujemy na danym obszarze
TRect drawRect(Rect());
// Czyścimy kontekst z pamięci (a zostaje widoczny na wyświetlaczu
gc.Clear(drawRect);
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::SizeChanged()
// Zostanie to wywołane przez framework kiedy rozmiar widoku zmieni się
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppView::SizeChanged()
{
DrawNow();
}
// -----------------------------------------------------------------------------
// CPierwszaAplikacjaAppView::HandlePointerEventL()
// Called by framework to handle pointer touch events.
// Note: although this method is compatible with earlier SDKs,
// it will not be called in SDKs without Touch support.
// -----------------------------------------------------------------------------
//
void CPierwszaAplikacjaAppView::HandlePointerEventL(
const TPointerEvent& aPointerEvent)
{
// Call base class HandlePointerEventL()
CCoeControl::HandlePointerEventL(aPointerEvent);
}
// End of File
Teraz napiszemy przygotujemy grafikę dla ikonki aplikacji. robimy ją w formacie SVG-T w folderze gfx. Pozostaje też zrobienie pliku graficznego HelloWorld.svg w tym folderze. Następnie trzeba będzie napisać kod skryptu dla kompilatora aby kompilator zmienił to w format *.mif. Plik skryptu icons.mk dla kompilatora znajduje się w podfolderze groups
# ============================================================================
# Name : icons.mk
#
# Description: to jest skrypt dla kompilatora to tworzenia pliku z mif z ikonką.
#
# ============================================================================
ifeq (WINS,$(findstring WINS, $(PLATFORM)))
ZDIR=$(EPOCROOT)epoc32\release\$(PLATFORM)\$(CFG)\Z
else
ZDIR=$(EPOCROOT)epoc32\data\z
endif
TARGETDIR=$(ZDIR)\resource\apps
ICONTARGETFILENAME=$(TARGETDIR)\PierwszaAplikacja_0xE82211C4.mif
ICONDIR=..\gfx
do_nothing :
@rem do_nothing
MAKMAKE : do_nothing
BLD : do_nothing
CLEAN : do_nothing
LIB : do_nothing
CLEANLIB : do_nothing
RESOURCE :
mifconv $(ICONTARGETFILENAME) \
/c32 /X $(ICONDIR)\HelloWorld.svg
FREEZE : do_nothing
SAVESPACE : do_nothing
RELEASABLES :
@echo $(ICONTARGETFILENAME)
FINAL : do_nothing
A teraz pozostało jeszcze przzygotowanie skryptu kompilacji PierwszaAplikacja.mmp
Ten plik będzie w folderze group
/*
============================================================================
Name : PierwszaAplikacja.mmp
Author : Michał Małaj
Copyright : LGPL
Description : To jest plik specyfikacji projektu dla PierwszaAplikacja.
============================================================================
*/
TARGET PierwszaAplikacja_0xE82211C4.exe
TARGETTYPE exe
UID 0x100039CE 0xE82211C4
SOURCEPATH ..\src
SOURCE PierwszaAplikacja.cpp
SOURCE PierwszaAplikacjaApplication.cpp
SOURCE PierwszaAplikacjaAppView.cpp
SOURCE PierwszaAplikacjaAppUi.cpp
SOURCE PierwszaAplikacjaDocument.cpp
SOURCEPATH ..\data
START RESOURCE PierwszaAplikacja.rss
HEADER
TARGET PierwszaAplikacja_0xE82211C4
TARGETPATH resource\apps
END //RESOURCE
START RESOURCE PierwszaAplikacja_reg.rss
TARGET PierwszaAplikacja_0xE82211C4_reg
TARGETPATH \private\10003a3f\apps
END //RESOURCE
USERINCLUDE ..\inc
SYSTEMINCLUDE \epoc32\include
LIBRARY euser.lib
LIBRARY apparc.lib
LIBRARY cone.lib
LIBRARY eikcore.lib
LIBRARY avkon.lib
LIBRARY commonengine.lib
LIBRARY efsrv.lib
LIBRARY estor.lib
LIBRARY aknnotify.lib
LIBRARY hlplch.lib
LANG SC 01 27
VENDORID 0
SECUREID 0xE82211C4
// End of file
Na koniec piszemy plik dla kompilatora bld.inf
/*
============================================================================
Name : bld.inf
Author : Michał Małaj
Copyright : LGPL
Description : Polecenia dla kompilatora
============================================================================
*/
PRJ_PLATFORMS
WINSCW GCCE
PRJ_MMPFILES
gnumakefile icons.mk
PierwszaAplikacja.mmp
Ale to jeszcze nie koniec trzeba też przygotować pliki prosto w paczkę instalacyjną
więc do katalogu sis trzeba zrobić plik do tworzenia paczki sis
; Plik instalacyjny PierwszaAplikacja
;
;Language - standard language definitions
&EN, PL
; standard SIS file header
#{"First Application", "Pierwsza Aplikacja"},(0xE82211C4),1,0,0
;Localised Vendor name
%{"Vendor-EN", "Vendor-PL"}
;Unique Vendor name
:"Vendor"
;Supports Series 60 v 3.0
[0x101F7961], 0, 0, 0, {"Series60ProductID", "S60ProductID"}
;Files to install
"C:\Symbian\9.2\S60_3rd_FP1\Epoc32\release\gcce\urel\PierwszaAplikacja_0xE82211C4.exe" -"!:\sys\bin\PierwszaAplikacja_0xE82211C4.exe"
{
"C:\Symbian\9.2\S60_3rd_FP1\Epoc32\data\z\resource\apps\PierwszaAplikacja_0xE82211C4.rsc"
"C:\Symbian\9.2\S60_3rd_FP1\Epoc32\data\z\resource\apps\PierwszaAplikacja_0xE82211C4.r27"
} -"!:\resource\apps\PierwszaAplikacja_0xE82211C4.rsc"
"C:\Symbian\9.2\S60_3rd_FP1\Epoc32\data\z\private\10003a3f\apps\PierwszaAplikacja_0xE82211C4_reg.rsc" -"!:\private\10003a3f\import\apps\PierwszaAplikacja_0xE82211C4_reg.rsc"
"C:\Symbian\9.2\S60_3rd_FP1\Epoc32\data\z\resource\apps\PierwszaAplikacja_0xE82211C4.mif" -"!:\resource\apps\PierwszaAplikacja_0xE82211C4.mif"
;required for application to be covered by backup/restore facility
"..\sis\backup_registration.xml" -"!:\private\E82211C4\backup_registration.xml"
Następną rzeczą jest zrobienie własnego certyfikatu do podpisywania
Albo najlepszym wg mnie rozwiązaniem jest wysłanie swojej aplikacji do podpisania na SymbianSigninig albo podpisac ją własnym podpisem developerskim.
Brak komentarzy:
Prześlij komentarz