Menciptakan form dengan bentuk sembarang

November 18, 2008 at 4:49 pm | Posted in Code Samples, Tutorials | 4 Comments
Tags: , , , , ,

oleh Zamrony P. Juhara

Pernah menggunakan WinAmp? Terkesan dengan window berbentuk sembarang mengikuti skin yang digunakan? Saya pribadi sangat terkesan dengan sistem skin pada WinAmp. Artikel berikut ini mencoba menjelaskan bagaimana kita dapat menghasilkan sistem skin dengan menciptakan form dengan bentuk sembarang (tidak lagi harus kotak).

Artikel ini adalah perluasan apa yang di bahas Corbin Dunn di artikelnya Creating Transparent Window. Di artikel tersebut, Dunn menciptakan window berbentuk aneh yang benar-benar tak terlihat dengan kontrol yang dapat dilihat berada di atasnya.

Kita akan mendiskusikan cara untuk menciptakan form window dengan bentuk sembarang sesuai pola yang kita tentukan melalui suatu bitmap. Idenya mirip dengan cara bagaimana sprite pada game bekerja. Kita potong window berdasarkan pixel-pixel pada bitmap. Jika kita temukan pixel dengan warna yang kita anggap sebagai warna transparan, bagian window akan kita potong, jika bukan warna transparan, kita tampilkan.

Artikel ini ditujukan sekedar untuk menunjukkan bagaimana teknik ini bekerja, sehingga contoh kode yang ada, sengaja dibuat sesederhana mungkin yang mungkin menghasilkan kode yang lambat dan kurang optimal. Anda bebas mengubahnya sesuai kebutuhan Anda. Proyek demo dapat didownload di CodeCentral CodeGear

Region

Sebelum kita beranjak, kita harus memahami apa itu region. Menurut Microsoft, definisi region adalah

Region is a rectangle, a circle or ellipse or combination of these shapes that can be filled, painted, inverted, framed and used to perform hit testing.

Kita dapat menciptakan sembarang bentuk dengan menggabungkan banyak bentuk dasar region berukuran kecil seperti kotak. Pertanyaannya sekarang, bagaimana kita melakukannya? Pertanyaan ini membimbimg kita ke bagian berikutnya yakni menciptakan region.

Penciptaan region

Untuk menciptakan region, kita menggunakan fungsi Windows API CreateRectRgn(), CreateRectRgnIndirect(), CreateEllipticRgn() dan lain-lain. Untuk artikel ini, saya hanya akan menggunakan fungsi CreateRectRgn(). Anda bisa menggunakan fungsi lain jika ingin bereksperimen.

CreateRectRgn() mengembalikan handle ke region yang berhasil diciptakan. Bila gagal, nilai kembali fungsi ini adalah nol.

Pastikan Anda menyimpan handle ini, karena semua operasi region membutuhkan handle tersebut.

Mari lihat contoh kode:

 myRegionHandle:=CreateRectRgn(0,0,400,300);

Tidak terlalu mengesankan, namun itu sebuah awal. Kode di atas akan menciptakan region berbentuk kotak dengan panjang dan tinggi sebesar 400×300 pixel. Menurut Microsoft, sisi kanan bawah tidak termasuk region (exclusive).

Unttuk menciptakan region 1×1 pixel, Anda menggunakan kode berikut

 myRegionHandle:=CreateRectRgn(0,0,1,1);

Ok, kita sudah tahu cara menciptakan region, lalu bagaimana region berbentuk sembarang? Jawabannya dengan menggabung sejumlah region berukuran 1×1 pixel menjadi region yang lebih besar.

Menggabung Region

Untuk menggabung region-region, Anda menggunakan fungsi CombineRgn(). Fungsi ini membutuhkan handle region tujuan, handle region sumber pertama dan kedua serta operasi region yang ingin dilakukan. Fungsi ini mengembalikan nilai integer berisi tipe region yang dihasilkan. Saya tidak membutuhkannya sehingga informasi ini tidak terlalu penting.

CombineRgn(destHRgn,srcHRgn1,srcHRgn2,RGN_OR);

Contoh kode di atas menggabung region yang ditunjuk oleh srcHRgn1 dan srcHRgn2, melakukan operasi OR (union) dan menyimpan hasilnya di region yang ditunjuk oleh destHRgn. Region yang ditunjuk oleh destHRgn harus sudah ada agar fungsi ini sukses.

Selain mode kombinasi RGN_OR, ada mode RGN_AND, RGN_XOR dan RGN_COPY. Namun untuk keperluan kita membuat window berbentuk sembarang, mode kombinasi region tersebut tidak cocok.

