Array of Control

June 22, 2006 at 7:31 pm | Posted in Code Samples, Tutorials | 6 Comments

by: Kusnassriyanto

Tulisan ini menanggapi permintaan sdr Bee di milis Delphindo yang juga mengacu ke tulisan sdr Bee di delphi-id.org. Artikel yang ditulis oleh sdr Bee tersebut membahas mengenai pembuatan sejumlah komponen TEdit yang tersusun sebagai array 2 dimensi. Secara umum artikel tersebut sudah memenuhi kebutuhan utama meskipun masih ada beberapa kekurangan minor berkaitan dengan reusability dan performance.

Artikel yang saya tulis ini akan membahas bagaimana membuat sebuah objek yang memiliki kemampuan untuk mengelola sejumlah kontrol (kelompok komponen turunan TControl, bukan cuma TEdit saja) dalam kerangka array 2 dimensi. Pada bagian akhir artikel ini dibahas bagaimana menurunkan objek TControlArray menjadi TEditArray untuk memudahkan akses terhadap kontrol didalamnya yang semuanya adalah TEdit.

Apa yang akan dibuat

Seperti yang sudah disebutkan sebelumnya, kita akan membuat sebuah objek yang memiliki kemampuan untuk mengelola sejumlah kontrol dalam kerangka array 2 dimensi. Objek ini akan menyediakan mekanisme yang mudah untuk meng-create kontrol sebanyak m kolom dan n baris.

Akses terhadap kontrol sebisa mungkin dibuat mudah. Bila memungkinkan bisa seperti contoh dibawah ini.

for i:=0 to jmlCol-1 do begin
  for j:=0 to jmlRow-1 do begin
    MyArrEdit[i, j].Color := clRed;
  end;
end;

Kalau bisa, implementasi internal menggunakan array untuk mengakses kontrol, karena kita tahu bahwa mengakses array sangat cepat. Objek ini akan kita beri nama TControlArray.

Definisi TControlArray

Perhatikan definisi TControlArray berikut ini.

  TControlArray = class
  private
    FCArray: array of array of TControl;
    FColCount: Integer;
    FRowCount: Integer;
  protected
    FControlClass: TControlClass;
  public
    constructor Create(ControlClass: TControlClass);
    procedure BuildControls(Parent: TWinControl;
      numCols, numRows, mostTop, mostLeft: Integer;
      cWidth, cHeight, spaceHorz, spaceVert: Integer); virtual;
    function GetControl(col, row: Integer): TControl; virtual;
    procedure ClearControls; virtual;
    destructor Destroy; override;
    property ColCount: Integer read FColCount;
    property RowCount: Integer read FRowCount;
  end;

Pertama, constructor Create yang dimiliki objek ini memiliki parameter ControlClass yang bertipe TControlClass. Parameter ini akan kita simpan dalam field (variabel dari objek) yang bernama FControlClass dan akan digunakan untuk control creation. Sederhananya, bila kita lewatkan TEdit ketika kita create TArrayControl, maka kontrol yang akan di-create pada procedure BuildControls adalah TEdit. Teknik ini serupa dengan yang digunakan TCollection.

Kedua, objek ini memiliki sebuah method yang bernama BuildControls. Parameter procedure ini adalah

  • Parent, tempat dimana kontrol yang dibuat akan diletakkan
  • numCols, banyaknya kolom
  • numRows, banyaknya baris
  • mostTop, posisi atas
  • mostLeft, posisi kiri
  • cWidth, Lebar kontrol
  • cHeight, Tinggi kontrol
  • spaceHorz, jarak horizontal antar kontrol
  • spaceVert, jarak vertikal antar kontrol

Ketiga, objek ini memiliki method GetControl, dengan parameter col dan row. Fungsi method ini adalah mengembalikan kontrol pada posisi col, row.

Keempat, objek ini memiliki procedure ClearControls yang dapat digunakan untuk menghapus semua kontrol, serta destructor Destroy untuk melakukan sesuatu sebelum objek ini di-destroy.

Kelima, ada property ColCount dan RowCount.

Keenam, pada bagian private kita menggunakan dynamic array 2 dimensi of TControl.

Implementasi TControlArray

Pertama, yang akan kita lakukan dalam constructor Create tidaklah banyak. Kita akan menyimpan parameter yang dilewatkan ke field FControlClass.

constructor TControlArray.Create(ControlClass: TControlClass);
begin
  FControlClass := ControlClass;
end;


Selanjutnya, implementasi method BuildControl adalah sebagai berikut

procedure TControlArray.BuildControls(Parent: TWinControl;
  numCols, numRows, mostTop, mostLeft, cWidth, cHeight,
  spaceHorz, spaceVert: Integer);
var i, j: Integer;
  vControl: TControl;
begin
  ClearControls;
  FColCount := numCols;
  FRowCount := numRows;
  SetLength(FCArray, numCols);
  for i:=0 to numCols-1 do begin
    SetLength(FCArray[i], numRows);
    for j:=0 to numRows-1 do begin
      // owner diisi nil
      vControl := FControlClass.Create(nil);
      // untuk memberikan efek seketika, visible dimatikan dulu
      vControl.Visible := False;
      // parent diset duluan karena ada beberapa control
      // tidak dapat diset property-nya kalo parent-nya belum
      // diset.
      vControl.Parent := Parent;
      vControl.Width := cWidth;
      vControl.Height := cHeight;
      vControl.Left := mostLeft+(cWidth+spaceHorz)*i;
      vControl.Top := mostTop+(cHeight+spaceVert)*j;
      vControl.Visible := True;
      FCArray[i, j] := vControl;
    end;
  end;
end;

Untuk mengakses kontrol tertentu dengan indeks col dan row, kita gunakan function GetControl. Implementasinya adalah sebagai berikut:

function TControlArray.GetControl(col, row: Integer): TControl;
begin
  result := nil;
  if (col>=0) and (col<FColCount) then begin
    if (row>=0) and (row<FRowCount) then begin
      result := FCArray[col, row];
    end;
  end;
end;

Pada function diatas, bila col dan row berada diluar range, maka nilai yang akan dikembalikan adalah nil.

Berikutnya adalah method ClearControls untuk membuang semua control:

procedure TControlArray.ClearControls;
var i, j: Integer;
begin
  for i:=0 to FColCount-1 do begin
    for j:=0 to FRowCount-1 do begin
      FCArray[i, j].Free;
    end;
  end;
  SetLength(FCArray, 0);
  FColCount := 0;
  FRowCount := 0;
end;

Terakhir adalah destructor Destroy yang akan memanggil procedure ClearControls terlebih dahulu

destructor TControlArray.Destroy;
begin
  // karena tidak memanfaat mekanisme owner
  // maka semua kontrol harus di-free dulu.
  ClearControls;
  inherited;
end;

Sampai disini objek TControlArray sudah bisa digunakan. Jangan lupa uses ke Controls.

Cara Penggunaan

Cara penggunaannya sangat mudah. Pertama siapkan sebuah variabel yang bertipe TControlArray. Jangan lupa uses ke unit tempat TControlArray berada. Create variabel tersebut dengan melewatkan TEdit sebagai parameter. Kalo ingin membuat array of TButton, tinggal ganti TEdit dengan TButton.

procedure TForm1.FormCreate(Sender: TObject);
begin
  FControlArray := TControlArray.Create(TEdit);
end;

Kemudian kita panggil method BuildControl untuk mengcreate komponen sebanyak m x n. Misalnya kita buat komponen sebanyak 4 x 15.

procedure TForm1.BtnCtrlBuildClick(Sender: TObject);
begin
  FControlArray.BuildControls(Self, 4, 15, 20, 50, 100, 21, 5, 5);
end;

Untuk mengakses setiap komponen sedikit agak kompleks, karena kita harus melakukan typecasting. Misalnya kita ingin mengeset property Text dari semua kontrol dengan asumsi bahwa kontrol yang dibuat adalah TEdit.

