Form Load Profiler: Multi Form: Class Helper
Pada kesempatan yang lalu, saya sajikan artikel mengenai bagaimana mengukur waktu tayang (load-time) suatu form dari form tersebut di buat hingga benar – benar tampil dan siap digunakan. Sudah saya sajikan metode untuk form tunggal maupun multi form. Pada teknik multi form, saya menggunakan teknik interposser class. Selain teknik tersebut, ada alternatif lain yaitu dengan menggunakan class helper yang akan dibahas pada kesempatan ini.
Bagi pembaca yang mengikuti blog saya dari awal, tentunya ingat bahwa saya sudah beberapa kali menyajikan artikel Did You Know yang membahas mengenai penggunaan Class Helper. Dan pada kesempatan ini saya tidak akan membahas apa dan bagaimana class helper itu sendiri. Anda dapat mencarinya pada dokumentasi yang disediakan oleh CodeGear atau googling.
Nah, sekarang bagaimana menerapkan class helper dalam kasus ini.
Pertama, buat helper untuk kelas TForm.
TGlobalFormHelper = class helper for TForm end;
Kemudian untuk mendeklarasikan variabel FStart dan FEnd, tidak bisa dilakukan secara sembarangan mengingat class helper memberikan batasan tidak dapat menambah instance data, namun dapat menambah class fields. Nah untuk itu kita memanfaatkan class var, sehingga deklarasi variabelnya menjadi:
TGlobalFormHelper = class helper for TForm class var FStart, FEnd : Cardinal; end;
langkah selanjutnya adalah mendeklarasikan constructor Create, namun kali ini deklarasinya sedikit berbeda. Jika pada interposer class, kita harus meng-override constructor Create, maka pada class helper tidak perlu. Secara umum, isi dari constructor sebagai berikut:
TGlobalFormHelper = class helper for TForm class var FStart, FEnd : Cardinal; public constructor Create(AOwner: TComponent); end; // // .... // constructor TGlobalFormHelper.Create(AOwner: TComponent); begin FStart := GetTickCount; inherited; end;
Sampai di sini kita sudah mulai menghitung pengukuran, langkah berikutnya tentu saja adalah meletakkan rutin akhir pengukuran pada method Activate. Namun sayang sekali, dalam class helper ini, kita tidak dapat mendeklarasikan dan atau meng-override method Activate karena sudah dideklarasikan. Sebagai alternatif solusinya, kita akan membelokkan event onActivate untuk menjalankan rutin pengukuran. Untuk itu kita harus menyimpan event onActivate yang sebenarnya. Nah di dalam rutin pengukuran tersebut kita jalankan event onActivate yang sebenarnya sebelum mengakhiri perhitungan. Selengkapnya menjadi:
TGlobalFormHelper = class helper for TForm class var FStart, FEnd : Cardinal; FOnActivateTemporary : TNotifyEvent; public constructor Create(AOwner: TComponent); procedure CalculateLoadTime(Sender: TObject); end; // // .... // procedure TGlobalFormHelper.CalculateLoadTime(Sender: TObject); begin if Assigned(FOnActivateTemporary) then FOnActivateTemporary(Sender); FEnd := GetTickCount; end; constructor TGlobalFormHelper.Create(AOwner: TComponent); begin FStart := GetTickCount; inherited; Sleep(50); FOnActivateTemporary := Self.OnActivate; Self.OnActivate := CalculateLoadTime; end;
Ok, sampai disini class helper sudah beres, sekarang bagaimana dengan kelas utama nya? Cukup dengan menambahkan constructor Create dan tambahkan directive override. Di dalam constructor tersebut, tambahkan kode inherited untuk memanggil constructor Create yang sebenarnya, yaitu yang dideklarasikan pada class helper.
TMainForm = class(TForm) // // ... // public { Public declarations } constructor Create(AOwner: TComponent); override; end; // // ... // constructor TMainForm.Create(AOwner: TComponent); begin inherited; end;
Langkah selanjutnya adalah bagaimana memanfaatkan class helper tersebut pada form. Untuk form utama, tidak ada masalah, tidak ada tambahan apapun karena class helper dideklarasikan dalam unit yang sama.
{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: MultipleMainFormUnit.pas, released on 2008-09-25 The Initial Developer of the Original Code is Bayu Prasetio Portions created by Bayu Prasetio are Copyright (C) 2008 Bayu Prasetio. All Rights Reserved. -----------------------------------------------------------------------------} unit MultipleMainFormUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls; type TMainForm = class(TForm) btnShowResult: TButton; mmoLegend: TMemo; stbMain: TStatusBar; btnLoadSecondary: TButton; lblLoadTime: TLabel; btnLoadAnotherForm: TButton; procedure btnShowResultClick(Sender: TObject); procedure btnLoadSecondaryClick(Sender: TObject); procedure btnLoadAnotherFormClick(Sender: TObject); private { Private declarations } public { Public declarations } constructor Create(AOwner: TComponent); override; end; TGlobalFormHelper = class helper for TForm class var FStart, FEnd : Cardinal; FOnActivateTemporary : TNotifyEvent; public constructor Create(AOwner: TComponent); procedure CalculateLoadTime(Sender: TObject); end; var MainForm: TMainForm; implementation {$R *.dfm} uses MultipleSecondaryFormUnit, MultipleAnotherFormUnit; procedure TMainForm.btnLoadAnotherFormClick(Sender: TObject); begin AnotherForm := TAnotherForm.Create(nil); AnotherForm.ShowModal; AnotherForm.Free; end; procedure TMainForm.btnLoadSecondaryClick(Sender: TObject); begin SecondaryForm := TSecondaryForm.Create(nil); SecondaryForm.ShowModal; SecondaryForm.Free; end; procedure TMainForm.btnShowResultClick(Sender: TObject); begin lblLoadTime.Caption := ' Form Load Time: ' + IntToStr(FEnd - FStart) + ' ms'; btnShowResult.Enabled := False; end; constructor TMainForm.Create(AOwner: TComponent); begin inherited; end; procedure TGlobalFormHelper.CalculateLoadTime(Sender: TObject); begin if Assigned(FOnActivateTemporary) then FOnActivateTemporary(Sender); FEnd := GetTickCount; end; constructor TGlobalFormHelper.Create(AOwner: TComponent); begin FStart := GetTickCount; inherited; Sleep(50); FOnActivateTemporary := Self.OnActivate; Self.OnActivate := CalculateLoadTime; end; end.
Nah untuk form yang lainya, deklarasi mirip dengan menggunakan interposer class, yaitu cukup dengan menambahkan pada klausul uses dengan nama unit dimana class helper dideklarasikan, seperti contoh kode berikut:
{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: MultipleAnotherFormUnit.pas, released on 2008-09-25 The Initial Developer of the Original Code is Bayu Prasetio Portions created by Bayu Prasetio are Copyright (C) 2008 Bayu Prasetio. All Rights Reserved. -----------------------------------------------------------------------------} unit MultipleAnotherFormUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TAnotherForm = class(TForm) btnShowResult: TButton; procedure btnShowResultClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var AnotherForm: TAnotherForm; implementation {$R *.dfm} uses MultipleMainFormUnit; procedure TAnotherForm.btnShowResultClick(Sender: TObject); begin ShowMessage('Load Time : ' + IntToStr(FEnd - FStart)); end; procedure TAnotherForm.FormCreate(Sender: TObject); begin Sleep(200); end; end.
Nah selesai…
Selengkapnya mengenai demo class helper dapat di-unduh di sini: Source Code.
Jika Anda sudah lupa dengan form load profiler untuk form tunggal, silahkan disimak di sini: Form Load Profiler: Single Form
Jika Anda sudah lupa dengan form load profiler dengan menggunakan teknik interposer class, silahkan disimak di sini: Form Load Profiler: Multiple Form: Interposer Class
Lalu mana yang terbaik antara interposer class dan class helper ?
Dilihat dari faktor kompatibilitas compiler Delphi, jelas interposer class karena class helper baru diperkenalkan mulai Delphi 2005 (CMIIW).
Di sisi lain, CodeGear dalam dokumentasinya menyebut secara khusus class helper:
Class helpers provide a way to extend a class, but they should not be viewed as a design tool to be used when developing new code. They should be used solely for their intended purpose, which is language and platform RTL binding.
Namun menurut saya tergantung kebutuhan dan pemahaman Anda mengenai kedua teknik tersebut.
Semoga bermanfaat.
Bagus boss artikelnya
thanks, seperti biasa, apa yang saya sajikan masih kulitnya saja, jika berminat, silahkan mendalami lebih jauh. 😀
btw saya menyertakan statement sleep(50) di dalam constructor Create form class helper dan sleep lainnya pada constructor yang lain, hanya sebagai penanda saja, agar efek dari metode ini terlihat. Pada kode yang sesungguhnya, sebaiknya sleep tersebut dihilangkan.
Semoga bermanfaat.