2 Hướng nghiên cứu và giới hạn đề tài
4.3 Xây dựng dự án ứng dụng mớ i
Phát triển ứng dụng trên Symbian chủ yếu sử dụng các môi trường phát triển ứng dụng tích hợp IDE. Vì vậy công việc xây dựng dự án ứng dụng mới là công việc
đầu tiên trong việc phát triển một ứng dụng trên một IDE. Các IDE sử dụng phổ
KHOA CNTT –
ĐH KHTN
Nhưng một IDE phổ biến trước đây và hiện vẫn còn được sử dụng là Visual C++ 6.0 không hỗ trợ chức năng này. Đó là lý do ra đời của nhiều công cụ khác nhau để
tạo dự án ứng dụng mới có thể phát triển trên IDE VC++ 6.0. 4.3.1 Công cụ
• Symbian OS Wizard : đây là một trình công cụ được viết bằng Perl chạy từ
dòng lệnh tạo ra một thư mục dự án với đầy đủ các loại file để phát triển ứng dụng cho điện thoại thuộc dòng Nokia 9200 Communicator Series. Ngoài ra công cụ này còn tạo ra các file dự án để phát triển ứng dụng trên IDE Visual C++ 6.0 (file .dsp và .dsw). Trình công cụ này có thể lấy từ www.forum.nokia.com. Nó có thể tạo dự
án cho các loại chương trình thực thi khác nhau trên Symbian: ứng dụng đồ họa (file thực thi .app), thư viện liên kết động (file .dll), chương trình thực thi (file .exe) với câu lệnh có tham số phù hợp.
Ví dụ: swiz app.tpl MyApp 0x01000001 sẽ tạo một thư mục dự án có tên ứng dụng sẽ là MyApp với UID là 0x01000001. Nếu muốn tạo một DLL ta chỉ việc thay app.tl bằng dll.tpl. Ứng dụng .exe hay .dll không cần UID chính xác, ta có thể chọn số tùy ý làm tham số thứ hai. Điều kiện bắt buộc để chạy trình công cụ này là phải có Active Perl.
• MEAD: đây là một chương trình đồ họa với mục đích tạo dự án ứng dụng đồ
họa để có thể biên dịch từ dòng lệnh hay bằng Microsoft Visual C++ 6.0 (file .dsp). Ngoài ra MEAD còn hỗ trợ công cụ xây dựng menu cho ứng dụng. MEAD tồn tại trong các SDK được cài đặt đầy đủ, MEAD được lưu trữ ở <%Symbian xx SDK%>\Delelopment Tools\MEAD hay từ start->programs->Symbian xx SDKs- >Development Tools->MEAD khi SDK được cài đặt trên Window.
KHOA CNTT –
ĐH KHTN
H4.3 Tạo dự án mới với MEAD
• EPOCfromMMP: chuyển file dự án .mmp thành file dự án hoạt động trên IDE VC .NET. Một đặc điểm lưu ý là EPOCfromMMP không thể chuyển các file .mmp cho các Symbian SDK hỗ trợ CodeWarrior. Do đó chỉ dùng EPOCfromMMP với các SDK hỗ trợ VC++ 6.0/C++ BuilderX. Không tạo file dự án hoạt động trên VC.NET, chúng còn đặt các chức năng vào menu của IDE VC .NET phục vụ cho phát triển ứng dụng Symbian như chức năng quản lý tài nguyên, ảnh bitmap, hay chuyển đổi loại biên dịch.
4.3.2 IDE
• Metrowerks CodeWarrior:
Để tạo một dự án ứng dụng mới với CodeWarrior, chúng ta chọn File>>New. Ở đây chúng ta có 2 loại dự án hoặc là rỗng: chúng ta chọn Empty Project, ngược lại chọn Symbian Stationery Wizard và làm theo các bước hướng dẫn. IDE CodeWarrior sẽ tự nhận ra các bộ SDK chúng ta cài trên máy và yêu cầu
KHOA CNTT –
ĐH KHTN
chúng ta chỉ định bộ công cụ chúng ta dùng. File dự án của CodeWarrior là .mcp và file workspace là .cww.
H4.4 Tạo dự án ứng dụng mới với IDE CodeWarrior
CodeWarrior có thể tạo một file dự án ứng dụng .mcp, hỗ trợ phát triển ứng dụng trên CodeWarrior từ một dự án đã được tạo trước bằng IDE hay các công cụ
khác. Để thực hiện việc này, chúng ta chọn File >> Import Project from .mmp file hoặc File >> Import Project… với file .xml.
KHOA CNTT –
ĐH KHTN
• Borland C++ Builder 6.0/C++ BuilderX
Hai IDE này hỗ trợ tạo dự án ứng dụng Symbian mới nhưng chủ yếu chỉ
phục vụ cho nền hệ thống Series 60. C++ BuilderX có hỗ trợ phát triển cho UIQv2.1. Tương tự, để tạo dự án ứng dụng mới, từ menu chúng ta chọn File>>New. Tiếp theo chúng ta sẽ thực hiện theo các chỉ dẫn và loại ứng dụng mà chúng ta muốn xây dựng.
H4.6 Tạo dự án mới với IDE C++ BuilderX
• VC++ 6.0/VC .NET
Chúng ta có thể tạo dự án ứng dụng Series 60 mới với IDE VC++ 6.0 hay VC .NET bằng công cụ Nokia Series 60 Appwizard được Series 60 SDK hỗ trợ
chứa trong \Symbian\6.1\Series60\Series60Tools. Đầu tiên, chúng ta chép file AvkonAppWizawx trong thư mục đó và thư mục Template của VC++ (chẳng hạn: C:\Program Files\Microsoft Visual Studio\Common\MsDev98\Template). Lúc này chúng ta có thể tạo một ứng dụng Symbian mới trên IDE VC++ bằng cách chọn từ
menu File->New. Sau đó chúng ta chọn loại dự án là Nokia Series 60 AppWizard v1.6 như hình vẽ. Các bước tiếp theo làm theo hướng dẫn và tùy chọn mà chúng ta muốn dùng cho ứng dụng của mình.
KHOA CNTT –
ĐH KHTN
H4.7 Tạo dự án cho IDE VC++ 6.0 với Nokia Series 60 App Wizard
4.4 Dự án mẫu HelloWorld được tạo bằng IDE CodeWarrior
4.4.1 Xây dựng dự án ứng dụng HellWorld
Dự án ứng dụng HelloWorld được xây dựng chạy trên nền hệ thống UIQ 2.1 với IDE Metrowerks CodeWarrior.
- Chọn loại dự án: Vào menu File>>New, sau đó chọn thẻ Project với loại dự
án là Symbian Stationery Wizard và điền tên file dự án như hình H4.9.
KHOA CNTT – ĐH KHTN - Chọn nền hệ thống (bộ SDK tương ứng) để xây dựng ứng dụng. H4.9 Chọn nền hệ thống cho ứng dụng - Chọn loại ứng dụng tạo là HelloWorld. H4.10 Chọn xây dựng ứng dụng HelloWorld
- Sau khi chọn Finish, các file cần cho phát triển dự án ứng dụng HelloWorld trên IDE CodeWarrior được tạo bao gồm :
+ Các file dự án trung tính: HelloWorld.mmp và bld.inf (xem phần 4.2). Ngoài ra một file HelloWorld.xml cũng được tạo. Đây là một dạng file định nghĩa
ứng dụng khác được IDE CodeWarrior hỗ trợđể tạo dự án ứng dụng.
+ Các file dự án ứng với IDE CodeWarrior: File đầu tiên là file dự án CodeWarrior: HelloWorld.mcp. Tiếp theo là 2 file được tạo dựa trên file HelloWorld.mmp: file HelloWorld.pref mô tả các thông tin như tên, loại chương
KHOA CNTT –
ĐH KHTN
trình, UID và file HelloWorld.resources khai báo các file và các thông tin tài nguyên cho ứng dụng.
+ Các file mã chương trình: các file tài nguyên HelloWorld.rss và HelloWorld.hrh, file header HelloWorld.h và 5 file mã nguồn C++: HelloWorld_Main.cpp, HelloWorld_Application.cpp, HelloWorld_Document.cpp, HelloWorld_AppUI.cpp và HelloWorld_View.cpp.
4.4.2 Cấu trúc các lớp chương trình ứng dụng HelloWorld
Trong phần này chúng ta sẽ tìm hiểu cấu trúc ứng dụng đồ họa qua các lớp một chương trình đơn giản HelloWorld. Đây là chương trình ứng dụng đồ họa khá
đơn giản chạy trên nền hệ thống UIQ với mục đích hiện ra dòng chữ “Hello World!” ở chính giữa màn hình.
Mã chương trình được xây dựng trong 4 file bao gồm 4 lớp theo đúng cấu trúc của ứng dụng đồ họa: lớp ứng dụng CExampleApplication chứa trong file HelloWorld_Application.cpp, lớp tài liệu CExampleDocument chứa trong file HelloWorld_Document.cpp, lớp giao diện ứng dụng CExampleAppUi chứa trong file HelloWorld_AppUi.cpp và lớp hiển thị CExampleAppView chứa trong file HelloWorld_AppView.cpp. Do đơn giản nên khai báo của cả 4 file này được đặt trong cùng một file header HelloWorld.h thay vì 4 file header như các ứng dụng lớn.
4.4.2.1 Mã khởi tạo hoạt động ứng dụng đồ họa
Tuy nhiên nếu chỉ với 4 file mã chương trình trên thì chương trình ứng dụng không thể thực thi được. Nhưđã biết thì ứng dụng đồ họa là một DLL đa hình, nó được thực thi nhờ chương trình apprrun.exe. Do đó trong mỗi ứng dụng đồ họa Symbian phải có thêm một file chứa các hàm đảm nhận việc khởi tạo hoạt động cho
ứng dụng đồ họa. Trong HelloWorld, các hàm này chứa trong file HelloWorld_Main.cpp.
Khi ứng dụng được chọn thực thi, chương trình apprun.exe sẽ hoạt động với tên ứng dụng và tên file ứng dụng làm tham số. Chương trình apprun sẽ sử dụng
KHOA CNTT –
ĐH KHTN
kiến trúc ứng dụng APPARC để nạp ứng dụng qua việc kiểm tra UID2 là KUiApp (0x100039ce) và tạo đối tượng ứng dụng đồ họa qua hàm NewApplication().
Nội dung chính của HelloWorld_Main.cpp cũng như mọi file cài đặt khởi tạo ứng dụng khác là cài đặt hàm NewApplication() và hàm E32Dll(TdllReason) (một hàm chỉ cài đặt, không sử dụng). Từ khóa EXPORT_C để báo hàm NewApplication là đầu vào của một DLL.
EXPORT_C CApaApplication* NewApplication() {
return new CExampleApplication; }
GLDEF_C TInt E32Dll(TDllReason) {
return KErrNone; }
4.4.2.2 Lớp ứng dụng
Sau khi gọi hàm NewApplication(), đối tượng ứng dụng HelloWorld, một
đối tượng của lớp CExampleApplication (kế thừa lớp CQikApplication) được tạo. Ngay sau khi được tạo hàm AppDllUid() của đối tượng ứng dụng này được APPARC gọi để kiểm tra UID3.
const TUid KUidHelloWorld = { 0x101F6163 };
TUid CExampleApplication::AppDllUid() const {
return KUidHelloWorld; }
KHOA CNTT –
ĐH KHTN
Sau đó APPARC sẽ gọi hàm CreateDocumentL() để tạo đối tượng tài liệu
ứng dụng.
CApaDocument* CExampleApplication::CreateDocumentL() {
return new (ELeave) CExampleDocument(*this); }
Mọi lớp ứng dụng đều phải chứa 2 hàm này và phải có cấu trúc giống như
vậy, chỉ khác nhau ở tên lớp và UID. 4.4.2.3 Lớp tài liệu
Do HelloWorld không phải là ứng dụng file nên nhiệm vụ chính của lớp CExampleDocument (kế thừa từ lớp CQikDocument) là nạp đối tượng giao tiếp của lớp CExampleAppUi. Sau khi đối tượng tài liệu được khởi tạo, APPARC sẽ gọi hàm CreateAppUiL() để tạo đối tượng giao diện ứng dụng.
CEikAppUi* CExampleDocument::CreateAppUiL() {
return new(ELeave) CExampleAppUi; }
4.4.2.4 Lớp giao diện ứng dụng
Lớp giao diện ứng dụng CExampleAppUi (kế thừa từ lớp CQikAppUi)
đóng 2 vai trò chính đó là nhận lệnh từ người dùng ứng dụng qua menu, toolbar và tạo cửa sổ hiển thị cho ứng dụng (view), phân phối các sự kiện cho các điều khiển tương ứng. Các điều khiển này có thể là view hay các điều khiển chứa trong view.
• Xử lý các lệnh:
Một lệnh là một chỉ thịđược biểu hiện dưới một số nguyên định danh 32bit. Hàm HandleCommandL(TInt aCommandId) là hàm nhận và xử lý các lệnh này.
KHOA CNTT –
ĐH KHTN
void CExampleAppUi::HandleCommandL(TInt aCommand) { switch (aCommand) { case EExampleItem0: iEikonEnv->InfoMsg(R_EXAMPLE_TEXT_ITEM0); break; case EExampleItem1: iEikonEnv->InfoMsg(R_EXAMPLE_TEXT_ITEM1); break; case EExampleItem2: iEikonEnv->InfoMsg(R_EXAMPLE_TEXT_ITEM2); break; case EEikCmdExit: Exit(); break; } }
EExampleItem0, EExampleItem1, EExampleItem2 là 3 định danh cho 3 lệnh trên menu Item0, Item1, Item2. Thông thường các định danh lệnh được khai báo trong file tài nguyên .hrh. Các định danh chuẩn của Symbian được khai báo trong eikcmds.hrh và có giá trị từ 0x0100 đến 0x01ff. Do đó giá trị các định danh lệnh của ứng dụng nên tránh khoảng giá trị đó. Trong HelloWorld, các định danh menu này được khai báo trong file tài nguyên HelloWorld.hrh.
enum TExampleMenuCommands {
EExampleItem0 = 200, EExampleItem1, EExampleItem2 };
KHOA CNTT –
ĐH KHTN
Định danh cuối cùng EEikCmdExit là định danh chuẩn do Symbian quy định, khi cần đóng ứng dụng, hệ thống sẽ gọi phát sinh sự kiện ứng với định danh lệnh này đểđóng ứng dụng.
• Tạo cử sổ hiển thị view và phân phối sự kiện cho các điều khiển:
Cửa sổ hiển thị được tạo trong hàm ConstructL() (đây là một dạng constructor thứ 2 được dùng trên Symbian).
void CExampleAppUi::ConstructL() { BaseConstructL(); iAppView = CExampleAppView::NewL(ClientRect()); AddToStackL(iAppView); }
BaseConstructorL được cung cấp từ lớp cơ sở để khởi tạo các thành phần cần thiết. Hệ thống giao diện ứng dụng đưa các điều khiển mà nó quản lý vào một ngăn xếp điều khiển (control stack) qua hàm AddToStack() và nó sẽ phân phối các sự kiện đến các điều khiển tương ứng dựa trên ngăn xếp này. Do đó để các điều khiển nhận được sự kiện gởi cho nó thì phải đưa nó vào ngăn xếp điều khiển.
4.4.2.5 Lớp hiển thị ứng dụng
Cửa sổ hiển thị là điều khiển đặc biệt, nó chứa các điều khiển khác và là nơi quan trọng nhất trong một ứng dụng đồ họa. Nó nhận sự kiện từđối tượng giao diện
ứng dụng rồi phân phối cho các điều khiển dựa trên loại sự kiện là nhấn phím qua hàm TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType) hay con trỏ qua hàm void HandlePointerEventL(const TPointerEvent& aPointerEvent).
Cũng như mọi điều khiển, lớp CExampleAppView kế thừa từ CCoeControl. Trên điều khiển cửa sổ hiện thị HelloWorld không có điều khiển nào nhận 2 loại sự
kiện này cả. Nhiệm vụ chính của nó là hiển thị dòng “Hello World!” được thể hiện qua hàm Draw:
KHOA CNTT –
ĐH KHTN
void CExampleAppView::Draw(const TRect& /*aRect*/) const {
// Window graphics context CWindowGc& gc = SystemGc(); // Area in which we shall draw TRect drawRect = Rect(); // Font used for drawing text const CFont* fontUsed; // Start with a clear screen gc.Clear();
// Draw an outline rectangle (the default pen and brush styles ensure this) // smaller than the drawing area.
drawRect.Shrink(30,30); gc.DrawRect(drawRect);
// Use the title font supplied by the UI fontUsed = iEikonEnv->TitleFont(); gc.UseFont(fontUsed);
// Draw the text in the middle of the rectangle.
TInt baselineOffset=(drawRect.Height() - fontUsed->HeightInPixels())/2; gc.DrawText(*iExampleText,drawRect,baselineOffset,
CGraphicsContext::ECenter, 0); // Finished using the font
gc.DiscardFont(); }
Đầu tiên nó lấy ngữ cảnh đồ họa, xóa sạch cửa sổ view và vẽ lại khung chữ
nhật và dòng chữ giữa màn hình với font được chọn. iExampleText là biến thành viên chỉđến chuỗi ký tự “Hello World!” lưu trên heap.
KHOA CNTT – ĐH KHTN CHƯƠNG 5 LẬP TRÌNH C++ CHO ỨNG DỤNG SYMBIAN Chuỗi và descriptor Các loại descriptor Sử dụng descriptor Quản lý lỗi và cơ chế cleanup stack Lỗi lập trình Lỗi môi trường Quản lý bộ nhớ và cơ chế cleanup stack Quản lý sự kiện (event handing) Quản lý sự kiện trong ứng dụng Symbian Quản lý sự kiện với active object Stream và store Stream Store Lập trình đồ họa Kiến trúc đồ họa
File tài nguyên
Các điều khiển trong ứng dụng đồ họa Quy ước đặt tên trong Symbian
Tên lớp Tên dữ liệu Tên hàm
Cấu trúc thư mục dự án
KHOA CNTT –
ĐH KHTN
5.1 Chuỗi và descriptor
Trên Symbian chuỗi được biết và cài đặt dưới các descriptor thay vì string như
trên C/C++ chuẩn hay Java. Chúng được cài đặt qua các lớp khác nhau mang lại sự
tiện lợi như trên C++ chuẩn hay Java. Nhưng khác với C++ chuẩn và Java vốn dùng trên PC, chuỗi trên Symbian đã được quản lý theo phong cách mới để phù hợp với bộ nhớ nhỏ trên điện thoại Symbian. Ngoài ra descriptor có thể dùng để lưu trữ các dữ liệu nhị phân.
5.1.1 Các loại descriptor
Trên Symbian chuỗi được cài đặt trong 4 loại descriptor:
• Abstract descriptor: Với các chuỗi ký tự và xử lý đơn giản, trên Symbian, 2 lớp TDesC và TDes có thểđảm nhận.
- TDesC là một descriptor hằng, không thể thay đổi nội dung được. Nó có một địa chỉ và một chiều dài. Với TDesC, chúng ta có thể thao tác chuỗi qua các hàm mà nó cung cấp nhưng không thể thay đổi được dữ liệu.
- TDes là một descriptor có thể sửa đổi dữ liệu được. Ngoài các thuộc tính kế thừa từ TDesC, nó có một độ dài tối đa cho phép dữ liệu được mở rộng, nối, cắt trong giới hạn của chiều dài tối đa. TDes cung cấp đầy đủ các hàm thao tác chuỗi, kể cả các hàm sửa đổi chuỗi mà trên TDesC không có.
Tất cả các descriptor còn lại đều kế thừa từ abstract descriptor qua 2 lớp này.
• Pointer descriptor: Đây là các lớp kế thừa đơn giản nhất từ 2 lớp TDesC và TDes.
- TPtrC kế thừa từ TDesC, nó chỉ có chiều dài và địa chỉ, nên chỉ mất 2 từ
nhớ 32 bit (8 byte). Một TPtrC có thể cài đặt để mô tả một dữ liệu đã được lưu trữ. - TPtr kế thừa từ TDes, nó được dùng để mô tả một vùng đệm (buffer) trên heap với một thuộc tính độ dài tối đa được thêm vào.
KHOA CNTT –
ĐH KHTN
H5.1 Mô hình đối tượng TPtrC và TPtr
TPtrC và TPtr gần giống như char* trên C, nhưng trong bản thân nó đã có chiều dài, không cần phải quét tìm ký tự kết thúc như trên C.
• Buffer descriptor: Cũng gồm có 2 lớp là TBufC và TBuf, chứa dữ liệu ngay trong chúng, lưu trữ trong ngăn xếp stack, tương tự như char[] trong C.
H5.2 Mô hình đối tượng TBufC và TBuf
Các descriptor này sử dụng cơ chế mẫu (template) trong C++ với tham số là một số nguyên để mô tả chiều dài.
KHOA CNTT –
ĐH KHTN
• Heap descriptor: chỉ gồm 1 lớp là HBufC.
H5.3 Mô hình đối tượng HBufC
HBufC chứa dữ liệu của chúng trong các ô trên heap. Điều này gần giống với (char*)malloc(length+1) trong C. Giống như trên C, loại này được dùng khi chúng ta không biết độ dài là bao nhiêu. Các buffer descriptor lưu trữ trên heap, chúng thường được tham khảo thông qua một HBufC* thay vì trực tiếp HBufC.