procedure TForm1.BtnCtrlSetTextClick(Sender: TObject);
var i, j: Integer;
begin
  for i:=0 to FControlArray.ColCount-1 do begin
    for j:=0 to FControlArray.RowCount-1 do begin
      if FControlArray.GetControl(i, j) is TEdit then begin
        TEdit(FControlArray.GetControl(i, j)).Text :=
          Format('%d, %d', [i+1, j+1]);
      end;
    end;
  end;
end;

Array of TEdit

Agar lebih mantap, kita turunkan TControlArray menjadi TEditArray sehingga cara aksesnya agak mirip dengan array.

Pertama, kita definisikan objek TEditArray sebagai berikut

  TEditArray = class (TControlArray)
  private
    function GetEdits(col, row: Integer): TEdit;
  public
    constructor Create;
    property Edits[col, row: Integer]: TEdit
      read GetEdits; default;
  end;

Kita hanya perlu mendefinisikan ulang method Create agar tidak perlu melewatkan parameter ControlClass, sehingga implementasinya adalah sebagai berikut

constructor TEditArray.Create;
begin
  inherited Create(TEdit);
end;

Kemudian kita definisikan sebuah array property dengan nama Edits dengan parameter col dan row. Tipe properti ini adalah TEdit dan hanya dapat diakses secara readonly melalui method GetEdits. Option default ditambahkan agar objek ini bisa diakses secara langsung (seperti array). Implementasi dari function GetEdits adalah sebagai berikut

function TEditArray.GetEdits(col, row: Integer): TEdit;
var vControl: TControl;
begin
  vControl := GetControl(col, row);
  if vControl is TEdit then begin
    result := TEdit(GetControl(col, row));
  end else begin
    result := nil;
  end;
end;

Pada function diatas, function GetControl dipanggil dan dilakukan typecasting menjadi edit. Sebelumnya diperiksa dulu untuk memastikan bahwa kontrol yang diakses adalah TEdit, agar tidak terjadi error.

Cara penggunaannya menjadi lebih mudah. Pada saat objek TEditArray di-create, parameter ControlClass tidak perlu dilewatkan. Perbedaan lainnya adalah akses ke kontrol menjadi lebih mudah (mirip array).

procedure TForm1.BtnEditSetTextClick(Sender: TObject);
var i, j: Integer;
begin
  for i:=0 to FEditArray.ColCount-1 do begin
    for j:=0 to FEditArray.RowCount-1 do begin
      FEditArray[i, j].Text := Format('%d, %d', [i+1, j+1]);
    end;
  end;
end;

Source kode dapat diperoleh di repository source code Delphindo dengan nama ArrayOfControl.zip.

6 Comments »

RSS feed for comments on this post. TrackBack URI

  1. Saya rasa TControlArray pun bisa ditambahi properti array untuk mengakses control agar lebih mirip array

    TControlArray=class

    public

    property Controls[col,row:integer]:TControl read GetControl;

    end

  2. Betul !
    Lebih mantep lagi kalo definisi property Controls ditambahi default di belakangnya

  3. klo masing2 kontrol misalnya TEdit mau saya beri event gmn caranya…?

    contoh: saya mau agar semua Tedit hanya bisa ditulisi angka saja…
    klo biasanya kan di taruh di event onKeyPress

    klo yg ini…
    gimna caranya pak kus?

  4. Event itu sama dengan property cuma tipenya procedure. Selama kita bisa ngeset property, berarti kita bisa ngeset event.

    Buat event untuk cek edit tersebut, misalnya dengan nama CekEdit.

    var i, j: Integer;
    begin
    for i:=0 to FEditArray.ColCount-1 do begin
    for j:=0 to FEditArray.RowCount-1 do begin
    FEditArray[i, j].OnKeypres := CekEdit;
    end;
    end;
    end;

  5. hi..
    gmn ya caranya memsukan data paralel port ke tabel delphi, data dari paralel port sudah dapat dibaca dengan menggunakan komponen TLabel. tapi saya gak tw cara masukin data itu ke tabel trs dari tabel akan saya tampilkan ke chart delphi..
    mohon bantuannya

  6. Kl codingan untuk penjumlahan bilangan biner?


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.
Entries and comments feeds.

%d bloggers like this: