Arsip: array of TEdit (menanggapi artikel)

 
user image
more 14 years ago

simba

Aku nyoba mengulas artikel dari saysansay berjudul TEdit Array di http://pascal-id.org/dpr/Article100.pas Artikel tsb sebenarnya menampilkan trik yg cukup baik dalam penanganan runtime object creation (dalam contoh ini adalah TEdit). Namun sayangnya trik tsb kurang elegan, setidaknya menurutku. Sebagian ke-tidak-elegan-an dari trik tsb jutru bertentangan dari tujuan trik itu sendiri, yaitu runtime object creation. Dgn menggunakan bhs Delphi yg OOP-nya sangat bagus, seharusnya ada cara lain yg lebih baik, lebih simple, dan lebih memanfaatkan OOP dan fitur RTTI (Run Time Type Information) yg disediakan Delphi. Apa yg membuat solusi tsb kurang elegan? 1. Kita harus mendeklarasikan secara eksplisit (hardcoded) nama dan jumlah object TEdit yg kita akan buat (liat deklarasi variabel2 TEdit di artikel tsb). Ini berarti disusun saat coding alias sebelum compile time, padahal tujuan dari trik ini adalah untuk saat runtime. Agak kontradiksi? :P 2. Property2 atribut tertentu dari object TEdit dideklarasikan sbg constant (GridTop, GridLeft, dlsb). Berarti hal ini mengurangi fleksibilitas dari pembuatan object. Jika dalam aplikasi tsb kita ingin membuat array lagi tapi dgn property2 yg berbeda gimana? Apa nambah konstanta lagi? Wah, tambah banyak kerjaan sebelum compile time (baca: ngetik) dong? :P 3. Sbg konsekuensi dari no (1) maka kita harus mengakses object2 TEdit yg dibuat dgn nama2 tsb. Dan ini juga harus diketahui saat compile time! Sedangkan tujuan dari adanya array adalah kemudahan mengakses object berdasarkan indeks array-nya, bukan pada nama object-nya. Kalo array masih diakses pake nama object itemnya, gak ada gunanya pake array dong? Mending susun aja TEdit yg banyak saat design form, justru lebih mudah kan? Nah, bagaimana trik yg lebih baik? Karena trik ini untuk runtime object creation maka target utamanya adalah memudahkan pembuatan object saat runtime tanpa batasan2 saat compile time. Dan karena object yg akan dibuat adalah array (2 dimensi) maka target selanjutnya dari trik ini adalah kemudahan akses ke object saat runtime berdasarkan indeks array-nya. Berikut adalah trik yg lebih baik... 1. Deklarasi methods
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    function  Array2DOfEdit(aCol, aRow: integer): TEdit;
    procedure CreateArray2DOfTEdit(numCols, numRows, mostTop, mostLeft: integer;
                                   defaultText: string = 'ArrayEditColRow';
                                   vSpace: integer = 10; hSpace: integer = 10;
                                   aHeight: integer = 21; aWidth: integer = 121);
  end;
Tidak ada deklarasi type untuk array sama sekali. Kita hanya membutuhkan 2 method disini yaitu: - function Array2DOfEdit untuk akses ke array berdasarkan indeksnya. Karena array 2 dimensi maka indeks array berupa kolom (parameter aCol) dan baris (parameter aRow). Fungsi ini mengembalikan object TEdit pada indeks array yg diberikan. - procedure CreateArray2DOfTEdit untuk pembuatan array object TEdit 2 dimensi. Property2 dasar yg dibutuhkan menjadi parameter dari prosedur ini. Beberapa parameter yg cenderung tetap memiliki default value sehingga pengisiannya bisa optional (menggunakan default value). 2. Pembuatan array dari object TEdit Berikut adalah isi dari prosedur CreateArray2DOfTEdit:
procedure TForm1.CreateArray2DOfTEdit(numCols, numRows, mostTop, mostLeft: integer;
                                      defaultText: string = 'ArrayEditColRow';
                                      vSpace: integer = 10; hSpace: integer = 10;
                                      aHeight: integer = 21; aWidth: integer = 121);
var
  i, j: integer;
  rtEdit: TEdit;
begin
  // cek batasan minimal array
  if (numCols < 1) or (numRows < 1) then 
  begin
    raise Exception.Create('Jumlah kolom dan baris minimal 1!');
    //Exit;
  end;
  // susun array 2 dimensi
  for i := 0 to numCols-1 do
    for j := 0 to numRows-1 do
    begin
      rtEdit := TEdit.Create(self);
      rtEdit.Parent := self;
      // tentukan nama object untuk akses menggunakan RTTI
      rtEdit.Name := 'ArrayEdit'+IntToStr(i)+IntToStr(j);
      // susun TEdit
      rtEdit.Width := aWidth;
      rtEdit.Height := aHeight;
      rtEdit.Top := mostTop + (rtEdit.Height + vSpace)  j;
      rtEdit.Left := mostLeft + (rtEdit.Width + hSpace)   i;
      // isikan default Text dari TEdit
      if defaultText = 'ArrayEditColRow' then
        rtEdit.Text := rtEdit.Name
      else
        rtEdit.Text := defaultText;
    end;
end;
Dgn fitur OOP Delphi, kita bisa membuat array of object tanpa perlu deklarasi array sama sekali! Lah kok bisa? Ini karena deklarasi variebel TEdit sebenarnya bukan object itu sendiri melainkan pointer thd instance object yg dibuat. Sehingga, cukup dgn 1 deklarasi variabel TEdit (rtEdit) kita bisa membuat instance TEdit berapa pun. Kita tinggal "menyerahkan" instance object yg telah dibuat pada owner (dalam hal ini adalah TForm1) untuk dikelola lebih lanjut. Perhatikan bahwa tiap object TEdit yg dibuat menggunakan nama yg "baku", yaitu: "ArrayEdit"+kolom+baris. Ini nanti akan dimanfaatkan oleh fungsi akses ke array-nya. 3. Akses ke array dari object TEdit (yg telah dibuat) Berikut adalah isi dari fungsi Array2DOfEdit:
function TForm1.Array2DOfEdit(aCol, aRow: integer): TEdit;
begin
  // cari komponen berdasarkan nama "baku"
  Result := FindComponent('ArrayEdit'+IntToStr(aCol)+IntToStr(aRow)) as TEdit;
  // cek hasil pencarian komponen
  if Result = nil then
    raise Exception.Create('Object tidak dikenal atau diluar batas array!');
end;
Dgn memanfaatkan fungsi FindComponent (yg merupakan salah satu fitur RTTI dari Delphi), yg dipadukan dgn penamaan baku dari object, maka kita bisa mengakses object2 TEdit seolah-olah seperti array beneran! See... dgn cara tsb di atas, kita bisa membuat array TEdit 2 dimensi secara fleksibel (ukuran berapapun) dan mengaksesnya dgn mudah (melalui indeks array). Cara ini lebih elegan drpd cara yg dipake rekan saysansay, bahkan dgn jumlah baris yg lebih sedikit (sudah termasuk pengecekan). Berikut adalah contoh penggunaannya...
procedure TForm1.FormCreate(Sender: TObject);
var
  c,r: integer;
begin
  // buat array TEdit ukuran 4 kolom 3 baris
  CreateArray2DOfTEdit(4, 3, 10, 20);
  // isi teks dari array TEdit berdasarkan indeks array
  for c := 0 to 3 do
    for r := 0 to 2 do
      case r of
        0: Array2DOfEdit(c,r).Text := 'DelphiExpert';
        1: Array2DOfEdit(c,r).Text := 'deLogic';
        2: Array2DOfEdit(c,r).Text := 'LuriDarmawan';
      end;
end;
Sangat mudah dan fleksibel sekali, bukan? :) Outputnya sama persis seperti output dari program rekan saysansay. Sebenarnya trik ini juga masih ada "kelemahan"-nya. :P Yaitu, trik ini masih "nempel" ke TForm1. Jika kita membutuhkannya di form lain, maka harus copy-paste code yg sama ke form tsb. Seharusnya dgn mekanisme refactoring, trik ini bisa jadi class tersendiri atau bahkan component. Tapi untuk ini perlu pembahasan lebih lanjut, yg jelas trik runtime array of object creation yg digunakan benar2 sesuai dgn tujuannya. :) Semoga bermanfaat. :) -Bee- has Bee.ography at: http://beeography.wordpress.com
user image
more 14 years ago

saysansay

Seep.....Seeplah..Entar ditanggapi lagi cuma numpang mampir aja jadi nga ada modul buat konsep OPP Seep dech mas abimayu............wakakaakakak UknownIdentifier User
user image
more 14 years ago

DelphiExpert

Coba koreksi utk beberapa optimasi ah... 1. Di procedur CreateArray2DOfTEdit, perintah "Exit" sama sekali tidak diperlukan karena exception yang di 'raise' otomatis akan membuat current proses keluar dari block procedure.

// cek batasan minimal array
  if (numCols < 1) or (numRows < 1) then 
  begin
    raise Exception.Create('Jumlah kolom dan baris minimal 1!');
    { Exit;  // -> Ngga' perlu }
  end;
2. Coding bro Simba tetap menggunakan array 1 dimensi meskipun seolah2 diakses menggunakan teknik 2 dimensi. Dalam hal ini "Editxx.Parent:= Self", artinya "Self" atau Form1 sebagaimana kita ketahui akan menyimpan child controlnya ke dalam 1 dimensi array alias list biasa. Konsekuensinya akses ke object menjadi lambat. Belum lagi kalau ada object lain dalam parent yang sama, turunan TControl maupun TComponent. See Form.FindComponent, fungsi ini akan men-search dari 0 sampai ComponentCount - 1. Code diatas baik digunakan jika tidak diperlukan kecepatan akses terhadap object, simple, mudah dimengerti oleh newbie sekalipun (Dengan beberapa pengetahuan dasar: Jika sebuah object di-set property Parent-nya ke sebuah turunan TWinControl; dalam contoh ini adalah Form1, maka otomatis parent yang ditunjuk akan menyimpan "register" child ke internal list-nya; yang kemudian otomatis akan di release/free pada saat Parent di release (memanggil destructor). Optimasi terbaik tetap menggunakan object list 2 dimensi, lebih cepat lagi kalau pencarian object dalam list menggunakan binary tree + balance search. Semoga bermanfaat :) D.E
user image
more 14 years ago

simba

@DelphiExpert: Untuk optimasi poin no 1... betul sekali, procedure Exit gak diperlukan disitu. Ma'af kelupaan. Sebelumnya aku cuman pake procedure ShowMessage, jadi butuh Exit. Setelah aku ganti jadi exception, lupa ngilanginnya. :D Untuk poin no 2... mungkin agak kurang tepat ya. Soalnya, aku sama sekali gak bikin array apapun! "Array" dalam trik di atas tidak lebih dari penamaan component secara "baku" untuk dimanfaatkan nantinya oleh RTTI (terlepas bagaimana RTTI menanganinya secara internal). Dalam keperluan praktis seperti contoh di atas, solusi optimasi dgn binary tree rasanya terlalu over-complicated. Dgn memanfaatkan RTTI Delphi, yg sebenarnya juga udah dioptimasi, walaupun hasilnya gak cepet2 amat, tapi masih mencukupi lah. Lain cerita kalo kita mau melakukan time-critical searching, tentu saja RTTI sangat tidak direkomendasikan. Kadang dalam melakukan optimasi kita juga perlu hitung2 kebutuhan dan konsekuensinya juga. Mungkin kita bisa optimasi coding dgn memanfaatkan seluruh teknik secara maksimal (assembler? :) ), tapi waktu dan kompleksitas coding jadi bertambah. Padahal, secara praktis sebenarnya gak perlu optimasi sampe segitu. Be practical aja. :) -Bee- has Bee.ography at: http://beeography.wordpress.com
user image
more 14 years ago

DelphiExpert

Memang kurang relevan optimasi tsb diatas utk keperluan yg "simple" seperti saysansay hadirkan. You right! terlalu complicated jika hanya utk beberapa puluh object saja; dengan interval akses yg tidak terlalu tinggi. Maksud & tujuan saya adalah utk wawasan umum rekan2 lain, barangkali punya keinginan utk me-manage ratusan object dengan akses cepat. Seperti bikin designer dsb. Betul sekali bro Bee sama sekali tidak mendeklarasikan/menggunakan satu array pun, tetapi memanfaatkan penamaan object dengan memetakan posisi "Col & Row". That was a good simple-way to make it. Yang saya bicarakan diatas adalah "bagaimana RTTI menanganinya secara internal" atau "bagaimana RTTI menghandlenya", silahkan cek how they manage the child objects. Konsep dasarnya adalah menggunakan array 1 dimensi yg berupa TList. Lain lagi dengan bagaimana RTTI meng-handle "classes collections", mungkin rekan2 ada yg pernah memanfaatkan "RegisterClass atau RegisterClasses" utk keperluan membuat object pada saat runtime dengan mengacu pada object Class / TClass (TPersistentClass) tersebut. RTTI menangani registered classes dalam bentuk Tree, class di kelompokan berdasar "ClassParent" nya. Hal ini jauh lebih baik dari pada penanganan child object pada TWinControl. Perhatikan deklarasi beberapa variable dalam TWinControl yang digunankan utk menyimpan daftar child-nya tsb:

TWinControl = class(TControl)
  private
   .
   .
   .
    FControls: TList;
    FWinControls: TList;
   .
   .
   .
Dan bagaimana procedure "TWinControl.InsertControl(AControl: TControl);" does, dalam hal ini merujuk pada penulisan property "Parent", yaitu procedure "SetParrent" yg akan "menyuruh" new parent-nya meng-insert dirinya sendiri dalam daftar "Controls" pada parent tsb. Hal yang sama juga diterapkan pada TComponent dalam manangani AOwner list pada constructor. Good works! :) D.E
user image
more 14 years ago

simba

Seharusnya dgn mekanisme refactoring, trik ini bisa jadi class tersendiri atau bahkan component.
http://delphindo.wordpress.com/2006/06/22/array-of-control/
user image
more 13 years ago

nrkhlsmjd

@simba cara ngambil/akses nilainya gimana mas? misal: TEdit tadi saya buat sbg input....trus nilanya mau saya pindah ke label.. pake Label1.Caption:=ArrayEdit00.Text; koq gak bisa ya? bukannya nama TEditnya adl. ArrayEdit00, ArrayEdit01,ArrayEdit02....dll mohon pencerahan...
more ...
  • Pages:
  • 1
Share to
Local Business Directory, Search Engine Submission & SEO Tools FreeWebSubmission.com SonicRun.com