Membangun Region Berbentuk Sembarang

Kita sudah punya pengetahuan bagaimana menciptakan region dan menggabungkan beberapa region untuk membentuk region yang lebih besar. Selanjutnya mari kita implementasikan untuk membangun region berbentuk sembarang.

Untuk itu, Anda butuh gambar bitmap untuk dijadikan pola.

Bitmap untuk pola pemotongan region

Bitmap untuk pola pemotongan region

Saya sarankan menggunakan bitmap karena mudah untuk memeriksa warna pixel yang dianggap sebagai warna transparan. Untuk format lain seperti JPEG, ketika kita menggambar warna hitam pekat RGB(0,0,0), algoritma JPEG mungkin akan menyimpan nilai lain yang mendekati warna hitam namun bukan RGB(0,0,0) seperti yang kita harapkan. Ini mungkin menghasilkan region dengan bentuk yang tidak sesuai keinginan.


function BuildRegion(ABitmap: TBitmap; 
               const transColor:TColor): HRGN;
var i,j:integer;
     rgnAll,rgnTemp:HRGN;
begin
   rgnAll:=0;
   for i:=0 to ABitmap.Height-1 do
   for j:=0 to ABitmap.Width-1 do
   begin
      if ABitmap.Canvas.Pixels[j,i]<>TransColor then
      begin
        //if tidak ada region, ciptakan satu
        if rgnAll=0 then
        begin
            rgnAll:=CreateRectRgn(j,i,j+1,i+1);
        end else
        begin
           rgnTemp:=CreateRectRgn(j,i,j+1,i+1);
           //tambahkan region with rgn_or
           CombineRgn(rgnAll,rgnAll,rgnTemp,RGN_OR);
           //hapus region, kita sudah tidak butuh
           DeleteObject(rgnTemp);
        end;
      end;
    end;
    result:=rgnAll;
end;

Mengaktifkan Region ke Window

Kita sudah punya region yang berbentuk sembarang. Agar region tersebut digunakan oleh window dan efeknya terlihat visual, Anda harus mengaktifkan region tersebut menggunakan fungsi Windows API SetWindowRgn(). Fungsi ini butuh tiga parameter. Parameter pertama adalah handle window, parameter kedua berisi handle region dan parameter terakhir adalah nilai boolean untuk mengaktifkan/menonaktifkan region.

Kode berikut ini adalah contoh penggunaan BuildRegion().


rgnHandle:=BuildRegion(ABitmap,FTransparentColor);
SetWindowRgn(AWindowHandle,rgnHandle,true);

Sentuhan Akhir

Coba perhatikan gambar screenshot proyek demo artikel ini.

Screenshot proyek demo. Perhatikan bagaimana form dipotong mengikuti bentuk bitmap

Screenshot proyek demo. Perhatikan bagaimana form dipotong mengikuti bentuk bitmap

Untuk menciptakan form seperti yang terlihat pada screenshot di atas, saya membuat handler untuk event OnPaint milik TForm seperti pada porongan kode berikut ini.


procedure TForm1.FormPaint(Sender:TObject);
begin
  Canvas.Draw(0,0,ABitmap);
end;

ABitmap adalah instance TBitmap, berisi gambar pola. Saya juga mengubah ClientWidth dan ClientHeight form sesuai isi lebar dan tinggi bitmap. Tampilannya bagus bila property FormStyle milik form diisi bsNone. Namun hal ini akan menyebabkan non client area form (bagian Caption) tidak akan tampil sehingga Anda harus menyediakan mekanisme untuk yang mengijinkan form dipindah-pindah dengan drag drop form pada client area.

Source code proyek demo dapat di download di CodeCentral CodeGear.

Penutup

Di artikel ini, Anda telah belajar bagaimana menggunakan bitmap untuk menciptakan form berbentuk sembarang menggunakan fungsi-fungsi manipulasi region Windows API. Ini adalah langkah dasar untuk membuat sistem skin yang lebih kompleks.

4 Comments »

RSS feed for comments on this post. TrackBack URI

  1. saya sudah mengaplikasikan tutor ini. dan berhasil. menarik sekali..

    saya ada pertanyaan, adakah kelemahan penggunaan bitmap..?

  2. bitmap ukurannya relatif besar dibandingkan format terkompresi lain

  3. MANTAP !!!! … langsung praktek

  4. Kalau penjumlahan biner dengan delphi?


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

Blog at WordPress.com.
Entries and comments feeds.

%d bloggers like this: