Anda di halaman 1dari 147

Algoritma

dalam
Bahasa C
Apa Itu Algoritma
Kata algoritma, mungkin bukan sesuatu yang asing bagi kita.
Penemunya adalah seorang ahli matematika dari Uzbekistan yang bernama Abu Abdullah
Muhammad Ibn Musa al- Khwarizmi (770-840). Di literatur barat dia lebih terkenal
dengan sebutan Algorizm. Panggilan inilah yang kemudian dipakai untuk menyebut konsep
algorithm yang ditemukannya.
Dalam bahasa Indonesia kita kemudian menyebutkannya sebagai algoritma.
Algoritma adalah kunci dari bidang ilmu komputer, karena banyak bidang di bawah ilmu
komputer yang lahir berdasarkan konsep algoritma ini. Pada hakekatnya algoritma juga
adalah kunci dari kehidupan kita. Cara membuat masakan (resep masakan) adalah juga
sebuah contoh nyata dari algoritma.

Definisi Algoritma
Kita bisa mendefinisikan algoritma seperti dibawah:
Algoritma adalah logika, metode dan tahapan (urutan) sistematis yang digunakan untuk
memecahkan suatu permasalahan.

Kamus besar bahasa Indonesia (Balai Pustaka 1988) secara formal mendefinisikan algoritma
sebagai:
Algoritma adalah urutan logis pengambilan putusan untuk
pemecahan masalah.

Beda Algoritma dan Program


Program adalah kompulan instruksi komputer, sedangkan metode dan tahapan
sistematis dalam program adalah algoritma. Program ini ditulis dengan menggunakan
bahasa pemrograman. Jadi bisa kita sebut bahwa program adalah suatu implementasi dari
bahasa pemrograman.

Beberapa pakar memberi formula bahwa:


program = struktur data + algoritma

Created By Muhammad Syahrizal 1


Bagaimanapun juga struktur data dan algoritma berhubungan sangat erat pada sebuah
program. Algoritma yang baik tanpa pemilihan struktur data yang tepat akan membuat
program menjadi kurang baik, semikian juga sebaliknya.
Struktur data disini bisa berupa list, tree, graph, dsb. Akan dibahas secara mendetail pada
bab-bab mendatang.

Menilai Sebuah Algoritma


Ketika manusia berusaha memecahkan masalah, metode atau teknik yang digunakan untuk
memecahkan masalah itu ada kemungkinan bisa banyak (tidak hanya satu). Dan kita
memilih mana yang terbaik diantara teknik-teknik itu. Hal ini sama juga dengan algoritma,
yang memungkinkan suatu permasalahan dipecahkan dengan metode dan logika yang
berlainan.

Lalu bagaimana mengukur mana algoritma yang terbaik ?


Beberapa persyaratan untuk menjadi algoritma yang baik adalah:
• Tingkat kepercayaannya tinggi (realibility). Hasil yang diperoleh dari proses harus
berakurasi tinggi dan benar.
• Pemrosesan yang efisien (cost rendah). Proses harus diselesaikan secepat mungkin dan
frekuensi kalkulasi yang sependek mungkin.
• Sifatnya general. Bukan sesuatu yang hanya untuk menyelesaikan satu kasus saja, tapi juga
untuk kasus lain yang lebih general.
• Bisa Dikembangkan (expandable). Haruslah sesuatu yang dapat kita kembangkan lebih jauh
berdasarkan perubahan requirement yang ada.
• Mudah dimengerti. Siapapun yang melihat, dia akan bisa memahami algoritma anda. Susah
dimengertinya suatu program akan membuat susah di maintenance (kelola).
• Portabilitas yang tinggi (Portability). Bisa dengan mudah diimplementasikan di berbagai
platform komputer.

Contoh Algoritma dan Implementasinya


Sebagai contoh sederhana, mari kita berlatih melihat permasalahan, mencoba
menyusun algoritma, dan meng-implementasi-kan dalam bahasa C.

Permasalahan
Anda adalah seorang guru SD yang ingin membuat rangking dari nilai ujian dari 9 orang murid anda. Nilai
ujian murid anda adalah sebagai berikut:

Bagaimana algoritma dalam pembuatan rangking nilai tersebut ?


Untuk memecahkan masalah diatas, kita bisa susun algoritma seperti dibawah:
1. Buat satu variable (misalnya rangking)
2. Set variable rangking = 1
3. Ambil satu nilai sebagai data yang ke a, misalnya 56
4. Chek nilai dari paling depan (56) sampai paling belakang (32) (b=0-8).
Apabila nilai tersebut lebih tinggi daripada nilai ke a (56), maka set
variable rangking = ranking + 1.
5. Ulangi proses nomor 2 dengan mengambil data ke (a) berikutnya.

Created By Muhammad Syahrizal 2


Kemudian mari kita implementasikan algoritma diatas dalam program bahasa C.

Program: Rangking Nilai Ujian


#include <stdio.h>
#define banyaknya_nilai 9
main(){
static int nilai[]={56, 78, 43, 96, 67, 83, 51, 74, 32};
int rangking[banyaknya_nilai];
int a,b;
for (a=0;a<banyaknya_nilai;a++){
rangking[a]=1;
for (b=0;b<banyaknya_nilai;b++){
if (nilai[a]>nilai[b])
rangking[a]++;
}
}
printf("Nilai Ujian \t Rangking\n");
for (a=0;a<banyaknya_nilai;a++){
printf("%d \t\t %d\n",nilai[a], rangking[a]);
}
}

Hasil
Nilai Ujian Rangking
56 4
78 7
43 2
96 9
67 5
83 8
51 3
74 6
32 1

Created By Muhammad Syahrizal 3


Membilang dalam Bahasa
Indonesia
Dalam aplikasi yang berhubungan dengan uang , kadang – kadang diperlukan pernyataan
nilai nominal tidak hanya dengan angka , tapi juga diperlukan pernyataan dalam bentuk
terbilangnya. Tentu saja jika dibandingkan dengan pernyataan dengan angka , pernyataan
dengan membilang lebih banyak membutuhkan ruang . Tapi disamping itu pernyataan
dengan membilang bisa meminimkan jumlah kesalahan yang terjadi karena faktor
kesalahan pembacaan .

Untuk itu dalam kesempatan ini kita akan membuat sebuah fungsi yang dapat digunakan
untuk merubah nilai menjadi bentuk terbilangnya. Di internet , tentunya sudah sangat
banyak sekali source code yang di publish untuk keperluan ini , bahkan dengan listing
yang cukup pendek. Tapi tentunya sebagai programer kita akan lebih tertantang jika
mampu membuat fungsi tersebut sendiri . Untuk akan saya bahas alur / logika
pemrogramannya , sehingga mudah untuk di translasikan dalam bahasa pemrograman
lain.

Untuk bisa membuat fungsi membilang dalam bahasa Indonesia kita harus tahu dulu ,
cara manusia membilang bilangan . Untuk itu mari kita analisa proses tersebut !!!!!
Bilangan satuan
0 -> nol
1 -> satu
9 -> sembilan
Ket : “->” berarti “dibaca”

Untuk proses membilang bilangan satuan tentunya tidak terlalu susah jika di
implementasikan dalam bahasa C . Anda bisa menggunakan seleksi untuk masing masing
bilangan . Tapi penulis akan menggunakan bantuan array

Berikut ialah potongan source codenya fungsi untuk membilang bilangan satuan
char StrBilangan[10][10] =
{"nol","satu","dua","tiga","empat","lima","enam","tujuh","delapan","sembi
lan"};
void SaySatuan(char nilai) //0..9
{
printf("%s",StrBilangan[nilai]);
}

Bilangan puluhan
10 -> sepuluh
11 -> sebelas
12 -> dua belas
13 -> tiga belas
19 -> sembilan belas
20 -> dua puluh

Created By Muhammad Syahrizal 4


21 -> dua puluh satu
45 -> empat puluh lima
99 -> sembilan puluh delapan

Secara umum untuk membilang bilangan puluhan bisa dilakukan dengan cara membilang
puluhannya secara satuan dan kemudian diikuti dengan “puluh” dan dilanjutkan dengan
membilang satuannya jika nilaisatuannya bukan 0.

Untuk lebih jelas mari kita perhatikan contoh berikut


Contoh : Kita akan membilang nilai 35
Kita ambil puluhannya dahulu . Untuk mengambil nilai puluhannya bisa didapat dengan
membaginya dengan 10 .
NilaiPuluhan = 35 / 10 = 3
Nilai Satuan bisa didapat dengan mengambil sisa pembagian dengan bilangan 10
NilaiSatuan = 35 % 10 = 5

Nah setelah dapat kita tinggal menggunakan cara diatas :


SaySatuan(NilaiPuluhan) + “puluh” + SaySatuan(NilaiSatuan)*SaySatuan ialah fungsi
untuk mencetak nilai satuan .Maka akan terbentuk tiga puluh lima Contoh berikutnya kita
ambil 40
NilaiPuluhan = 4
NilaiSatuan = 0

Karena nilai satuan sama dengan 0 untuk itu kita tidak perlu membilang nilai satuannya
jadi cukup dengan :
SaySatuan(NilaiPuluhan) + “puluh”
Maka akan didapat hasil “empat puluh"
Jadi jelaslah maksud kata jika nilainya bukan 0 , yaitu untuk menghindari terjadinya
(pada kasus 40) tercetak empat puluh nol Cara diatas memang benar untuk sebagian besar
nilai puluhan tapi ada beberapa nilai yang perlu perkecualian . Dari contoh data analisa
diatas dapat dilihat bahwa nilai 10,11,12 .. 19 tidak memenuhi cara diatas. Tapi jika
dianalisa lebih lanjut bilangan 12..19 ternyata memiliki pola yang sama yaitu :
membilang satuan dan diikuti dengan kata belas Untuk contoh saya ambil 14.
NilaiSatuan = 4 .

Maka dengan menggunakan cara diatas :


SaySatuan(NilaiSatuan) + “belas”

Untuk 10 dan 11 anda bisa gunakan seleksi biasa .


Berikut ialah source code untuk membilang bilangan puluhan .
void SayPuluhan(char nilai) // 10..99
{
if (nilai < 10) // seleksi , jika lebih kecil dari 10
SaySatuan(nilai); // tentunya masuk ke fungsi SaySatuan
else
{
if (nilai == 10)
printf("sepuluh");

Created By Muhammad Syahrizal 5


if (nilai == 11)
printf("sebelas");
if (nilai >= 12 && nilai <= 19)//Cetak satuan diikuti dengan belas
{
SaySatuan(nilai % 10); // Satuan bisa dicari dengan memodulo
printf("belas"); // bilangan dengan 10 ( mencari hasil sisa
} // pembagian
if (nilai >= 20 && nilai <= 99) //Cetak puluhan diikuti kata puluh
{ // kemudian cetak satuan
SaySatuan(nilai / 10); // Nilai Puluhan bisa dicari dengan
printf(" puluh "); // membaginya dengan 10
SaySatuan(nilai % 10);
}
}
}

Bilangan ratusan
100 -> seratus
101 -> seratus satu
110 -> seratus sepuluh
189 -> seratus delapan puluh sembilan
200 -> dua ratus
201 -> dua ratus satu
999 -> sembilan ratus sembilan puluh sembilan

Dapat dilihat bilangan ratusan juga memilik pola yang secara umum hampir sama yaitu :
membilang nilai ratusannya diikuti kata ratus dan dilanjutkan dengan membilang nilai
puluhannya jika nilai puluhannya bukan 0.

Kita ambil contoh 223


NilaiRatusan = 223 / 100= 2
NilaiPuluhan = 223 % 100 = 23
Dengan cara diatas didapat :
SaySatuan(NilaiRatusan) + “ratus” + SayPuluhan(NilaiPuluhan)

Tentunya jika fungsi SayPuluhan anda benar akan tercetak :


dua ratus dua puluh tiga

Untuk perkecualian yaitu bilangan antara 100..199 . Untuk bilangan tersebut dapat
dibilang dengan rumus Cetak “seratus” diikuti dengan membilang bilanga puluhannya
Berikut ialah cuplikan SourceCodenya dalam C
void SayRatusan(int nilai) // 100..999
{
if (nilai < 100)
SayPuluhan(nilai); // seleksi , jika puluhan
else
{
if(nilai >= 100 && nilai <= 199) // jika dibawah 200 gunakan kata
printf("seratus "); // seratus

Created By Muhammad Syahrizal 6


if (nilai >= 200 && nilai <= 999) // jika diatasnya , bilang nilai
{ // ratusannya diikuti dengan kata
SaySatuan(nilai / 100);
printf(" ratus "); // ratus
}
if(nilai % 100 != 0) //Hindari jika kelipatan 100
SayPuluhan(nilai % 100); //Bilang nilai puluhannya
}
}

Bilangan ribuan
1.000 -> seribu
1.100 -> seribu seratus
2.111 -> dua ribu seratus sebelas
10.000 -> sepuluh ribu
25.250 -> dua puluh lima ribu dua ratus lima puluh
130.750 -> seratus tiga puluh ribu , tujuh ratus lima puluh
999.999 -> sembilan ratus sembilan puluh sembilan ribu , sembilan ratus sembilan puluh
sembilan

Jika diperhatikan ternyata untuk mencetak bilangan ribuan caranya sama sampai
mencetak bilangan ratusan ribu yaitu : bilang nilai ribuannya diikuti dengan kata “ribu”
dan dilanjutkan dengan bilang nilai ratusannya jika nilai ratusannya bukan 0.

Sebagai contoh saya akan ambil 256.750


NilaiRibuan = 256.750 / 1000 = 256
NilaiRatusan = 256.750 % 1000 = 750
Dengan menggunakan cara diatas :
SayRatusan(NilaiRibuan) + “ribu” + SayRatusan(NilaiRibuan)
Tentunya jika Fungsi SayRatusan anda benar akan tercipta :
dua ratus lima puluh enam ribu tujuh ratus lima puluh

Dan seperti biasa perkecualian terdapat pada bilangan antara 1000..1999 , yaitu cukup
dengan mencetak “seribu” diikuti dengan membilang nilai ratusannya jika tidak 0
void SayRibuan(unsigned long nilai) //1000...999999
{
if (nilai < 1000)
SayRatusan(nilai); //Seleksi jika ratusan
else
{
if (nilai >= 1000 && nilai <= 1999) //Seleksi nilai dibawah 2000
printf("Seribu ");
if (nilai >= 2000 && nilai <= 999999)
{
SayRatusan(nilai/1000); //Cetak digit ribuan secara Ratusan
printf(" ribu "); // diikuti kata ribu
}
if (nilai % 1000 != 0) // seleksi kelipatan 1000
SayRatusan(nilai % 1000); // diikuti dengan mencetak digit sisanya
}
}

Created By Muhammad Syahrizal 7


Begitu pula halnya untuk bilangan diatas 999.999 . Tidak terlalu susah bukan ?
Ternyata untuk membuat fungsi membilang anda hanya perlu operator bagi (/) dan
modulus (%), dan tentunya sedikit analisa Sebenarnya program diatas masih cukup
panjang dan tentunya masih bisa dipendekkan dan dioptimasi lagi. Nah untuk tugas ini
saya serahkan sepenuhnya kepada pembaca saja .

Berikut ialah source code lengkap program membilang tersebut


#include <stdio.h>
char StrBilangan[10][10] =
{"nol","satu","dua","tiga","empat","lima","enam","tujuh","delapan","sembi
lan"};
void SaySatuan(char nilai) //0..9
{
printf("%s",StrBilangan[nilai]);
}
void SayPuluhan(char nilai) // 10..99
{
if (nilai < 10)
SaySatuan(nilai);
else
{
if (nilai == 10)
printf("sepuluh");
if (nilai == 11)
printf("sebelas");
if (nilai >= 12 && nilai <= 19)
{
SaySatuan(nilai % 10);
printf("belas");
}
if (nilai >= 20 && nilai <= 99)
{
SaySatuan(nilai / 10);
printf(" puluh ");
SaySatuan(nilai % 10);
}
}
}
void SayRatusan(int nilai) // 100..999
{
if (nilai < 100)
SayPuluhan(nilai);
else
{
if(nilai >= 100 && nilai <= 199)
printf("seratus ");
if (nilai >= 200 && nilai <= 999)
{
SaySatuan(nilai / 100);
printf(" ratus ");
}
if(nilai % 100 != 0) //untuk menghindari seratus nol
SayPuluhan(nilai % 100);
}

Created By Muhammad Syahrizal 8


}
void SayRibuan(unsigned long nilai) //1000...999999
{
if (nilai < 1000)
SayRatusan(nilai);
else
{
if (nilai >= 1000 && nilai <= 1999)
printf("Seribu ");
if (nilai >= 2000 && nilai <= 999999)
{
SayRatusan(nilai/1000);
printf(" ribu ");
}
if (nilai % 1000 != 0)
SayRatusan(nilai % 1000);
}
}
void SayJuta(unsigned long nilai) //1.000.000 -> 999.999.999
{
if (nilai < 1000000)
SayRibuan(nilai);
else
{
SayRatusan(nilai / 1000000);
printf(" juta ");
if(nilai % 1000000 != 0)
SayRibuan(nilai % 1000000);
}
}
void SayMilyar(unsigned long nilai) // 1.000.000.000 -> 999.999.999.999
{
if (nilai < 1000000000)
SayJuta(nilai);
else
{
SayRatusan(nilai / 1000000000);
printf(" Milyar ");
if(nilai % 1000000000 != 0)
SayJuta(nilai % 1000000000);
}
}
void SayBilangan(unsigned long nilai) // Fungsi pengarah
{
if (nilai <= 9)
SaySatuan(nilai);
if (nilai >= 10 && nilai <= 99)
SayPuluhan(nilai);
if (nilai >= 100 && nilai <= 999)
SayRatusan(nilai);
if(nilai >= 1000 && nilai <= 999999)
SayRibuan(nilai);
if(nilai >= 1000000 && nilai <= 999999999)
SayJuta(nilai);
if(nilai >= 1000000000)
SayMilyar(nilai);

Created By Muhammad Syahrizal 9


}
void main(void)
{
SayBilangan(163);
SayBilangan(25234);
SayBilangan(-1);
}

Analisa Numerik:
Mengecek Bilangan Prima
Bilangan Prima ialah Bilangan yang hanya memiliki 2 faktor yaitu , 1 dan bilangan itu
sendiri.
Contoh :
7 merupakan bilangan Prima karena 7 hanya memiliki 2 faktor yaitu 1 dan 7 saja
8 bukan merupakan bilangan Prima karena 8 bisa memiliki lebih dari 2 faktor yaitu :
1248

Dengan menggunakan pengertian diatas dapat dibuat algoritma :


1. Input N // N = Bilangan Prima yang akan di cek
2. counter = 0 // counter menyatakan jumlah faktor
3. FOR I = 1 to N step = 1 // step langkah setiap perulangan (i++)

Jika N % I == 0 maka // Jika N habis di bagi I counter++ //Tambahkan Counter


4. Jika counter == 2 maka “N Bilangan Prima”
Jika Tidak “N Bukan Bilangan Prima”
Jika kita telaah lebih lanjut , untuk mengecek bilangan ke N maka diperlukan N kali
iterasi (langkah 3 ) . Oke kalau begitu mari kita sederhanakan lagi Kita tahu bahwa

1. Bilangan genap kecuali 2 bukan merupakan bilangan prima


2. Bilangan Genap ialah bilangan yang kelipatan 2
3. Setiap Bilangan pasti memiliki faktor 1 dan bilangan itu sendiri

Karena semua bilangan genap kecuali bukan prima dan Bilangan genap merupakan
kelipatan 2 jadi kita dapat menskip pembagian dengan bilangan genap (step = 2) asalkan
pertama kali dilakukan pengecekan bilangan genap.
Karena Setiap bilangan pasti memiliki faktor 1 dan bilangan itu sendiri jadi kita tidak
perlu mencek 1 dan bilangan itu sendiri , tapi cukup mulai dari 2 sampai dengan n -1
.Jika ada faktor pada range tersebut sudah barang tentu bahwa bilangan tersebut bukan
bilangan prima.

Created By Muhammad Syahrizal 10


Baiklah mari kita sempurnakan algoritmanya
1. Input N
2. Jika N == 2 maka // 2 Merupakan Bilangan Prima
“N Bilangan Prima”
3. Jika N % 2 == 0 maka // Bilangan Genap bukan bilangan Prima
“N Bukan Bilangan Prima”
4. FOR I = 3 To N-1 STEP 2 // Tidak perlu mengadakan pengecekan
Jika N % I == 0 maka // terhadap bilangan genap “N Bukan Bilangan Prima”
5. “N Bilangan Prima

Dengan sedikit analisis , algoritma diatas telah mampu dioptimasi . Jika sebelumnya
untuk mengecek bilangan ke N pasti memerlukan N iterasi . Maka pada keadaan sekarang
jika bilangan itu bilangan genap maka tidak perlu itersi ( best case ) jika bukan bilangan
genap maka diperlukan paling banyak N / 2 iterasi ( worst case ) .

Ternyata ada sebuah optimasi lagi yang dapat dilakukan . Apa itu ??? . Sebelumnya mari
kita lihat sama – sama tabel di bawah ini:

Tabel Diatas ialah Tabel Faktor dari 8 .


Kalau diperhatikan ternyata pada nilai 4 ( kolom 1 baris 3 ) sudah ada pada kolom 2 .

Contoh lain

Tabel diatas ialah Tabel Faktor dari 12 . Kalau diperhatikan ternyata nilai 4 (kolom 1
baris)sudah ada pada kolom 2 .

Apa yang bisa diambil dari contoh diatas ? , apa yang bisa dimanfaatkan untuk
mengoptimasi algoritma pengecekan bilangan prima diatas ??
Dari tabel dapat disimpulkan :
faktor 8 :
8 : 1 = 8 ; 8 : 2 = 4 ; 8 : 4 = 2 dst

Created By Muhammad Syahrizal 11


pada kasus nilai 8 tidak perlu diadakan pengecekan melebihi dari nilai 2
faktor 12 :
12 : 1 = 12 ; 12 : 2 = 6 ; 12 : 3 = 4 ; 12 : 4 = 3 dst
pada kasus nilai 12 tidak perlu diadakan pengecekan melebihi dari nilai 3

Artinya kita tidak perlu mengecek semua faktor dari bilangan. melainkan cukup
setengahnya dari faktornya saja yaitu pada akar dari bilangan tersebut , karena faktor
sisanya merupakan hasil pembagian dari bilangan tersebut dengan faktornya .

Nah dengan analisis tersebut algoritma diatas dapat disederhanakan menjadi :


1. Input N
2. Jika N == 2 maka
“N Bilangan Prima”
3. Jika N % 2 == 0 maka
“N Bukan Bilangan Prima”
4. FOR I = 3 To Sqrt(N) STEP 2 // Sqrt(N) -> Akar dari N
Jika N % I == 0 maka “N Bukan Bilangan Prima”
5. “N Bilangan Prima

Algoritma diatas membutuhkan 0 itersi saat N bilangan genap . Sedangkan membutuhkan


maksimum Akar(N) iterasi saat bilangan tersebut bukan bilangan genap .
Berikut Source code lengkap dari algoritma diatas .
#include <stdio.h>
#include <math.h>
int isprima(int n)
{
int li;
if (n == 2)
return 1;
if (n % 2 == 0 || n == 1)
return 0;
for(li = 3;li <= sqrt(n);li+=2)
{
if (n%li == 0)
return 0;
}
return 1;
}
void main(void)
{
int li;
printf("Bilangan prima dari 1 sampai 100 : \n");
for(li = 1;li<=100;li++)
if (isprima(li))
printf("%3d",li);
}

Berikut Hasil dari source code diatas :


Bilangan Prima dari 1 sampai 100 :
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Created By Muhammad Syahrizal 12


Rekursiif
Pengenalan
Rekursif ialah salah satu teknik pemrograman dengan cara memanggil sebuah fungsi dari
dirinya sendiri, baik itu secara langsung maupun tidak langsung. Pemanggilan fungsi
rekursif secara langsung berarti dalam fungsi tersebut terdapat statement untuk
memanggil dirinya sendiri sedangkan secara tidak langsung berarti fungsi rekursif
tersebut memanggil 1 atau lebih fungsi lain sebelum memanggil dirinya sendiri.

Fungsi Rekursif Tak Langsung

Rekursif tidak selalu lebih jelek daripada iteratif . Ada kalanya sebuah fungsi rekursif
justru mempermudah penyelesaian masalah yang ditemui pada kasus iteratif
(pengulangan)
Kelemahan pada proses rekursif antar lain, memerlukan tempat penampungan stack yang
cukup besar. Karena setiap kali pemanggilan fungsi , register – register seperti cs ( untuk
memory far ) dan ip harus disimpan , belum lagi untuk penanganan local variable serta
parameter fungsi yang tentunya membutuhkan ruang untuk stack lebih banyak lagi .
Selain itu karena setiap pemanggilan fungsi , register dan memory harus di push ke stack
maka setelah selesai pemanggilan perlu diadakannya pop stack . untuk mengembalikan
memory dan register kembali ke keadaan awal , ini sering disebut sebagai overhead .

Proses Rekursif
Untuk dapat memahami proses yang terjadi dalam sebuah fungsi rekursif , marilah kita
simak contoh fungsi rekursif berikut :

Created By Muhammad Syahrizal 13


Misalkan Fungsi tersebut dipanggil dengan nilai a = 3 dan b = 3 maka pertama tama di
cek apakah b = 0 (if (b == 0) return), jika sama maka keluar. Ternyata nilai b tidak
sama dengan 0 maka tambahkan a dengan 1 dan kurangi b dengan 1 . Maka keadaan
sekarang menjadi a = 4 dan b = 2 . Baris berikutnya menampilkan nilai a dan b ke layar
(printf("Masuk -> a = %d || b = %d \n",a,b)). Kemudian panggil fungsi rekursi
dengan nilai a = 4 dan b = 2 . Langkah – langkah tersebut diulang terus sampai
pemanggilan fungsi rekursi dengan nilai a = 6 dan b = 0. Pada saat ini kondisi if bernilai
benar sehingga fungsi akan keluar (return) dan melanjutkan perintah setelah pemanggilan
fungsi rekursi dengan a = 6 dan b = 0. Yaitu mencetak nilai a dan b (printf("Keluar ->
a = %d || b = %d \n",a,b)). Setelah mencetak nilai a dan b maka fungsi rekursif
akan keluar lagi , dan melanjutkan perintah setelah pemanggilan fungsi rekursif
sebelumnya dimana nilai a = 5 dan b = 1 . Demikian seterusnya sampai nilai a = 4 dan
nilai b = 2. yang tidak lain pemanggilan fungsi rekurif yang pertama. Proses pemanggilan
fungsi rekursif dapat diilustrasikan :

Langkah ke :
1. a = 4 ; b = 2 . Cetak : Masuk -> a = 4 || b = 2
2. a = 5 ; b = 1 . Cetak : Masuk -> a = 5 || b = 1
3. a = 6 ; b = 0 . Cetak : Masuk -> a = 6 || b = 0
4. a = 6 ; b = 0 , Cetak : Keluar -> a = 6 || b = 0
5. a = 5 ; b = 1 , Cetak : Keluar -> a = 5 || b = 1
6. a = 4 ; b = 2 , Cetak : Keluar -> a = 4 || b = 2

Created By Muhammad Syahrizal 14


Untuk memperjelas lagi penggunaan fungsi rekursif dibawah ini akan di berikan contoh
contoh program dengan menggunakan rekursif .

Menghitung Nilai Faktorial dan Fibonacci Dengan Rekursif


Untuk menghitung nilai faktorial bilangan bulat positif marilah kita daftarkan dulu nilai –
nilai faktorial untuk mempermudah pengambilan algoritma .
0! = 1
1! = 1
2! = 2 x 1 N! = N x (N – 1) !
3! = 3 x 2 x 1 = 3 x 2!
4! = 4 x 3 x 2 x 1 = 4 x 3!

Untuk Mencari Bilangan Fibonacci juga sama . Sebelumnya mari kita daftarkan dulu
bilangan Fibonacci untuk mempermudah pencarian algoritma .
1 1 2 3 5 8 13 ...

Dapat dilihat bahwa


Fibo(0) = 1
Fibo(1) = 1
Fibo(2) = Fibo(1) + Fibo(0) = 1 + 1 = 2
Fibo(3) = Fibo(2) + Fibo(1) = 2 + 1 = 3
Untuk Listing Program dalam bahasa C saya serahkan ke pembaca sebagai latihan.

Menara Hanoi
Menara Hanoi ialah salah satu permainan yang dulunya dimainkan oleh seorang pendeta
di Hanoi . Tujuan permainan ini ialah memindahkan n buah pringan dari tonggak asal (A)
melalui tonggak bantu (B) menuju tonggak tujuan (C) .Dengan aturan – aturan bahwa
piringan yang lebih kecil tidak boleh berada di bawah piringan yang lebih besar .

Seperti biasa untuk memecahkan masalah kita daftarkan dulu langkah – langka yang
diambil mulai n = 1. Dengan dfinisi piringan yang paling atas ialah piringan 1.
Untuk n = 1 :
- Pindahkan piringan 1 dari A ke C
Untuk n = 2 :
- Pindahkan piringan 1 dari A ke B
- Pindahkan piringan 2 dari A ke C
- Pindahkan piringan 3 dari B ke C

Created By Muhammad Syahrizal 15


Dari contoh diatas dapat diambil kesimpulan , untuk memindahkan N piringan dari
tonggak asal (A) ke tonggak tujuan (C) maka piringan ke N harus berada di tonggak
tujuan (C) , sedangkan piringan ke 1 sampai (N - 1) harus berada di tonggak bantu (B).
Setelah piringan ke 1 sampai (N-1) berada pada tonggak bantu (B) , kemudian pindahkan
piringan ke 1 sampai (n-1) tersebut dari tonggak bantu (B) ke tonggak tujuan (C) Nah
bagaimana caranya membawa piringan ke 1 sampai (N-1) dari tonggak asal ke tonggak
bantu (B) , caranya sama saja yaitu dengan memindahkan piringan ke (n-1) dari tonggak
asal (A) ke tonggak tujuan yang pada saat ini berada pada tonggak (B) sedangkan
piringan dari 1 sampai ke (N- 2) dipindahkan ke tonggak bantu yang saat ini berada di
tonggak (C) , Setelah piringan ke 1 sampai (N-2) berada pada tonggak bantu (C) ,
kemudian pindahkan piringan ke 1 sampai (N-2) ke tonggak tujuan (B) dan seterusnya.
Metode penyelesaian permainan Hanoi diatas sering disebut sebagai metode back
tracking , jadi solusi dicari dengan cara mundur ke belakang dahulu , baru kemudian
solusi bisa di temukan .

Berikut Listing program Menara Hanoi dalam bahasa C


#include <stdio.h>
void Hanoi(int n,char asal,char bantu,char tujuan) // pindahkan piringan ke n
{ // dari asal menuju tujuan
// melalui bantu
if (n == 0) return;
Hanoi(n-1,asal,tujuan,bantu); //pindahkan piringan ke n-1
// dari asal ke bantu melalui
//tonggak tujuan
printf("Pindahkan piringan ke %d ke dari %c ke %c\n",n,asal,tujuan);
Hanoi(n-1,bantu,asal,tujuan); //pindahkan piringan ke n – 1
// dari bantu menuju tujuan
// melalu asal
}
int main(void)
{
int n;
printf("Jumlah piringan ? ");
scanf("%d",&n);
Hanoi(n,'a','b','c');
return 0;
}

Berikut Hasil dari program diatas .


Jumlah piringan ? 3
Pindahkan piringan ke 1 ke dari a ke c
Pindahkan piringan ke 2 ke dari a ke b
Pindahkan piringan ke 1 ke dari c ke b
Pindahkan piringan ke 3 ke dari a ke c
Pindahkan piringan ke 1 ke dari b ke a
Pindahkan piringan ke 2 ke dari b ke c

Created By Muhammad Syahrizal 16


Pindahkan piringan ke 1 ke dari a ke c

Penggunaan Templlate
Dalam pemrograman , terutama yang sangat tergantung pada tipe variable , sering kali kita direpotkan
dengan harus membuat fungsi yang berfungsi sama tapi dengan tipe variable berbeda.Untuk itu pada
C++ dikeluarkan lah sebuah keyword baru , yaitu template. Dengan penggunaan template kita bisa
membuat sebuah fungsi yang bias mendukung segala macam tipe variable , tidak terbatas pada
variable yang di definisikan oleh keyword C/C++ tapi juga mendukung penggunaan untuk tipe
variable masa depan. Penggunaan template tidak terbatas hanya pada fungsi tapi juga
mencakup class ( termasuk juga struct , union) . Secara garis besar penggunaan template dapat dibagi
2 yaitu template pada fungsi ( function template)dan template pada Class ( class template). Oke saya
rasa kita langsung saja membahas penggunaan template.

Function Template
Pertama - tama mari kita membahas tentang function template.Untuk itu marilah kita perhatikan
contoh berikut.
template <class tipe>
void swap(tipe &a,tipe &b)
{
tipe c;
c = a;
a = b;
b = c;
}
Pada contoh diatas terdapat sebuah fungsi swap (menukar 2 buah variable) menggunakan template..
Untuk pemanggilan fungsi dilakukan seperti pemanggilan fungsi tanpa template. Untuk itu mari
perhatikan penggalan perintah untuk menggunakan fungsi swap.

Contoh template dengan instance tipe int


void main(void)
{
int a,b;
a = 10;
b = 20;
swap(a,b);
cout << a << “ “ << b << endl;
}
Contoh template dengan instance tipe float
void main(void)
{
float a,b;
a = 10.0;
b = 20.0;
swap(a,b);
cout << a << “ “ << b << endl;
}
Contoh template dengan instance struct tTes
struct tTes
{
int a,b;
};
void main(void)
{

Created By Muhammad Syahrizal 17


tTes a,b;
a.a = 10;
a.b = 20;
b.a = 30;
b.b = 40;
swap(a,b);
cout << a.a << " " << a.b << " " << b.a << " " << b.b;
}
Dapat dilihat , dengan menggunakan template kita telah menghemat waktu untuk
menulis fungsi Pada fungsi swap diatas , juga tidak menutup kemungkinan untuk
menukar 2 buah kelas.

Pada contoh diatas fungsi tidak akan bekerja jika variable yang ditukar berbeda tipe .
Walaupun kekerabatannya cukup dekat . Anda tidak bisa menukar tipe int (16bit)
dengan tipe short (16 bit). Ini terkait dengan pendeklarasian template pada fungsi
swap.
template <class tipe>
void swap(tipe &a,tipe &b)

Pada pendeklarasian fungsi swap dapat dilihat bahwa formal parameter a sama
dengan formal parameter b . Oleh sebab itu sudah seharusnya tipe pada aktual
parameter pun harus sama. Untuk contoh fungsi swap diatas sebaiknya anda tidak
menggunakan type-casting untuk mengatasi masalah diatas. Mengingat fungsi swap
diatas dikirim by reference . (Yang mana dalam pengiriman fungsi menggunakan
reference berkaitan dengan pointer). Tentu saja ukuran dari variable menjadi sangat
penting karena kita telah merubah ukuran dari variable (type casting) bisa saja terjadi
hasil yang tak terduga . Walupun kadang – kadang memberikan hasil yang benar.
Kecuali jika ukuran kedua tipe variable tersebut benar - benar sama , anda dapat
menggunakan type–casting dalam hal ini.

Untuk mendefiniskan lebih dari satu type pada template anda dapat menggnakan
koma sebagai pemisah
contoh :
Template dengan 2 buah tipe
template <class tipe1,class tipe2>

Overloading Template Function


Jikalau suatu saat ada sebuah variable yang harus diperlakukan khusus untuk
menukarkannya anda dapat mengoverload sebuah template function. Sebagai contoh :
misalkan jika anda ingin menukar 2 buah variable float tanpa perlu memperhatikan
negatif atau positif . Anda tinggal membuat sebuah fungsi tambahan dengan variable
float. Jadi ketika dijalankan compiler akan memprioritaskan dulu pada fungsi yang
memiliki formal parameter dan aktual parameter dengan tipe yang sama. Baru
kemudian jika tidak ditemukan maka compiler akan membuat sebuah instance dari
template function yang telah anda buat. Untuk lebih jelasnya mari kita lihat contoh
source code berikut ini .
#include <iostream.h>
template <class Tipe>
void swap(Tipe &a,Tipe &b)
{
Tipe tmp;
tmp = a;
a = b;
b = tmp;
}

Created By Muhammad Syahrizal 18


void swap(float &a,float &b)
{
float c;
a = (a < 0.00)?-a:a;
b = (b < 0.00)?-b:b;
c = a;
a = b;
b = c;
}
void main(void)
{
float a,b;
a = -10.0;
b = 20.0;
swap(a,b);
cout << a << " " << b;
}

Class Template
Jenis template yang berikutnya ialah Class template. Class Template , tidak hanya
berlaku untuk pendefinisian template pada class tapi juga berlaku pada pendefinisian
struct dan union.Cara pendefinisan sama seperti Funtion template yang beda hanya
pada caramembuat instance dari class template tersebut. Untuk lebih jelasnya mari
kita perhatikan contoh pendefinisian Class Template.

Pendefinisian Class Template pada sebuah class CMyTemplate


template <class MyTipe>
class CMyTemplate
{
protected :
MyTipe m_a,m_b;
public :
void Done(void)
{
memset(&m_a,0,sizeof(MyTipe)); // pendeklarasian method
} // didalam kelas
};
//pendeklarasian methos diluar kelas
template <class MyTipe>
void CMyTemplate<MyTipe>::Init(MyTipe a,MyTipe b)
{
m_a = a;
m_b = b;
}

Pendefinisian Class Template pada sebuah struct tMyStruct


template <class MyTipe>
struct tMyStruct
{
MyTipe a,b;
};

Pendefinisian Class Template pada sebuah union _MyUnion


template <class MyTipe>
union _MyUnion
{
MyTipe a;
int b;

Created By Muhammad Syahrizal 19


};

Yang perlu diperhatikan dari contoh diatas , antara lain perbedaan antara pendefinisian method
didalam atau diluar kelas .

Untuk menggunakan sebuah class template sebelumnya kita harus mendefiniskan


instance dari template yang akan dibuat. Untuk mendefinisikan instance dari class
template dapt dilakukan dengan cara menuliskan tipe data dari instance yang diapit
oleh tanda “<” ,”>” .
Contoh :
void main(void)
{
CMyTemplate<short> a; // membuat instance CMyTemplate dengan tipe
short
tMystruct<short> b; // membuat instance tMyStruct dengan tipe short
_MyUnion<float> c; // membuat instance _MyUnion dengan tipe float
}

Pada instance CMyTemplate yang dideklarasikan dengan tipe data short maka MyTipe
(pada pendefinisian class ) akan menjadi short .Ini berarti variable m_a dan m_b akan
bertipe short begitu pula pada struct dan union. Untuk mendefinisikan lebih dari 1 tipe
pada class template dapat anda lakukan sama seperti Function Template yaitu dengan
menggunakan tanda koma sebagai pemisah .
Contoh :
template <class MyTipe1,class MyTipe2>
class CMyTemplate
{
protected :
MyTipe1 m_a
MyTipe2 m_b;
public :
void Init(MyTipe1 a,MyTipe2 b)
{
m_a = a;
m_b = b;
}
};

Untuk membuat instancenya tinggal ditambahkan tanda koma .


Contoh :
void main(void)
{
CMyTemplate<short,float> a;
}
Jadi sekarang pada Object a , Variabel m_a akan bertipe short sedangkan pada variable
m_b akan bertipe float.

Analisa Numerik:
Menghitung FPB Metode Euclidian
FPB ialah isitilah yang digunakan untuk menyatakan sebuah bilangan yang mampu

Created By Muhammad Syahrizal 20


membagi pasangan bilangan lain sehingga didapatkan hasil bilangan bulat yang paling
kecil. Dengan kata lain FPB ialah sebuah bilangan terbesar yang mampu membagi habis
(sisa = 0) pasangan bilangan lain
Contoh :
FPB dari 60 dan 80 :
60 = 20 * 3
80 = 20 * 4

Pada contoh diatas FPB dari 60 dan 80 ialah 20.


Ada beberapa macam contoh untuk menghitung FPB salah satunya yang terkenal ialah
algoritma Euclidian .

Berikut adalah Algoritma Euclidian untuk menemukan FPB dari 2 buah bilangan
1. Input Bilangan1
2. Input Bilangan2
3. Sisa = Bilangan1 modulus Bilangan2
4. Jika Sisa != 0 maka
Bilangan1 = Bilangan2
Bilangan2 = Sisa
5. Jika Sisa = 0 maka
FPB = Bilangan2

Berikut adalah implementasinya dalam Bahasa C


#include <stdio.h>
int FPB(int Bil1,int Bil2)
{
int sisa;
while((sisa = Bil1%Bil2) != 0)
{
Bil1 = Bil2;
Bil2 = sisa;
}
return Bil2;
}
void main(void)
{
int bil1,bil2;
int sisa;
printf("FPB dari 60 dan 80 = %d\n",FPB(60,80));
printf("FPB dari 40 dan 120 = %d\n",FPB(40,120));
printf("FPB dari 2 dan 3 = %d\n",FPB(2,3));
}

Hasil :
FPB dari 60 dan 80 = 20
FPB dari 40 dan 120 = 40
FPB dari 2 dan 3 = 1

Analisa Numerik:
Created By Muhammad Syahrizal 21
Menukar 2 Buah Nilai
Metode klasik dalam dalam menukar 2 buah nilai , biasanya dengan menggunakan
bantuan sebuah variable penampung. Untuk itu diperlukan minimal 3 buah variable
dalam implementasinya.
Contoh :
Untuk menukar var A dan B
temp = A ;
A = B;
B = temp;

Didalam bahasa C pendeklarasian variable harus diletakkan sebelum statemen. Jadi jika
program anda cukup panjang ( dalam artinya banyak baris ) tentu saja anda harus ke atas
dahulu untuk mendeklarasikan varibale temp.

Ada cara lain yang dapat digunakan untuk menukar 2 buah nilai tanpa harus memberikan
variable tambahan ( cukup dengan 2 buah variable saja ). Yaitu dengan bantuan logika
xor .

Untuk itu sebelumnya mari kita melihat sejenak tabel kebenaran xor.

Contoh :
A = 1010
B = 0101
C = A xor B
C = 1111
X = C xor A -> X = 0101 // penting !!!!
Y = C xor B -> Y = 1010 // penting !!!!

Dari contoh diatas dapat ditarik kesimpulan :


C = A xor B
C xor A akan menghasikan B
C xor B akan menghasilkan A

Sifat diatas biasanya digunakan untuk membuat sebuah enkripsi data yang sederhana.
Tapi yang akan kita bicarakan ialah menggunakan xor untuk menukar 2 buah nilai Mari
perhatikan contoh berikut .
C = A xor B

Created By Muhammad Syahrizal 22


B = C xor B // pertama
A = C xor B // kedua

Pada C xor B yang pertama akan dihasilkan nilai A oleh sebab itu nilai tersebut ditaruh di
B (karena kita akan menukar) . C xor B yang kedua dimana B merupakan nilai A awal
maka akan menghasilkan B oleh sebab itu kita taruh di A. Dengan mensubtitusi nilai C
dengan salah satu variable maka akan didapatkan :
A = A xor B
B = A xor B
A = A xor B

Karena (A xor B) = (B xor A) , pada statement 2 dapat diganti B = B xor A


Sehingga dalam bahasa C dapat ditulis :
A ^= B ^= A ^= B;
Meakjubkan bukan ?? , Menukar 2 buah nilai hanya dengan 1 perintah ( titik koma ) .

C++ : Scope Class


C++ memperluas pengertian scope (visibility) dalam bahasa C dengan masuknya
class dan namespace. Artikel ini membahas scope sebuah class. Pembahasan scope tidak
terlepas dari konsep yang saling berkaitan dalam C/C++ yaitu lifetime (storage
duration) dan linkage. Lifetime menentukan kapan destructor sebuah class dipanggil.

Scope sebuah kaji ulang


Komputer, sebagai sebuah mesin, dirancang untuk bekerja mengolah angka.
Komputer menyimpan data dan perintah di memori dalam bentuk angka. Manusia tidak
menggunakan angka melainkan nama untuk membedakan suatu bentuk dengan bentuk
lainnya. Manusia lebih mudah mengenali bentuk/benda melalui nama daripada angka.
Sebagai contoh, dalam sebuah jaringan LAN lebih mudah mengenali server melalui
nama server daripada alamat IP (sebuah angka) server tersebut. Nama juga sangat berarti
bagi sebuah program, seseorang penulis program menggunakan nama untuk
membedakan data (variabel), fungsi, atau entity lain yang dikenal dalam sebuah bahasa
pemrograman.
Istilah formal sebuah nama, dalam bahasa C/C++ disebut identifier. Nama (identifier)
digunakan untuk menyatakan,
• Data
• fungsi (function)
• typedef
• structure/class, dan anggotanya

Created By Muhammad Syahrizal 23


• enumeration, dan anggotanya
• union
• label

dalam sebuah program C/C++. Sebuah program mengenali nama obyek melalui
deklarasi nama tersebut. Scope membatasi nama (identifier), artinya sebuah nama hanya
dapat digunakan dalam scope nama tersebut. Scope sebuah nama sudah ditentukan pada
saat nama tersebut dideklarasikan. Nama dalam sebuah scope dapat dikenali di scope
yang berbeda apabila sesorang penulis program menghendaki demikian. Sebuah scope
dapat mempunyai hubungan (linkage) dengan scope lain, karena menggunakan sebuah
nama (identifier) yang sama, dengan kata lain nama (identifier) tersebut visible di scope
yang berbeda.

Translation Unit
Ada perbedaan antara organisasi penulisan program C++, melalui file .h (berisi
deklarasi) dan .cpp (berisi definisi), dengan proses pemilahan token (parsing) yang
dilakukan compiler. Perbedaan tersebut tidak begitu menentukan dalam memahami
konsep scope, lifetime dan linkage dalam C. C++ memiliki batasan scope yang lebih
abstrak, oleh karena itu standard C++ memperkenalkan istilah translation unit.
Sebuah translation unit mungkin dibentuk dari beberapa file, karena umumnya
sebuah program C++ menyertakan satu atau lebih file .h. Pada proses kompilasi, file
berisi pernyataan program (source file) dan file lain yang dibutuhkan digabungkan
menjadi satu kesatuan sebagai masukan proses pemilahan token.

Created By Muhammad Syahrizal 24


Seperti ditunjukkan pada ilustrasi di atas [3], file main.cpp, h1.h, dan h2.h
digabungkan menjadi sebuah translation unit. Compiler tidak mengikutsertakan baris
program diantara #ifndef (#if !defined) atau #else jika syarat tidak terpenuhi.

Sebagai contoh, jika INCL bernilai 1 maka dihasilkan translation unit TU#1, baris
program diantara syarat kondisi pada file h1.h diikutsertakan. Apabila INCL bernilai 0,
maka dihasilkan translation unit TU#2, baris program diantara syarat kondisional pada
file h1.h tidak diikutsertakan dan baris program diantara syarat kondisi pada file h2.h
yang diikutsertakan. Perlu diperhatikan juga bahwa compiler mengikutsertakan file yang
dibutuhkan secara rekursif, jika file h1.h mencantumkan file *.h lainnya maka file
tersebut termasuk dalam translation unit yang sama.

Proses pemilahan token menggunakan pernyataan program yang terdapat dalam


translation unit dan bukan yang tertulis pada masing-masing file. Demikian halnya
dengan scope, lifetime dan linkage masing-masing identifer ditentukan berdasarkan
translation unit.

Deklarasi dan Definisi


Sebuah deklarasi memperkenalkan sebuah nama dalam sebuah program. Deklarasi
sebuah nama sekaligus menentukan scope nama tersebut. Definisi, selain memasukkan
nama obyek1 dalam sebuah program juga membentuk (create) obyek tersebut dan
melakukan inisialisasi. Deklarasi dan definisi sering dipertukarkan, tetapi sebenarnya
terdapat perbedaan deklarasi dan definisi.
Secara sederhana, sebuah program hanya mempunyai satu definisi terhadap satu
obyek atau fungsi (function) dan sebuah program dapat mempunyai lebih dari satu
deklarasi. Persyaratan tersebut dalam C++ dikenal dengan istilah aturan satu definisi
(One Definition Rule(ODR)).
int i; //definisi
int i=0; //definisi
extern int i; //deklarasi
extern int i=0; //definisi
static int j; //definisi
static int j=0; //definisi
void g(int k) //deklarasi fungsi
void f(int k) //definisi fungsi
{
int l;
}

Dalam C++, seperti pada beberapa contoh di atas, sebuah deklarasi adalah sebuah
definisi kecuali,
• sebuah deklarasi fungsi tanpa isi (body) fungsi tersebut, contoh fungsi g.
• sebuah deklarasi obyek dengan katakunci extern dan tanpa inisialisasi.
• sebuah deklarasi obyek (data member) static dalam scope class.

Jadi deklarasi menurut ODR merupakan bentuk pengecualian definisi, berbeda dengan

Created By Muhammad Syahrizal 25


C yang mengenal definisi tentatif (tentative definition). C++ menyarankan untuk tidak
menggunakan “implicit int” dalam deklarasi. Dalam C, jika tidak ditulis type obyek
maka dianggap obyek tersebut bertipe int,
static a; //a bertipe int
const b; //b bertipe int
void f(const c); //c bertipe int
main(void) { return 0; } //return type int

C++ menyarankan untuk menuliskan tipe obyek secara eksplisit, sebagai berikut,
static int a;
const int b=1;
void f(int const c);
int main(void) { return 0; }

Scope
Scope dan lifetime adalah dua konsep yang terkait erat. Visibility sebuah nama
(identifier) dalam sebuah program C++ berbeda-beda, sebuah nama dengan scope global
mempunyai visibility paling luas sedangkan sebuah nama dengan scope lokal
mempunyai visibility lebih sempit misalkan sebatas eksekusi suatu fungsi. Sebuah scope
menentukan batas visibility sebuah nama dalam program C++. Scope dapat dibentuk
dengan sepasang tanda kurung {}, yang membentuk block scope, misalnya pada forloop,
while-loop, dll. Batasan scope dapat juga lebih abstrak seperti pada pembahasan
translation unit.
Bahasa C mengenal beberapa bentuk scope, antara lain:
- block, scope nama adalah bagian program yang dibatasi oleh sepasang tanda
kurung { }. Sebuah nama visible sejak deklarasi nama tersebut sampai dengan
tanda kurung penutup } yang menandakan akhir masa pakai nama tersebut.
- prototipe fungsi (function prototype), scope nama hanya sebatas tanda kurung
( dan ) yang membentuk prototipe fungsi.
- fungsi, scope sebuah nama adalah seluruh badan fungsi tersebut.
- file, scope sebuah nama adalah keseluruhan file sejak sebuah nama
dideklarasikan.

Scope block dan prototipe fungsi dikenal dengan scope lokal (local scope).
Bahasa C++ menambahkan dua scope lagi, yaitu class dan namespace. Deklarasi
class (dan namespace) dibatasi oleh sepasang tanda kurung { }, walaupun definisi
member function dapat ditulis di luar deklarasi class. Pada penulisan definisi seperti itu,
member function tetap berada dalam scope class.

Scope minimal
Standar C++ mengubah sedikit aturan mengenai scope sebuah nama variabel dalam
pernyataan for-loop, while-loop, atau if-condition. C++ mengijinkan deklarasi variabel
sebagai bagian dari sebuah for-loop. Sebagai contoh deklarasi variabel i (loop counter)
pada cuplikan baris program berikut ini,
for (int i=0; i<10; i++) //deklarasi dan inisialisasi i

Created By Muhammad Syahrizal 26


//dalam sebuah for-statement
{
cout << i << endl;
}
int n=i; //error: menggunakan i diluar scope

Pada contoh, scope i adalah badan for-loop tersebut yang dibatasi oleh pasangan tanda
kurung { }. Penggunaan variabel i diluar scope adalah suatu pelanggaran terhadap
aturan scope C++ yang terdeteksi pada saat kompilasi program. Perubahan aturan scope
tersebut sejalan dengan teknik scope minimal (minimal scoping)[1]. Teknik scope
minimal mempersempit jarak antara deklarasi sebuah nama dengan pemakaian nama
tersebut. Teknik ini bertujuan untuk menambah readability2 sebuah program. Scope
minimal menunda alokasi obyek sampai obyek tersebut memang benar-benar
dibutuhkan, seperti ditunjukkan pada contoh berikut
if (<kondisi>)
{
int i,j;
}

Jika <kondisi> tidak bernilai benar (.T.) maka tidak ada alokasi memori untuk obyek i
dan j.

Tidak semua compiler C++ mengikuti aturan scope yang disempurnakan, salah satu
yang paling menonjol adalah Microsoft Visual C++. Sampai dengan dengan versi 6,
Visual C++ tidak mengikuti aturan scope yang baru dan hal ini adalah salah satu contoh
ketidak sesuaian (incompatibility) VC++ dengan standar C++[6,7]. VC++ menggunakan
konvensi pembentukan nama yang dikenal dengan notasi Hungarian (Hungarian
notation) dengan mengikutsertakan tipe data dalam nama variabel. Dengan demikian
pendekatan VC++ tidak memandang perlu memperpendek jarak antara deklarasi dengan
pemakaian nama tersebut pertama kali.

Lifetime
Lifetime atau storage duration sebuah obyek adalah rentang waktu sejak obyek
tersebut dibentuk sampai waktu saat obyek tersebut dihancurkan. Selama rentang waktu
tersebut, nama tersebut mengacu ke lokasi memori yang ditempati oleh obyek tersebut,
selepas rentang waktu tersebut, sebuah nama tidak lagi mengacu ke lokasi memori
tersebut karena mungkin sudah ditempati oleh obyek lain.
C++ mengenal tiga jenis storage duration sebuah nama, yaitu: static, automatic
(local), dan dynamic. Argument sebuah fungsi mempunyai automatic storage duration,
artinya argumen tersebut dibentuk begitu eksekusi program memasuki fungsi tersebut
(scope argumen tersebut) dan dihancurkan begitu eksekusi fungsi tersebut selesai
(keluar dari scope fungsi). Sebuah obyek automatic menempati memori stack (stack
memory). Sebuah deklarasi obyek dengan scope block tanpa kata kunci extern atau
static juga mempunyai automatic storage duration (seperti contoh scope minimal di
atas). Sebuah obyek dengan static storage duration menempati memori sejak saat
pertama eksekusi program, dengan demikian obyek static mempunyai alamat yang sama
sepanjang eksekusi program. Obyek static menempati memori static (static storage).
Sebuah obyek dengan dynamic storage duration menempati memori melalui fungsi

Created By Muhammad Syahrizal 27


alokasi (operator new) dan dilepas dengan fungsi dealokasi (operator delete). Obyek
dinamik menempati memori heap atau memori dinamik (free store).

Storage specifier
C++ mengenal lima buah kata kunci yang menyatakan attribut storage duration
sebuah nama (storage class specifiers), yaitu: auto, register, extern, static dan
mutable. Sedikit perbedaan dengan C, typedef tidak termasuk storage class specifier.
Secara umum, dalam sebuah deklarasi tidak boleh menggunakan dua buah storage
specifier secara bersamaan. Kata kunci extern dan static dapat menjadi bagian dari
deklarasi obyek atau fungsi dalam scope namespace3 dan scope block, akan tetapi
static tidak dapat menjadi bagian deklarasi fungsi dalam scope block. static juga
dapat menjadi bagian deklarasi dalam sebuah scope class.
auto dan register dapat menjadi bagian sebuah deklarasi dalam scope block
maupun atau dalam deklarasi argumen fungsi (formal parameter), tetapi tidak dalam
scope namespace, sebagai contoh:
register char *p; //error – register dalam scope namespace
void f(register char *p); //ok – register dalam formal parameter
void f(auto int i); //ok di C++, error di C

C++ mengijinkan penggunaan auto dalam argumen fungsi walaupun tidak ada pengaruh
apapun, sedangkan C tidak memperbolehkannya.
mutable tidak berpengaruh terhadap linkage maupun lifetime sebuah nama, mutable
hanya dapat digunakan dalam deklarasi obyek (data member) dalam scope class.
mutable menyatakan bahwa sebuah obyek tidak pernah konstant.

Linkage
Sebuah nama yang sama tetapi dalam translation unit yang berbeda dapat mengacu ke
sebuah obyek yang sama. Hal ini, dalam C maupun C++, disebut linkage. Ada 3 macam
linkage, masing-masing adalah:
1. external linkage, yaitu sebuah nama yang dapat terjangkau dari scope lain
meskipun berbeda translation unit.
2. internal linkage, yaitu sebuah nama dalam sebuah translation unit yang dapat
terjangkau di scope lain dalam translation unit yang sama.
3. tanpa (no) linkage, yaitu nama sebuah obyek dalam sebuah scope dan tidak
terjangkau melalui nama tersebut dari scope lainnya.

Linkage sebuah obyek maupun fungsi ditentukan oleh kombinasi beberapa faktor,
yaitu: scope, storage class specifier, dan linkage yang ditetapkan melalui deklarasi
sebelumnya. Selain itu const juga mempunyai pengaruh terhadap hasil akhir linkage
obyek atau fungsi.

Secara umum, extern pada deklarasi sebuah obyek atau fungsi dalam scope
namespace menyatakan external linkage. Demikian halnya dengan deklarasi tanpa
storage class specifier juga menyatakan external linkage. Sebaliknya static pada
deklarasi obyek maupun fungsi menyatakan internal linkage. Sebagai contoh, definisi
nama dalam file1.cpp dan file2.cpp berikut ini,

Created By Muhammad Syahrizal 28


Pada contoh, definisi nama data tersebut mempunyai scope file, i mempunyai linkage
external,sedangkan k mempunyai linkage internal. Hasil kompilasi (dan link) kedua file
tersebut menghasilkan sebuah program dengan sebuah obyek i,j dan dua buah obyek k.
Deklarasi j pada file1 mengacu ke obyek j di file2, deklarasi i pada file2 mengacu ke
obyek i di file1. static pada deklarasi k mengacu ke obyek yang berbeda, walaupun
kedua file menggunakan nama yang sama. Dalam C++, berbeda dengan C, const pada
sebuah deklarasi menyatakan linkage internal, seperti deklarasi N pada contoh di atas.

Namun demikian, extern pada deklarasi sebuah obyek const mengubah linkage obyek
tersebut menjadi linkage eksternal.

Aturan linkage pada scope block berbeda dengan aturan linkage pada scope
namespace (termasuk scope file). Dalam scope blok, nama obyek tidak mempunyai
linkage (no linkage), kecuali terdapat extern pada deklarasi obyek tersebut. Nama
parameter (formal parameter) juga tidak mempunyai linkage. Sebagai contoh,
void f(int i) //f: eksternal
{ //i:no linkage
int j; //no linkage
static int k; //no linkage
//file1.cpp
int i=0; //internal
extern j; //external
static int k; //internal
int const N=100 //internal
//file2.cpp
extern int i; //external
int j; //external
static int k; //internal

}

Pada contoh tersebut, nama fungsi f mempunyai linkage eksternal, nama parameter i
tidak mempunyai linkage, nama variabel lokal j dan k tidak mempunyai linkage.
Bagaimana dengan deklarasi yang menggunakan extern pada blok scope, seperti contoh
berikut ini,
static int i=0; //internal
extern int j; //eksternal
void f()
{
extern int i; //internal
extern float j; //error
extern int k; //external

}
Seperti terlihat pada contoh, hasil akhir linkage obyek extern dalam scope blok

Created By Muhammad Syahrizal 29


bergantung kepada linkage obyek pada scope yang memuat scope blok tersebut. Obyek i
dalam blok scope mempunyai linkage internal, mengikuti linkage obyek i dalam scope
file. Obyek k mempunyai linkage eksternal, mengikuti linkage obyek k dalam scope file.
Deklarasi obyek merupakan pelanggaran terhadap aturan linkage, karena tipe data j
(float) dalam scope blok berbeda dengan tipe data j (int) dalam scope file.

Scope Class
Setiap definisi class membentuk sebuah scope baru. Scope class mencakup deklarasi
class, masing-masing badan fungsi anggota class (member function), dan constructor
initializers.

Akses terhadap anggota class dapat dilakukan menggunakan salah satu diantara
beberapa cara dibawah ini,
a) operator .
b) operator ->
c) operator :: (scope resolution operator)
d) melalui fungsi anggota class tersebut (member function) atau derived class

Ketiga cara tersebut harus mengikuti batasan akses (public, protected, private) class
tersebut. Keempat cara tersebut dapat digunakan untuk mengakses anggota class dengan
batasan akses public. Cara keempat dapat digunakan untuk mengakses anggota class
dengan batasan akses protected dan public.

Class dalam class (nested class) mempunyai scope terpisah, seperti contoh berikut
ini,
struct s
{
struct t
{
int i;
} j;
}

Jika t tidak tersedia untuk akses public (protected atau private), maka operator :: tidak
dapat digunakan untuk mengakses struct t karena batasan akses masih tetap berlaku.
Standar C++ sebelum dibakukan, memperkenalkan cara untuk mendefinisikan suatu
besaran konstan (compile-time constant) yang mempunyai scope class. Sebagai contoh
sebuah class C berikut ini,
class C
{
int buf[10];
public:
C();
};

Created By Muhammad Syahrizal 30


mempunyai angota berupa array integer buf dengan jumlah elemen 10. Inisialisasi array
buf dalam constructor perlu menggunakan operator sizeof() untuk mendapatkan
jumlah elemen array, sebagai berikut:
C::C()
{
for(int i=0;i<(sizeof(buf)/sizeof(&buf[0]));i++)
buf[i]=i;
}

Cara yang lebih mudah untuk inisialisasi array buf adalah dengan mendefinisikan
jumlah elemen array buf. Dua cara untuk mendefinisikan besaran konstan dengan scope
class adalah,

Dengan demikian inisialisasi array buf dalam constructor tidak lagi menggunakan
operator sizeof(), melainkan dengan nilai konstan BUFSIZE.
C::C()
{
for(int i=0;i<BUFSIZE;i++)
buf[i]=i;
}

Cara ‘enum hack’ sering digunakan sebelum standar C++ memasukkan cara untuk
mendefinisikan konstan dengan scope class. Cara ‘enum hack’ disebut demikian karena
menggunakan enum tidak sesuai dengan penggunaan seharusnya. Namun demikian
‘enum hack’ masih lebih baik dari pada menggunakan manifest constant (#define)
yang tidak mengenal batasan scope.

Overloading
Scope dan linkage adalah dua buah konsep dasar yang menjadi dasar compiler C++
dalam menguraikan penggunaan nama dalam sebuah program. Sebuah program dapat
menggunakan nama yang sama asalkan berbeda scope. C++ melonggarkan hal ini
dengan memasukkan konsep overloading untuk nama fungsi. C++ mengijinkan sebuah
program menggunakan nama yang sama untuk dua buah fungsi yang berbeda.
Overloading dapat digunakan dalam scope file maupun scope class. Salah satu contoh
adalah overloading anggota class berupa fungsi (member function), seperti pada contoh
berikut ini,

Created By Muhammad Syahrizal 31


Masing-masing class Base maupun class Derived membentuk scope tersendiri. Pada
contoh, class Derived mempunyai fungsi write dengan signature yang berbeda. Hal ini
tidak diperbolehkan dalam C++, karena function overloading tidak dapat menembus
batas scope masing-masing class (cross scope). Cara pertama untuk mendapatkan hasil
yang diinginkan adalah memanggil fungsi write class Base sebagai berikut,

Cara kedua adalah menggunakan using directive, namun hanya dapat dilakukan dengan
compiler C++ yang sudah mengenal namespace.

Dalam menguraikan nama fungsi, linker C++ tidak hanya melihat nama fungsi
melainkan signature fungsi tersebut. Signature merupakan rangkaian kata (token) yang
dapat membedakan kedua fungsi, yaitu tipe masing-masing argumen (formal parameter)
fungsi tersebut. Sebagai contoh, char *strcpy(char *,const char *), mempunyai
signature { char*,const char *}. Signature hanya mengambil tipe masing-masing
argumen, bukan nama argumen fungsi tersebut. Hal ini yang memungkinkan sebuah
program C++ mempunyai deklarasi dua fungsi berbeda dengan nama yang sama dalam
scope yang sama.

Class Linkage
Dalam hal nama obyek data maupun fungsi, external linkage dalam C++ dan C
mempunyai pengertian yang sama, yaitu sebuah nama yang mengacu ke satu obyek dan
nama tersebut dapat digunakan di translation unit yang berbeda. Sebagai contoh,
file1.cpp
void f() {}
int n;

Created By Muhammad Syahrizal 32


file2.cpp
void f(); //mengacu ke fungsi f di file1.cpp
extern int n; //mengacu ke obyek data n di file1.cpp

Linkage sebuah nama class berbeda dengan pengertian linkage pada nama obyek data
maupun fungsi. Sebagai contoh,

Dalam C++, nama sebuah class, “C” pada contoh di atas, mempunyai linkage external.
Pada contoh di atas kedua translation unit mempunyai definisi class C yang sama persis.
Pengertian linkage eksternal pada nama obyek dan fungsi tidak dapat digunakan untuk
menjelaskan pengertian linkage eksternal pada nama class “C” tersebut.

Hal inilah perbedaan yang muncul dengan masuknya konsep class dalam C++.
Pengertian linkage eksternal secara umum, berlaku untuk nama data obyek, fungsi dan
class, adalah setiap obyek dengan linkage eksternal harus mengikuti aturan “satu
definisi” (ODR). Pada contoh, jika TU2 mempunyai definisi class C maka definisi
tersebut harus sama dengan definisi class C pada TU1. ODR mensyaratkan, jika satu
atau lebih translation unit mempunyai definisi sebuah obyek yang sama, maka definisi
tersebut harus sama di semua translation unit (yang memuat definisi obyek tersebut).

Salah satu cara praktis, sadar atau tidak sadar, setiap pemrogram memastikan hal ini
dengan memasukkan definisi class dalam sebuah file header (.h) dan mengikutsertakan
(melalui #include) obyek tersebut bilamana diperlukan, seperti kolom “source file”
pada contoh di atas.

Static
Sebuah class dapat mempunyai anggota berupa data atau fungsi static. Tidak seperti
obyek static pada scope file maupun blok, static dalam scope class mempunyai arti
linkage eksternal. Selain operator . dan operator ->, anggota class berupa data dan fungsi
static dapat diakses dengan operator ::.
Anggota class berupa data static harus dinisialisasi sekali saja, diluar scope class,
yaitu dalam scope file tetapi tidak dalam file .h (header). Data static dalam scope class
bukan merupakan bagian dari obyek class tersebut. Data static berlaku seperti halnya
sebuah data global sebuah class, artinya hanya ada satu data static untuk semua obyek

Created By Muhammad Syahrizal 33


class tersebut.

Anggota class berupa fungsi static tidak mempunyai pointer this, karena hanya ada
satu fungsi static untuk semua obyek class tersebut. Tanpa pointer this, fungsi static
tidak dapat mengakses anggota class lainnya yang non-static. Dengan demikian fungsi
static umumnya digunakan untuk manipulasi anggota class berupa data statik. Salah satu
contoh pemakaian fungsi static adalah pola desain (design pattern) Singleton.
Sebuah class dapat menempatkan data static dalam member function maupun sebagai
anggota class seperti data member lainnya. Sebagai contoh,
class Base
{
public:
int countCalls()
{
static int count=0; //definisi static dalam member function
return ++count;
}
};

Semua class yang mewarisi (inherit) class Base tersebut juga mewarisi data static
tersebut, sehingga count akan bertambah jika countCalls() dipanggil melalui obyek
Base maupun Derived.
class Derived1 : public Base { };
class Derived2 : public Base { };
int main()
{
Derived1 d1;
Derived2 d2;
int d1_count=d1.countCalls(); //d1_count=1
int d2_count=d2.countCalls(); //d2_count=2
}

Penjelasan mengenai nilai obyek static pada contoh di atas merupakan latihan bagi para
pembaca. Definisi data static sebagai anggota class lebih umum digunakan, seperti
ditunjukkan pada contoh berikut,
class Base
{
private:
static int i;
public:
virtual int countCalls() { return ++i; }
};
int Base::i;
class Derived1 : public Base
{
private:
static int i; //menyembunyikan Base::i
public:
int countCalls() { return ++i; }

Created By Muhammad Syahrizal 34


};
int Derived1::i;
class Derived2 : public Base
{
private:
static int i; //menyembunyikan Base::i
public:
int countCalls() { return ++i; }
};
int Derived2::i;
int main()
{
Derived1 d1;
Derived2 d2;
int d1_count = d1.countCalls(); //d1_count = 1
int d2_count = d2.countCalls(); //d2_count = 1
return 0;
}

Scope class Derived terpisah dengan scope Base maka class Derived tidak lagi mewarisi
data static i class Base, sehingga countCalls memberikan nilai yang berbeda bila
dipanggil dari obyek class Derived.
C++ mengenal class local, sebuah definisi class dalam scope blok, sebagai contoh:
#include <iostream>
int i=10;
int main()
{
void f();
f();
return 0;
}
void f()
{
static int j=20;
class Local
{
int k;
public:
Local(int i) : k(i) {}
void a() { std::cout << k+i << std::endl; }
void b() { std::cout << k+j << std::endl; }
};
local l(30);
l.a();
l.b();
};

class lokal dapat digunakan (visible) hanya sebatas scope fungsi f. Definisi class lokal
harus mencakup definisi semua anggota class berupa fungsi (member function), karena
C maupun C++ tidak mengenal definisi fungsi dalam fungsi. Class local juga tidak
mungkin mempunyai anggota berupa data static, karena data static memerlukan
inisialisasi dalam scope file. Namun demikian scope class Local berbeda dengan scope

Created By Muhammad Syahrizal 35


fungsi f, artinya jika f mempunyai argumen maka argumen tersebut tidak dikenal dalam
scope class Local.

Analisa Numerik:
Menghitung Nilai Cosinus
Tahukah anda , bagaimana caranya komputer menghitung nilai dari cos(30) ? . Mungkin
kalau hanya sekedar menghitung nilai dari cos(30°) kita tidak membutuhkan bantuan
komputer. Nah bagaimana halnya dengan cos(30.5°).Komputer tentu saja tidak
menyimpan nilai – nilai tersebut dalam sebuah tabel.Selain memakan tempat , juga
terbatas hanya pada sudut yang tertentu yang disimpan saja. Dalam beberapa kasus
pemrograman, penyimpanan nilai dalam tabel dapat dipertimbangkan terutama dalam
program – program yang berjalan secara real time dimana dengan bantuan tabel dapat
mengurangi beban dari proses komputasi . Pada kesempatan kali ini saya akan membahas
salah satu algoritma yang dapat digunakan sebagai alat membantu mendapatkan nilai dari
beberapa fungsi dasar matematika . Untuk itu ada baiknya kita menengok sejenak
pembahasan mengenai deret khususnya Deret Taylor dan Deret Maclaurin yang
terdapat pada mata kuliah Kalkulus.

Deret Taylor dan Deret Maclaurin


Bentuk Umum Deret Taylor :

Nilai a adalah sebuah constanta , Deret MacLaurin merupakan Deret Taylor khusus yang
didapat dengan cara mensubtitusi nilai a dengan 0.

Dengan bantuan rumus diatas maka menghitung nilai cos bukan merupakan hal yang
misteri lagi . Persamaan diatas berlaku tidak hanya untuk menghitung nilai cos saja tapi
juga dapat menghitung beberapa fungsi matematika lainnya , seperti fungsi fungsi yang
berhubungan dengan trigonometri , exponensial , logaritma , Hyperbolic dan lainnya .
Oke saya rasa kita langsung menuju contoh saja . Kali saya akan membuat fungsi untuk
menghitung nilai cos dengan menggunakan deret MacLaurin.

Created By Muhammad Syahrizal 36


Pertama – tama kita mencari dulu turunan masing masing tingkat dari cos(x) serta
hasilnya bila x = 0 (Maclaurin)

dan seterusnya
jika diterjemahkan dalam bahasa C maka aka menjadi :
int turunan(int n)
{
int hasil;
n = n % 4;
switch(n)
{
case 0 : hasil = 1;break;
case 1 : hasil = 0;break;
case 2 : hasil = -1;break;
case 3 : hasil = 0;break;
}

Fungsi turunan diatas ialah untuk menghitung nilai turunan tingkat ke - n. Melihat dari
tabel bahwa pada turunan ke 4 sama dengan turunan ke 0 maka bisa disimpulkan:
n = n % 4;

Setelah kita tahu turunannya maka dapat disusun algoritma global untuk penyelesaian
semua masalah yang menggunakan deret Maclaurin dengan input X.

1. n = 0 // menyatakan turunan ke – n
2. pembilang = 1 // X0 = 1
3. penyebut = 1 // 0! = 1
4. hasil = 0 // hasil keseluruhan
5. suku = turunan(n) * pembilang / penyebut // hitung nilai dari suku ke n
6. hasil = hasil + suku
7. Tambahkan nilai n dengan 1
8. pembilang = pembilang * X // untuk mendapatkan Xk+1 = Xk * X
9. penyebut = penyebut * n // untuk mendapatkan faktorial ke n
10. Ulangi terus langkah ke 4 – 8 sampai keadaan tertentu

Dalam perhitungan menggunakan deret MacLauriun dimana fungsi diturunkan terus


sampai tak hingga , maka diperlukan adanya sebuah pemotongan pada keadaan tertentu
yang menyatakan kapan perhitungan tersebut harus berhenti . Keadaan tertentu yang
dipakai biasanya ditentukan oleh nilai dari suku . Pada contoh yang saya berikan , jika

Created By Muhammad Syahrizal 37


nilai suku sudah lebih kecil dari galat maka tidak perlu dilakukan perhitungan lagi alias
keluar dari looping.

Berikut listing program lengkap dari contoh diatas :


#include <stdio.h>
#define abs(x) ((x >= 0)?x:-x)
int turunan(int n)
{
int hasil;
n = n % 4;
switch(n)
{
case 0 : hasil = 1;break;
case 1 : hasil = 0;break;
case 2 : hasil = -1;break;
case 3 : hasil = 0;break;
}
return hasil;
}
double cos(double x)
{
double pembilang,penyebut,hasil,suku;
double galat;
double n;
pembilang = penyebut = 1;
galat = 0.00001;
hasil = 0.0;
n = 0;
do
{
if (turunan(n) != 0) // untuk mengurangi perkalian dengan 0
{
suku = turunan(n) * pembilang / penyebut;
hasil = hasil + suku;
}
n++;
pembilang = pembilang * x; // pangkat
penyebut = penyebut * n; // faktorial
}while(abs(suku) >= galat);
return hasil;
}
void main(void)
{
const double PI = 3.14159265;
printf("%8.4f\n",cos(0));
printf("%8.4f\n",cos(PI/6));
printf("%8.4f\n",cos(PI/4));
printf("%8.4f\n",cos(PI/2));
printf("%8.4f\n",cos(PI));
}
Hasil :
1.0000
0.8660
0.7071
0.0000
-1.0000
Nah coba dibandingkan hasil yang anda dapat dari program ini dengan kalkulator .
Hasilnya pasti sama.

Created By Muhammad Syahrizal 38


Class C++ Dasar
Pemrograman C++ memerlukan pemahaman yang memadai untuk menterjemahkan
desain ke dalam bentuk implementasi, terutama untuk desain yang menggunakan
abstraksi class. Fokus pembahasan pada aspek pembentukan obyek (construction)
sebuah class, dan proses sebaliknya pada saat obyek tersebut sudah tidak digunakan lagi
(destruction).

Deklarasi dan Definisi


Deklarasi dan definisi adalah langkah awal dalam setiap penulisan program tidak
terkecuali dalam bahasa C++. Deklarasi dan definisi diperlukan untuk semua tipe data
termasuk tipe data bentukan user (user-defined type).
Bentuk sederhana deklarasi class adalah sebagai berikut,
class C { }; atau
struct C { };
dalam bahasa C++ struct dan class mempunyai pengertian yang sama. Deklarasi
class dengan struct mempunyai anggota dengan akses public kecuali jika dinyatakan
lain.
struct C
{
int i;
void f();
}
class C
{
public:
int i;
void f();
}

Kedua deklarasi tersebut mempunyai arti yang sama.


Hal ini adalah pilihan desain yang diambil oleh desainer C++ (Bjarne Stroustrup) untuk
menggunakan C sebagai basis C++ ketimbang membuat bahasa yang sama sekali baru.
Tentunya ada konsekuensi atas pilihan desain ini, salah satu contoh adalah
kompatibilitas terhadap bahasa C.
Dalam bahasa C deklarasi,
struct C { … };
menyatakan C sebagai nama tag. Nama tag berbeda dengan nama tipe, sehingga C
(nama tag) tidak dapat dipergunakan dalam deklarasi yang membutuhkan C sebagai
suatu tipe obyek. Kedua contoh deklarasi berikut ini tidak valid dalam bahasa C,
C c; /* error, C adalah nama tag */
C *pc; /* error, C adalah nama tag */

Dalam bahasa C, kedua deklarasi tersebut harus ditulis sebagai berikut,


struct C c;

Created By Muhammad Syahrizal 39


struct C *pc;
atau menggunakan typedef sebagai berikut,
struct C { … };
typedef struct C C;
C c;
C *pc;
C++ memperlakukan nama class, C sebagai nama tag sekaligus nama tipe dan dapat
dipergunakan dalam deklarasi. Kata class tetap dapat dipergunakan dalam deklarasi,
seperti contoh berikut ini,
class C c;

Dengan demikian C++ tidak membedakan nama tag dengan nama class, paling tidak
dari sudut pandang pemrogram (programmer), dan tetap menerima deklarasi structure
seperti dalam bahasa C. Kompatibilitas C++ terhadap tidak sebatas perbedaan nama tag
dan nama tipe, karena standar C++ masih perlu mendefinisikan tipe POD (Plain Old
Data). POD type mempunyai banyak persamaan dengan structure dalam C. Standar C++
mendefinisikan POD type sebagai obyek suatu class yang tidak mempunyai userdefined
constructor, anggota protected maupun private, tidak punya base class, dan
tidak memiliki fungsi virtual.

Dalam desain suatu aplikasi terdiri atas banyak class, dan masing-masing class tidak
berdiri sendiri melainkan saling bergantung atau berhubungan satu sama lain. Salah satu
contoh hubungan tersebut adalah hubungan antara satu class dengan satu atau lebih base
class atau parent class. Jika class C mempunyai base class B, dikenal dengan
inheritance, maka deklarasi class menjadi,
class C : public B {}; atau
class C : protected B {}; atau
class C : private B {};
akses terhadap anggota base class B dapat bersifat public, protected, maupun private,
atau disebut dengan istilah public, protected atau private inheritance. Class C disebut
dengan istilah derived class. Jika tidak dinyatakan bentuk akses secara eksplisit, seperti
dalam deklarasi berikut:
class C : B
maka interpretasinya adalah private inheritance (default), tetapi jika menggunakan
struct maka tetap merupakan public inheritance.
Jika desainer class C tersebut menginginkan hubungan multiple inheritance (MI)
terhadap class B dan A, maka deklarasi class C menjadi,
class C : public B, public A { };
Sebuah class, seperti halnya class C mempunyai anggota berupa data maupun fungsi
(member function). Isi class tersebut berada diantara tanda kurung { } dan dipilah-pilah
sesuai dengan batasan akses yang ditentukan perancang (desainer) class tersebut.
class C : public B
{
public:
(explicit) C()(:member-initializer);
C(const C& );
C& operator=(const C&);
(virtual)~C();

Created By Muhammad Syahrizal 40


statement lain
(protected: statement)
(private: statement)
};

Secara ringkas batasan akses (access specifiers) mempunyai arti seperti ditunjukkan
pada table berikut ini,

Batasan Akses
Arti
public Semua class atau bebas
protected Class itu sendiri, friend, atau derived class
private Class itu sendiri, friend

Sebuah class dapat memberikan ijin untuk class lain mengakses bagian protected
maupun private class tersebut melalui hubungan friendship (dinyatakan dengan keyword
friend).
Sebuah class mempunyai beberapa fungsi khusus, yaitu constructor, copy constructor,
destructor dan copy assignment operator.

Constructor
C() adalah anggota class yang bertugas melakukan inisialisasi obyek (instance) dari
suatu class C. Constructor mempunyai nama yang sama dengan nama class, dan tidak
mempunyai return value. Sebuah class dapat mempunyai lebih dari satu constructor.
Constructor yang tidak mempunyai argumen, disebut default constructor, sebaliknya
constructor yang mempunyai lebih dari satu argumen adalah non-default consructor.
Constructor dengan satu default argument tetap merupakan sebuah default constructor,
class C
{
public:
C(int count=10) : _count(count) {}

private:
int _count;
};
Compiler C++ dapat menambahkan default constructor bilamana diperlukan, jika dalam
definisi class
• tidak tertulis secara eksplisit sebuah default constructor dan tidak ada deklarasi
constructor lain (copy constructor).
• tidak ada anggota class berupa data const maupun reference.
Sebagai contoh definisi class C sebagai berikut,
class C {…};
C c1; // memerlukan default constructor
C c2(c1); // memerlukan copy constructor
Compiler C++ memutuskan untuk menambahkan default dan copy construtor setelah
menemui kedua baris program tersebut, sehingga definisi class secara efektif menjadi
sebagai berikut,

Created By Muhammad Syahrizal 41


class C
{
public:
C(); // default costructor
C(const C& rhs); // copy constructor
~C(); // destructor
C& operator=(const C& rhs); // assignment operator
C* operator&(); // address-of operator
const C* operator&(const C& rhs) const;
};
compiler menambahkan public constructor, dan destructor. Selain itu, compiler juga
menambahkan assignment operator dan address-of operator. Constructor (default dan
non-default) tidak harus mempunyai akses public, sebagai contoh adalah pola desain
(design pattern) Singleton.
class Singleton
{
public:
static Singleton* instance();
protected:
Singleton();
private:
static Singleton* _instance;
};
obyek (instance) singleton tidak dibentuk melalui constructor melainkan melalui fungsi
instance. Tidak ada obyek singleton lain yang dapat dibentuk jika sudah ada satu obyek
singleton.

Umumnya default constructor bentukan compiler (generated default constructor)


menggunakan default constructor anggota bertipe class, sedangkan anggota biasa (builtin
type) tidak diinisialisasi. Demikian halnya dengan obyek yang dibentuk dari obyek
lain (copy), maka copy constructor bentukan compiler (generated copy constructor)
menggunakan copy constructor dari anggota bertipe class pada saat inisialisasi. Sebagai
contoh deklarasi class C berikut ini,
class C
{
public:
C(const char* aName);
C(const string& aName);

private:
std::string name;
};
copy constructor bentukan compiler menggunakan copy constructor class string
untuk inisialisasi name dari aName. Jika class C tidak mempunyai constructor, maka
compiler menambahkan juga default constructor untuk inisialisasi name menggunakan
default constructor class string.
Inisialisasi obyek menggunakan constructor (non-default) dapat dilakukan dengan
member initializer maupun dengan assignment sebagai berikut,
member initialization assignment
class C

Created By Muhammad Syahrizal 42


{
int i,j;
public:
C() : i(0),j(1) {}

};
class C
{
int i,j
public:
C()
{
i=0;j=0;
}

};

Kedua cara tersebut memberikan hasil yang sama, tidak ada perbedaan signifikan antara
kedua cara tersebut untuk data bukan tipe class. Cara member initializer mutlak
diperlukan untuk data const maupun reference, seperti kedua contoh berikut ini:
class C //:1
{
public:
C(int hi,int lo) : _hi(hi),_lo(lo) {}

private:
const int _hi,_lo; // const member
};
class C //:2
{
public:
C(const string& aName) : name(aName) {}

private:
std::string& name; // reference member
};

Cara member initialization sebaiknya dilakukan untuk anggota bertipe class (userdefined
type) seperti ditunjukkan pada contoh berikut ini,
class C
{
public:
C(const string& aName) : name(aName) { }
private:
std::string name; // bukan reference member
};

Pertimbangan menggunakan cara member initialization terletak pada efisiensi eksekusi


program. Hal ini berkaitan dengan cara kerja C++ yang membentuk obyek dalam dua
tahap,
• pertama, inisialisasi data
• kedua, eksekusi constructor (assignment)

Created By Muhammad Syahrizal 43


Dengan demikian jika menggunakan cara assignment sebenarnya eksekusi program
dilakukan dua kali, pertama inisialisasi kemudian assignment, sedangkan menggunakan
member initialization hanya memanggil sekali constructor class string. Semakin
kompleks class tersebut (lebih kompleks dari class string) semakin mahal (tidak
efisien) proses pembentukan obyek melalui cara assignment.
Constructor dengan satu argumen berfungsi juga sebagai implicit conversion operator.
Sebagai contoh deklarasi class A dan B berikut ini,
class A
{
public:
A();
};
class B
{
public:
B(const A&);
};
pada cuplikan baris program di bawah ini terjadi konversi tipe obyek A ke B secara
implisit melalui copy constructor class B.
A a
B b=a; // implicit conversion

explicit
C++ menyediakan satu sarana, menggunakan keyword explicit, untuk mengubah
perilaku constructor dengan satu argumen agar tidak berfungsi sebagai conversion
operator. Jika class B menyatakan explicit pada copy constructor sebagai berikut,
class B
{
public:
explicit B(const A& a); // explicit ctor
};
maka konversi A ke B secara implisit tidak dapat dilakukan. Konversi A ke B dapat
dilakukan secara eksplisit menggunakan typecast,
A a;
B b=static_cast<B>(a); atau
B b=(B)a;

Konversi secara implisit dapat terjadi melalui argumen fungsi f dengan tipe B
void f(const B& );
tetapi f diakses dengan variabel tipe A, f(a). Apabila class B menghalangi konversi
secara implisit maka argumen fungsi f menjadi,
f((B)a); atau
f(static_cast<B>(a));

Konversi tipe obyek secara implisit sebaiknya dihindari karena efeknya mungkin lebih
besar terhadap aplikasi program secara keseluruhan dan tidak dapat dicegah pada saat
kompilasi, karena construcor dengan argumen tunggal adalah suatu pernyataan program
yang sah dan memang dibutuhkan.

Created By Muhammad Syahrizal 44


Copy Constructor dan Copy Assignment
Sejauh ini sudah dibahas mengenai copy constructor sebagai anggota class yang
berperan penting pada saat pembentukan obyek. Apabila sebuah class tidak menyatakan
secara tegas copy constructor class tersebut, maka compiler menambahkan copy
constructor dengan bentuk deklarasi,
C(const C& c);
Bentuk lain copy constructor adalah sebagai berikut,
C(C& c); atau
C(C volatile& c); atau
C(C const volatile& c);

Copy constructor class C adalah constructor yang mempunyai satu argumen. Sebuah
copy constructor boleh mempunyai lebih dari satu argumen, asalkan argumen tersebut
mempunyai nilai default (default argument).
C(C c); // bukan copy constructor
C(C const& c,A a=b); //copy constructor
Constructor dengan argumen bertipe C saja (tanpa reference) bukan merupakan copy
constructor.
Copy constructor juga dibutuhkan pada saat memanggil suatu fungsi yang menerima
argumen berupa obyek suatu class,
void f(C x);
memerlukan copy onstructor class C untuk mengcopy obyek c bertipe C ke obyek x
dengan tipe yang sama, yaitu pada saat memanggil fungsi f(c)(pass-by-value).

Hal serupa terjadi pada saat fungsi f sebagai berikut,


C f()
{
C c;

return c;
}
mengirim obyek c ke fungsi lain yang memanggil fungsi f() tersebut.
Copy assignment operator class C adalah operator=, sebuah fungsi yang mempunyai
satu argumen bertipe C. Umumnya deklarasi copy assignment mempunyai bentuk,
C &operator=(const C &c);
Bentuk lain yang mungkin adalah,
C &operator=(C &c); atau
C &operator=(C volatile &c); atau
C &operator=(C const volatile &c);
Copy assignment boleh mempunyai argumen dengan tipe C (bukan reference), tetapi
tidak boleh mempunyai argumen lebih dari satu walaupun argumen tersebut mempunyai
nilai default (default argument). Seperti halnya copy constructor, compiler akan
menambahkan copy assignment jika suatu class tidak mempunyai fungsi tersebut. Copy
assignment dibutuhkan untuk membentuk obyek melalui assignment, seperti contoh
berikut
class C
{

Created By Muhammad Syahrizal 45


public:
C(); //ctor
~C(); //dtor

};
C c1;
C c2=c1; //copy constructor
C c3;
c3=c1; //copy assignment

Class C tidak mempunyai copy constructor maupun copy assignment operator, maka
pembentukan obyek c2, dan c3 menggunakan copy constructor dan copy assignment
yang ditambahkan oleh compiler ke class C tersebut.
Suatu class yang mempunyai data dengan alokasi dinamik (pointer) sebaiknya tidak
mengandalkan copy constructor maupun copy assignment operator yang ditambahkan
compiler. Copy assignment hasil tambahan compiler mengcopy (memberwise copy)
pointer dari obyek satu (yang dicopy) ke obyek lainnya (hasil copy), sehingga kedua
obyek mengacu ke lokasi memori yang sama. Masalah timbul jika kedua obyek
mempunyai masa pakai (lifetime1) yang berbeda. Jika salah satu obyek sudah habis
masa pakainya maka destructor obyek tersebut mengembalikan memori (dynamic
memory) yang digunakan obyek tersebut, padahal copy obyek tersebut masih mengacu
ke lokasi memori yang sama.

Pada contoh hasil copy assignment b=a (shalow copy), menunjukkan kedua obyek a dan
b mengacu ke lokasi memori p. Apabila obyek a melepas memori p (melalui destructor),
maka obyek b mengacu ke lokasi memori yang sudah tidak valid lagi. Lokasi memori p
dapat digunakan obyek lain jika obyek a melepasnya. Demikian pula halnya dengan
lokasi memori q, apabila obyek b habis masa pakainya (keluar scope, dihapus dll) maka
destructor class B tidak melepas memori q. Akibatnya terjadi pemborosan memori
(memory leak).

Salah satu jalan keluar adalah dengan menyatakan secara tegas copy constructor dan
copy assignment yang dibutuhkan suatu class sehingga compiler tidak membuat copy
constructor dan copy assignment ke class tersebut. Alternatif lain adalah menempatkan
deklarasi copy constructor dan copy assignment operator private sebagai berikut,
class C
{ …
private:
C(const C&);
C &operator=(const C&);
};
definisi copy constructor dan copy assignment operator class C pada contoh di atas
tidak perlu ada, karena tujuannya adalah menghalangi proses penggandaan (copy)
menggunakan kedua fungsi tersebut. Pada tahap kompilasi penggunaan assignment,
b=a masih dapat diterima karena deklarasi asignment operator tersebut tersedia. Pada
saat link akan gagal karena linker tidak dapat menemukan definisi copy assignment
operator. Teknik ini masih mempunyai kelemahan, karena class lain masih mungkin
mempunyai akses ke private copy constructor dan copy assignment operator tersebut

Created By Muhammad Syahrizal 46


(melalui hubungan friendship).

Destructor
Destructor adalah anggota class (member function) yang berfungsi melepas memori
pada saat suatu obyek sudah tidak diperlukan lagi. Fungsi destructor kebalikan
constructor. Destructor tidak mempunyai atau memerlukan argumen. Destructor juga
tidak mengembalikan nilai apapun (tidak mempunyai return type). Seperti halnya
constructor, compiler dapat menambahkan sebuah destructor jika sebuah class tidak
mempunyai destructor.
virtual Destructor
Sebuah destructor dapat berupa fungsi virtual. Hal ini menjadi keharusan jika class B,
• merupakan base class.
• class D yang menggunakan B sebagai base class mempunyai anggota berupa
data dengan alokasi memori dinamik (pointer).
class B
{
public:
B();
~B();
};
class D : public B
{
public:
D() : p(new char[256]) {}
~D()
{
delete[] p;
}

private:
char *p;
};

Pada contoh tersebut destructor base class B bukan fungsi virtual. Dalam C++
umumnya obyek class D digunakan secara polimorphic dengan membentuk obyek class
D (derived class) dan menyimpan alamat obyek tersebut dalam pointer class B (base
class) seperti pada contoh berikut ini,
void main(void)
{
B *pB=new D();
delete pB;
}

Dalam standar C++ menghapus obyek D (derived class) melalui pointer class B (base
class) sedangkan destructor base class non-virtual mempunyai efek yang tidak menentu
(undefined behaviour). Apabila standard C++ tidak menetapkan apa yang seharusnya
berlaku, maka terserah kepada pembuat compiler menentukan perilaku program pada
kondisi semacam ini. Umumnya pembuat compiler mengambil langkah untuk tidak
memanggil destructor class D (derived class). Dengan demikian, pada saat menjalankan

Created By Muhammad Syahrizal 47


perintah delete, destructor class D tidak dieksekusi karena destructor base class B
nonvirtual.

Akibatnya lokasi memori dinamik yang digunakan class D tidak pernah dilepas.
Hal ini adalah contoh lain terjadinya pemborosan memori (memory leak) oleh suatu
program. Jalan keluarnya adalah membuat destructor base class B virtual,
class B
{
public:
B();
virtual ~B();
}

Tidak seperti destructor, tidak ada virtual constructor atau virtual copy constructor.
Pada saat membentuk obyek, tipe obyek harus diketahui terlebih dahulu, apakah
membentuk obyek class A, B, C dsb. Tidak ada aspek bahasa C++ untuk mewujudkan
virtual constructor secara langsung, menempatkan virtual pada deklarasi constructor
merupakan kesalahan yang terdeteksi pada proses kompilasi. Efek virtual constructor
bukan tidak mungkin dicapai, C++ memungkinkan membuat idiom virtual constructor
yang bertumpu pada fungsi virtual dalam kaitannya dengan hubungan antara sebuah
class dengan base classnya.

Konversi Basis Bilangan


Biasanya dalam berinteraksi dalam dunia nyata , kita menggunakan bilangan dengan
basis 0 (Desimal) sebagai perantaranya. Tapi karena satu dan lain hal kita perlu juga
menggunakan basis bilangan lain . Dalam dunia digital misalnya . Ukuran terkecil untuk
menyatakan satuan data dalam dunia digital ialah bit. 1 Bit terdiri dari 2 buah keadaan
yaitu 1 atau 0 , low atau high dsbnya. Mengingat pentingnya proses konversi tersebut
maka kali ini kita akan membahas cara mengkonversi bilangan dengan basis dasar 10
menjadi bilangan dengan basis 2 sampai 16. Dan dengan algoritma yang sama anda bisa
kembangkan sendiri untuk mengkonversi sampai basis ke N. Kita akan menggunakan
Metode rekursif untuk pembentukan algoritmanya.

Metode Konvensional
Oke sebelum menginjak kepada metode konvensional , ada beberapa hal yang perlu kita
ketahui. Maksud dari basis bilangan 10 ialah karakter bilangan yang tersedia ialah dari
‘0’ sampai dengan ‘9’ . maksud dari basis bilangan 2 , karakter yang tersedia ialah dari
‘0’ sampai ‘1’ . Nah bagaimana dengan basis yang lebih besar dari 10 ? . Jika basis lebih
besar dari 10 digunakan karakter abjad . Misalkan basis 16 . Maka karakter bilangan yang
tersedia yaitu dari ‘0’ .. ‘9’ , ‘A’ , ‘B’,’C’,’D’,’E’,’F’. Begitu seterusnya untuk bilangan
diatas basis 10.

Dibawah ini ialah salah satu metode konvensional untuk merubah bilangan dengan basis
dasar 10 ke basis lainnya , yang mana penulis dapat ketika masih duduk di bangku
sekolah dasar .

Created By Muhammad Syahrizal 48


Misalkan kita ingin mencari berapakah nilai bilangan 10 dalam basis 10 jika di konversi
ke basis 2 (biner) . Untuk itu perhatikan gambar berikut

Pada gambar 1 didapat bahwa 10(10) = 1010(2)


Algoritma pada gambar 1 dapat dijelaskan sebagai berikut . Nilai 10 kita bagi dengan
basis tujuan yang kita mau (dalam hal ini 2 ) maka akan dihasilkan 5 , dengan sisa 0 .
Kemudian 5 kita kembali bagi dengan basis yang kita tuju , sehingga 5 dibagi dengan 2 .
Maka akan didapat 2 dengan sisa 1 begitu seterusnya. Langkah ini diulangan terus sampai
hasil dari pembagian ialah 0 . Hasil konversinya didapat dari merunut sisa hasil
pembagian dari yang paling bawah ke atas ( lihat gambar ) Dari gambar diperoleh 1010
sebagai hasil.

Listing Program
Setelah kita tahu cara metode pengkonversiannya , maka tentunya tidak sulit lagi untuk
membuatnya kedalam bahasa pemrograman C . Untuk memudahkan dan sekalian
memahami penggunaan rekursif , maka fungsi akan dibuat dengan menggunakan rekursif
Berikut ialah listing programnya :

#include <stdio.h>
char ch[17] = "0123456789ABCDEF";
void CetakBaseN(int base,int nilai)
{
if (nilai == 0) //jika nilai sudah 0 maka keluar
return;
CetakBaseN(base,nilai / base);
printf("%c",ch[nilai % base]);
}
void main(void)

Created By Muhammad Syahrizal 49


{
CetakBaseN(2,255); printf("\n");
CetakBaseN(8,255); printf("\n");
CetakBaseN(10,255); printf("\n");
CetakBaseN(16,255); printf("\n");
}

Cara kerja Fungsi CetakBaseN

Misalkan kita memanggil fungsi CetakBaseN dengan nilai base = 2 dan nilai = 10 . Maka
pertama – tama dicek apakah nilai = 0 , jika sama maka langsung keluar . Ternyata nilai
tidak sama dengan 0 maka lanjutkan pada baris berikutnya .
Yaitu memanggil dirinya sendiri dengan parameter nilai yang kini bernilai nilai / base (
10 / 2 = 5) (Langkah 1)

Kemudian di cek kembali apakah nilai == 0 , dilanjutkan dengan memanggil dirinya


sendiri yang kini parameter nilai bernilai nilai / base (5 / 2 = 2) (Langkah 2) begitu
seterusnya . Ketika nilai == 0 (pada pemanggilan fungsi yang ke 5) maka fungsi akan
keluar (Langkah 5) dan akan melanjutkan fungsi pemanggilnya yaitu mencetak sisa dari
nilai / base . Kemudian fungsi akan keluar lagi (Langkah 6 ) dan kembali mencetak sisa
dari nilai / base fungsi pemanggilnya dan begitu seterusnya.
CetakBase(2,10)
CetakBase(2,5)
CetakBase(2,2)
CetakBase(2,1)
CetakBase(2,0)

Created By Muhammad Syahrizal 50


Memahami Konsep OOP
dengan C++ .

Pembahasan Kelas Dalam C++


Tulisan ini merupakan pengenalan kepada pemrograman berorientasi objek (Object-oriented
Programming, selanjutnya disebut OOP) dengan menggunakan ANSI C++. Disarankan agar Anda
menguasai dasar-dasar pemrograman struktural terlebih dahulu dengan menggunakan salah satu
bahasa pemrograman, baik C, Pascal, Basic atau yang lainnya. Sedikit sejarah tentang C++, C++
diciptakan oleh Bjarne Stroustrup di laboratorium Bell pada awal tahun 80-an, sebagai
pengembangan dari bahasa C dan Simula. Saat ini, C++ merupakan salah satu bahasa yang paling
populer untuk pengembangan software berbasis OOP. Tulisan ini memperkenalkan paradigma
pemrograman berorientasi objek dengan menggunakan C++.

Bagaimana Konsep OOP?


Konsep utama pemrograman berorientasi objek yaitu melakukan permodelan objek dari kehidupan
nyata ke dalam tipe data abstrak. Jelasnya, pemrograman berorientasi objek merupakan konsep
pemrograman untuk memodelkan objek yang kita gunakan dalam kehidupan sehari-hari, dan konsep
seperti ini membawa perubahan yang mendasar dalam konsep pemrograman terstruktur. Perubahan
dramatis dalam konsep dasar disebut paradigma, maka jangan heran bila banyak orang yang
menyebut “paradigma OOP” karena memang OOP membawa konsep yang sama sekali berbeda
dengan bahasa pemrograman generasi sebelumnya (bahasa pemrograman terstruktur). Setiap objek
dalam kehidupan nyata dapat kita pandang sebagai kelas, misalnya kelas Hewan, kelas Manusia,
kelas Mobil. Sedangkan objek dari kelas tersebut misalnya sapi dan ayam untuk kelas Hewan, Budi
dan Tono untuk kelas Manusia serta Toyota dan VW untuk kelas Mobil. Dengan OOP, kita dapat
mengimplementasikan objekt data yang tidak hanya memiliki ciri khas (attribut), melainkan juga
memiliki metode untuk memanipulasi attribut tersebut. Singkatnya, OOP memiliki keunggulan dari
konsep pemrograman terstruktur, selain itu juga memiliki kemampuan untuk mengimplementasikan
objek dalam kehidupan nyata.

Struktur Kelas
Sebagai langkah pertama dalam OOP akan kita bahas pendefinisian kelas di C++. Dalam bagian 1.2
penulis telah mencontohkan beberapa kelas yang lazim kita temui dalam kehidupan sehari-hari. Mari
kita amati contoh lain dari kehidupan kita, dengan mendeklarasikan sebuah kelas bernama
BilanganRasional :
class BilanganRasional
{
public :
void assign (int,int);
void cetak();
private :
int pembilang, penyebut;

Created By Muhammad Syahrizal 51


};

Perhatikan contoh di atas. Untuk mendefinisikan sebuah kelas, dipakai kata kunci class, diikuti
dengan pendeklarasian nama kelas tersebut. Fungsi assign() dan cetak() disebut member function
(member fungsi). Sedangkan variabel pembilang dan penyebut disebut member data (member data
atau member variabel). Disebut member karena kesemuanya merupakan anggota dari kelas
BilanganRasional.

Perhatikan kata kunci Public dan Private. Member functions pada contoh di atas dideklarasikan
sebagai fungsi global, sedangkan member data dideklarasikan sebagai lokal. Perbedaannya, member
global dapat diakses dari luar kelas, sedangkan member lokal hanya dapat diakses dari kelas itu
sendiri.

Sekarang, dimana kita telah menciptakan kelas Bilangan Rasional, kita dapat mendeklarasikan
sebuah objek dari kelas BilanganRasional sebagai berikut :
BilanganRasional objekBilangan;

Perhatikan bahwa disini objekBilangan merupakan nama dari objek tersebut, dan BilanganRasional
merupakan nama kelas yang ingin kita buat objeknya. Proses pembuatan sebuah objek biasa disebut
penginstansian (bukan penginstalasian), dan sebuah objek disebut instans (instance) dari sebuah
kelas.

Untuk lebih jelasnya, perhatikan listing selengkapnya :


class BilanganRasional

{
public :
void assign (int,int);
void cetak();
private :
int pembilang, penyebut;
};
void main()
{
//mendeklarasikan objekBilangan seperti telah dibahas di atas
BilanganRasional objekBilangan;
// member fungsi assign() dipanggil.
objekBilangan.assign (22,7);
// member fungsi cetak() dipanggil.
ObjekBilangan.cetak();
}
void BilanganRasional::assign(int pemb, int peny)
{
pembilang = pemb;
penyebut = peny;
}
void BilanganRasional::cetak()
{
cout<<pembilang<<' / '<<penyebut;
}

Perhatikan blok main(). Sekarang Anda sudah mempunyai sebuah objek bernama objekBilangan dari
kelas BilanganRasional. Seperti Anda lihat, pendeklarasian sebuah objek sama seperti
mendeklarasikan sebuah variabel. Atau dengan kata lain objekBilangan adalah sebuah objek dengan

Created By Muhammad Syahrizal 52


tipe BilanganRasional. Sekarang, bagaimana memanggil fungsi dari sebuah objek? Hal ini dapat
dicapai dengan menghubungkan nama objek dan fungsi yang ingin dipanggil dengan operator tanda
titik (.). Sehingga untuk memanggil fungsi assign(), dapat dilakukan dengan cara sebagai berikut :
objekBilangan.assign(22,7);

Nilai 22 dan 7 merupakan parameter yang diterima oleh fungsi assign(). Di dalam fungsi tersebut,
nilai 22 diinisialisasikan ke dalam member data pembilang, dan nilai 7 diinisialisasikan ke dalam
member data penyebut. Sehingga bila fungsi cetak() dipanggil, maka akan diperoleh hasil sebagai
berikut :

Sebagai tambahan perhatikan ilustrasi di bawah ini :

Gambar di atas merupakan ilustrasi dari objek objekBilangan dengan 2 member data, yakni
pembilang dan penyebut.

Perhatikan juga bahwa semua pendeklarasian fungsi, baik fungsi assign() maupun fungsi cetak()
didahului dengan penanda BilanganRasional:: . Hal ini untuk menunjukkan kepada compiler agar
compiler tidak “bingung”, untuk kelas mana fungsi tersebut dideklarasikan, karena di C++ biasanya
sebuah fungsi diletakkan di file yang terpisah.

Konstruktor
Sebelumnya kita telah menggunakan member fungsi assign() untuk memasukkan nilai ke dalam
member variabel pembilang dan penyebut. Sebuah konstruktor melakukan tugas yang sama dengan
fungsi assign(), sehingga Anda tidak perlu repot-repot memanggil fungsi assign() untuk setiap objek
yang Anda deklarasikan. Sebuah konstruktor harus mempunyai nama yang sama dengan kelas
dimana konstruktor tersebut berada, dan dideklarasikan tanpa return value (nilai balik), juga tanpa
kata kunci void. Mari kita kembangkan kelas BilanganRasional yang telah kita bahas sebagai
berikut :
class BilanganRasional
{
public :
//KONSTRUKTOR BilanganRasional
BilanganRasional(int pemb, int peny)
{
pembilang = pemb;
penyebut = peny;
}
private :
int pembilang, penyebut;
};

Bandingkan struktur konstruktor dengan fungsi assign() yang telah kita bahas sebelumnya.
Konstruktor BilanganRasional melakukan tugas yang sama dengan member fungsi assign().

Created By Muhammad Syahrizal 53


Bedanya hanya terletak pada pemanggilan fungsi dan konstruktor tersebut. Jika fungsi assign() harus
kita panggil dengan didahului oleh pendeklarasian sebuah objek, kemudian fungsi dari objek
tersebut dipanggil dengan operator titik disertai nilai yang ingin kita input, misal
BilanganRasional x;
x.assign(22,7);
maka konstruktor cukup dipanggil sebagai berikut :
BilanganRasional x(22,7);
Kedua varian tersebut melakukan hal yang sama, yakni menginitialisasikan nilai 22 ke member
variabel pembilang, dan nilai 7 ke variabel penyebut.

Konstruktor Dengan Initialization Lists


Penulisan konstruktor dengan daftar initialisasi (initialization lists) merupakan fasilitas yang
disediakan oleh C++ untuk menyederhanakan struktur konstruktor. Ini berarti, contoh konstruktor di
atas dapat pula ditulis sebagai berikut :
class BilanganRasional
{
public :
BilanganRasional(int pemb, int peny) : pembilang(pemb),
penyebut(peny) { }
private :
int pembilang, penyebut;
};
Contoh di atas menghasilkan fungsi yang sama dengan konstruktor yang kita bahas sebelumnya.

CopyConstructor
Sampai sejauh ini kita telah mempelajari bagaimana struktur sebuah konstruktor serta bagaimana
membuat objek dari konstruktor yang telah didefinisikan. Akan tetapi, coba bayangkan apabila Anda
telah mempunyai sebuah objek x, dan kemudian Anda menginginkan membuat sebuah objek y yang
memiliki nilai member data dan member fungsi yang sama. Tentu saja Anda dapat mendeklarasikan
objek baru dengan memanggil konstruktor yang sama sebanyak 2 kali :
BilanganRasional x(22,7);
BilanganRasional y(22,7);

Perintah di atas mendeklarasikan 2 objek, yakni x dan y yang masing-masing memiliki nilai 22 pada
member variabel pembilang dan 7 pada member variabel penyebut. Akan tetapi, Anda dapat juga
mempersingkat kode diatas dengan perintah berikut :
BilanganRasional x(22,7);
BilanganRasional y(x);
Berikut listing contoh untuk Copy Constructor :
class BilanganRasional
{
public :
BilanganRasional(int pemb, int peny) : pembilang(pemb),
penyebut(peny) { }
//CopyConstructor terdapat disini
BilanganRasional(const BilanganRasional& br) :
pembilang(br.pembilang), penyebut(br.penyebut) { }
private :
int pembilang, penyebut;
};
void main()
{
BilanganRasional x(22,7);
BilanganRasional y(x);
}

Created By Muhammad Syahrizal 54


Deklarasi CopyConstructor otomatis dipanggil ketika Anda mengkopi objek x ke objek y. Perhatikan
bahwa x menjadi parameter ketika kita mendeklarasikan objek y.

Destruktor
Jika kita mendeklarasikan konstruktor untuk membuat sebuah objek, maka kita juga harus
mendeklarasikan sebuah destruktor untuk menghapus sebuah objek. Setiap kelas mempunyai tepat
satu destruktor. Jika Anda tidak mendeklarasikan sebuah destruktor dalam sebuah kelas, maka
destruktor otomatis akan diciptakan sendiri oleh compiler C++. Destruktor dapat kita definisikan
sendiri dengan simbol ~. Disarankan untuk mendefinisikan sendiri destruktor walaupun secara
otomatis compiler C++ akan mendeklarasikan sebuah destruktor pada saat program Anda dicompile,
tetapi dengan mendefinisikan sendiri sebuah destruktor maka Anda mempunyai kontrol penuh
terhadap apa yang dilakukan destruktor dari kelas Anda. Perhatikan listing di bawah :
class BilanganRasional
{
public :
BilanganRasional() {cout <<"Konstruktor dipanggil\n";}
//Destruktor dari kelas BilanganRasional
~BilanganRasional() {cout <<"Destruktor dipanggil\n";}
private :
int pembilang, penyebut;
};
void main()
{
BilanganRasional x;
cout<<"Disini main program\n" ;
}

Listing di atas akan menghasilkan output sebagai berikut :


Konstruktor dipanggil
Disini main program
Destruktor dipanggil

Dari contoh di atas dilihat bahwa konstruktor dipanggil ketika objek x dibuat. Sedangkan destruktor
secara otomatis dipanggil oleh compiler ketika objek x meninggalkan blok main(). Hal ini sesuai
dengan kaidah kelokalan objek di C++.

Ringkasan
Pada bab ini Anda telah mengetahui konsep OOP, mengapa OOP disebut paradigma serta apa
bedanya konsep pemrograman berorientasi objek dengan konsep pemrograman terstruktur. Anda
juga telah belajar mendefinisikan sebuah kelas, mendefinisikan member fungsi dan member data
serta struktur konstruktor dan destruktor dari sebuah kelas. C++ juga menyediakan fasilitas jika
Anda ingin membuat duplikat sebuah objek, yaitu menggunakan fasilitas CopyConstructor. Selain
itu Anda juga telah belajar mendeklarasikan sebuah konstruktor dengan Initialization Lists, sehingga
pendeklarasian konstruktor Anda menjadi lebih efisien.

Membangun aplikasi berbasis GUI di Unix mengharuskan penggunaan Application


Programming Interface (API) dari X Window. Bertahun-tahun yang silam, hanya API ini
yang tersedia. Tidak heran bahwa API yang lengkap namun relatif ekstensif dan berat
menyebabkan tidak semua programmer mempunyai cukup energi untuk mempelajarinya.
Dus, mengembangkan aplikasi untuk X bukanlah hal yang menyenangkan bagi tiap

Created By Muhammad Syahrizal 55


orang.

Belakangan muncul toolkit yang memang dirancang untuk memudahkan pembuatan


aplikasi dengan bertindak selaku lapis abstraksi, selain juga untuk memicu upaya
konsistensi look-and-feel antara satu program dengan program lainnya. Dengan
menggunakan toolkit, API X Window yang rumit menjadi disembunyikan melalui
sekumpulan fungsi-fungsi yang lebih sederhana. Lebih jauh, setelah kehadiran toolkit,
muncul pula desktop environment seperti CDE, KDE, dan GNOME yang meningkatkan
derajat abstraksi pengembangan aplikasi menjadi lebih dari sekedar user interface
semata.

Qt adalah toolkit yang digunakan untuk membangun aplikasi berbasis GUI di Unix. Qt
dikembangkan oleh Trolltech [1] dan menjadi fondasi untuk K Desktop Environment
(KDE), selain juga telah dipergunakan dalam berbagai aplikasi komersial. Qt
digolongkan sebagai software open-source karena dilisensi dual: dengan General Public
License (GPL) dan Qt Public License (QPL). Khusus untuk tulisan ini, yang akan dibahas
adalah Qt versi 2.x.

Qt dirancang untuk pengembangan aplikasi dengan C++. Oleh karenanya, Qt berisi


sekumpulan kelas-kelas yang tinggal dimanfaatkan saja, mulai dari urusan antarmuka
(user interface), operasi input ouput, networking, timer, template library, dan lain-lain. Qt
mendukung penuh Unicode (mulai versi 2.0) sehingga urusan internationalization (I18N)
dan encoding teks bukan menjadi masalah. Walaupun merupakan free software, Qt
terbukti stabil dan lengkap. Dibandingkan toolkit lain, Qt juga mudah untuk dipelajari
dan dipersenjatai dengan dokumentasi dan tutorial yang ekstensif dan rinci.
Untuk dapat mempelajari Qt, syarat utama adalah tersedia Qt pada sistem Anda. Bila
tidak, maka Qt bisa didownload terlebih dahulu dari situs web Qt di Trolltech.com.
Selanjutnya, Anda bisa mengikuti instruksi yang diberikan untuk melakukan compile dan
instalasi. Qt dirancang cocok untuk digunakan di lingkungan Unix, oleh karenanya Anda
seharusnya tidak akan menemui hambatan dalam proses kompilasi.
Cara lain yang lebih menghemat waktu dan tenaga (dan juga bandwidth) adalah dengan
mengambil Qt yang sudah dipaket dalam RPM atau DEB. Tentunya paket yang diambil
harus sesuai dengan distribusi Linux yang digunakan. Lokasi paling gampang untuk
memperoleh Qt versi RPM adalah pada server FTP untuk KDE 2, hal ini karena Qt 2.x
selalu tersedia bersama KDE [2].
Hello World !
Sudah menjadi tradisi, bahwa untuk memulai mempelajari penggunaan sebuah bahasa
pemrograman maupun library, contoh aplikasi pertama selalu yang berkenaan dengan
"Hello World". Mengikuti kebiasaan ini, berikut adalah program berbasis Qt untuk
menampilkan pesan yang sangat terkenal ini:
1: // qhello.cpp - Qt Hello world
2:
3: #include <qapplication.h>
4: #include <qlabel.h>
5:
6: int main( int argc, char **argv )
7: {
8: QApplication app( argc, argv );
9: QString msg( "Hello world !" );
10:
11: QLabel txt( "Hello world !", 0 );
12: txt.resize( 250,50 );

Created By Muhammad Syahrizal 56


13: txt.setAlignment( Qt::AlignCenter );
14:
15: app.setMainWidget( &txt );
16: txt.show();
17:
18: return app.exec();
19: }
Listing 1: qhello.cpp

Mengasumsikan Qt terinstal di /usr/lib/qt2, maka contoh program di atas dapat


dikompilasi dengan perintah berikut ini:
g++ -o qhello qhello.cpp -lqt -I /usr/lib/qt2/include -L /usr/lib/qt2/lib
(Belakangan Makefile akan digunakan untuk memudahkan proses kompilasi sehingga
tidak perlu melalui perintah yang panjang seperti di atas).
Pada perintah di atas, option -I menentukan lokasi pencarian file header yang akan
di-include dalam program sementara option -L untuk memberi informasi lokasi library
untuk proses link, dalam hal ini adalah libqt.so. Bisa dilihat, bahwa dengan option -l,
contoh program ini dilink dengan library qt.

Tentu saja Anda mungkin mendapatkan hasil yang berbeda karena baik dekorasi window
dan style dari program akan sangat tergantung kepada window manager yang digunakan.
Walaupun demikian, secara fungsional, program qhello ini tidak akan berubah. Contoh
di atas adalah qhello yang dijalankan pada KDE dengan theme dari SuSE.

Untuk memberikan gambaran dengan jelas akan apa yang terjadi, berikut akan diuraikan
penjelasan mengenai source code program qhello ini.
Dua kelas utama yang digunakan di sini adalah QApplication dan QLabel. Yang pertama
adalah untuk membangun sebuah aplikasi generik, sedangkan yang kedua dibutuhkan
sebagai elemen user interface untuk menampilkan label, yaitu sebuah teks dalam
window. Kedua kelas ini terlebih digunakan dengan meng-include-kan file header yang
bersesuaian, yaitu qapplication.h dan qlabel.h.
Objek app adalah dari kelas QApplication. Dapat dilihat di sini bahwa QApplication
selalu diinisialisasi dengan memberikan seluruh argumen program. Lebih rinci mengenai
hal ini bisa dirujuk ke dokumentasi Qt.
Objek txt adalah label yang berasal dari kelas QLabel. Objek ini dikonstruksi dengan
memberikan string yang akan ditambilkan. Argumen kedua pada konstruktornya, yaitu 0,
bermakna bahwa QLabel ini tidak diikatkan ke objek lainnya.

Fungsi setMainWidget diperlukan agar label yang barus saja dibuat dijadikan widget
utama window aplikasi. Dalam terminologi Qt, widget berarti objek yang berhubungan
dengan user interface. Label adalah hanya salah satu jenis widget. Menu, button, kotak
dialog, dan lain-lain adalah juga widget. Walaupun tidak harus, biasanya sebuah aplikasi
memiliki widget utama, yang dalam hal ini diset dengan setMainWidget. Perhatikan
bahwa setelahnya fungsi show perlu dipanggil secara eksplisit. Tanpa ini, widget tidak
akan tampak (alias hidden).

Signal dan Slot


Salah satu karakteristik dari Qt adalah penggunaan signal dan slot. Karena Qt dibangun
dengan C++, maka baik signal maupun slot terintegrasi sebagai bagian dari kelas-kelas
yang terdapat pada Qt. Lebih jauh, signal/slot menjadi bagian dari object model yang
digunakan Qt. Object model ini didesain khusus untuk memudahkan pemrograman

Created By Muhammad Syahrizal 57


aplikasi yang berbasis GUI.

Sebuah signal menandakan bahwa sesuatu telah terjadi. Signal dibangkitkan manakala
terjadi interaksi antara user dan program, seperti misalnya ketika user mengklik mouse
atau mengetikkan sesuatu di keyboard. Signal juga bisa dipicu oleh hal-hal yang
merupakan internal program, misalnya karena sebuah timer yang diaktifkan sebagai
alarm.

Slot adalah fungsi yang berespon terhadap signal tertentu. Untuk dapat melakukan hal ini,
sebelumnya slot harus dikoneksikan dengan signal yang dimaksud.
Contoh program berikut menggambarkan penggunaan signal dan slot yang sederhana.
Coba Anda cermati listing pogramnya berikut ini:
1: // qclick.cpp - Qt Click-to-quit example
2:
3: #include <qapplication.h>
4: #include <qpushbutton.h>
5:
6: int main( int argc, char **argv )
7: {
8: QApplication app( argc, argv );
9:
10: QPushButton button( "Click to quit !", 0 );
11: button.resize(250,50);
12:
13:
14: QObject::connect( &button, SIGNAL(clicked()),
15: &app, SLOT(quit()) );
16:
17: app.setMainWidget( &button );
18: button.show();
19:
20: return app.exec();
21: }
Listing 2: qclick.cpp

Anda dapat mencoba dahulu untuk menjalankan program qclick. Lakukan compile
dengan perintah berikut ini:
g++ -o qclick qclick.cpp -lqt -I /usr/lib/qt2/include -L /usr/lib/qt2/lib
Program qclick tidak banyak berbeda dengan contoh sebelumnya. Di sini dimanfaatkan
QPushButton untuk menghasilkan sebuah button pada window aplikasi, karenanya
digunakan file header qpushbutton.h. Objek button dikonstruksi dengan memberikan
string yang menjadi caption dari button tersebut.

Berbeda dengan contoh sebelumnya, program qclick ini sudah dapat sedikit berespons.
Bila tombol "Click to quit" diklik, maka program akan segera diakhiri. Dapat dilihat pada
source codenya, bahwa hal ini terjadi karena signal QPushButton::clicked() dari
objek button dihubungkan dengan slot QApplication::quit() dari object app. Dalam
dokumentasi Qt disebutkan bahwa QPushButton akan memicu (emit) signal clicked()
kalau user mengklik tombol tersebut. Sementara itu, slot QApplication bernama quit(),
manakala dieksekusi akan menyebabkan program utama berakhir.

Jelas bahwa fungsi QObject::connect() akan menyambungkan satu signal dengan


sebuah slot tertentu. Baik signal maupun slot dapat saja dimiliki oleh objek yang berbeda.
Pada contoh di atas, signal QPushButton::clicked() dihubungkan dengan slot

Created By Muhammad Syahrizal 58


QApplication::quit().

Pagelaran Widget
User-interface yang hanya dibangun dari tombol (alias button) semata tentu saja tidak
menarik. Pada ulasan di bawah, akan ditunjukkan beberapa widget yang paling sering
digunakan untuk sebuah program aplikasi yang umum. Beberapa di antaranya adalah
label, edit box, list box, check box, radio button, dan slider.

Untuk menghasilkan program Gallery ini, dibutuhkan beberapa file yaitu gallery.cpp,
main.cpp,dan sebuah Makefile.
Bagaimana widget-widget tersebut dirangkaikan menjadi satu ? Lihat file header
gallery.h dan file gallery.cpp di bawah ini:
1: // gallery.h
2:
3: #ifndef __GALLERY_H
4: #define __GALLERY_H
5:
6: #include <qwidget.h>
7:
8: class Gallery: public QWidget
9: {
10: Q_OBJECT
11:
12: public:
13: Gallery();
14:
15: private:
16: };
17:
18: #endif
Listing 3: gallery.h

Perhatikan bahwa pada pendefinisiannya, digunakan Q_OBJECT yang berarti kelas ini
menjadi bagian dari object model yang digunakan Qt. Dengan demikian, file header ini
harus diproses dengan Meta Object Compiler (moc).
1: // gallery.cpp - Gallery of some Qt widgets
2:
3: #include "gallery.moc"
4:
5: #include <qpushbutton.h>
6: #include <qbuttongroup.h>
7: #include <qcheckbox.h>
8: #include <qradiobutton.h>
9: #include <qlabel.h>
10: #include <qlineedit.h>
11: #include <qslider.h>
12: #include <qcombobox.h>
13:
14: // this is pixmap for a button
15: const static char * floppy_xpm[] = {
16: "16 16 11 1",
17: " c None",
18: ". c #5D5D5D",
19: "+ c #000000",
20: "@ c #303030",
21: "# c #FFFFFF",
22: "$ c #800080",
23: "% c #DCDCDC",
24: "& c #C3C3C3",
25: "* c #000080",
26: "= c #0000FF",

Created By Muhammad Syahrizal 59


27: "- c #585858",
28: "++++++++++++++++",
29: "+@+$=$*$=$*$=+@+",
30: "+#+##########+++",
31: "+@+##########+@+",
32: "+@+#$*$=$*$=#+@+",
33: "+@+##########+@+",
34: "+@+#$*$=$*$*#+@+",
35: "+@+##########+@+",
36: "+@@++++++++++@@+",
37: "+@@@@@@@@@@@@@@+",
38: "+@@@++++++++@@@+",
39: "+@@+#%#%%%&%+@@+",
40: "+@@+%@-&%&%&+@@+",
41: "+@@+#@-%&%&&+@@+",
42: "++@+%&%&%&&&+@@+",
43: " +++++++++++++++"};
44:
45:
46: Gallery::Gallery(): QWidget( 0, "Widget" )
47: {
48: setCaption("Gallery of Widgets");
49: resize( 260, 330 );
50:
51: // label
52: QLabel* name_label = new QLabel ( "Name", this );
53: name_label->move ( 5, 5 );
54:
55: // edit box
56: QLineEdit* name_editbox = new QLineEdit ( "(type your name)", this
);
57: name_editbox->move ( 50, 7 );
58: name_editbox->resize ( 200, 24 );
59:
60: // another label
61: QLabel* prof_label = new QLabel ( "Profession", this );
62: prof_label->move ( 5, 35 );
63:
64: // combo box
65: QComboBox* prof = new QComboBox ( this );
66: prof->insertItem ( "Engineer" );
67: prof->insertItem ( "Student" );
68: prof->insertItem ( "Professor" );
69: prof->resize ( 180, 24 );
70: prof->move ( 70, 35 );
71:
72: // some check boxes
73: QButtonGroup* bg = new QButtonGroup ( 3, Qt::Vertical, "Known Unix
systems", this );
74: QCheckBox* linux_check = new QCheckBox ( "Linux", bg );
75: QCheckBox* bsd_check = new QCheckBox ( "BSD", bg );
76: QCheckBox* solaris_check = new QCheckBox ( "Solaris", bg );
77: bg->resize ( 250, 100 );
78: bg->move( 5, 70 );
79: linux_check->setChecked( TRUE );
80:
81: // radio buttons in a group, arranged horizontally
82: QButtonGroup* browserbg = new QButtonGroup ( 3, Qt::Horizontal,
83: "Browser of choice", this );
84: QRadioButton* netscape_button = new QRadioButton( "Netscape",
browserbg );
85: QRadioButton* konq_button = new QRadioButton( "&Konqueror",
browserbg );
86: QRadioButton* mozilla_button = new QRadioButton( "Mozilla",
browserbg );
87: browserbg->resize ( 250, 50 );
88: browserbg->move( 5, 180 );
89: konq_button->setChecked( TRUE );

Created By Muhammad Syahrizal 60


90:
91: // horizontal slider
92: QSlider* vol = new QSlider ( QSlider::Horizontal, this );
93: vol->resize ( 250, 30 );
94: vol->move ( 5, 240 );
95: vol->setRange ( 0, 100 );
96: vol->setValue ( 35 );
97: vol->setTickmarks ( QSlider::Below );
98:
99:
100: // normal button
101: QPushButton* normal_button = new QPushButton ( "Normal &Button",
this );
102: normal_button->move( 5, 290 );
103:
104: // toggle button
105: QPushButton* toggle_button = new QPushButton ( "Toggle", this );
106: toggle_button->setToggleButton( TRUE );
107: toggle_button->move( 110, 290 );
108:
109: // button with picture
110: QPushButton* pic_button = new QPushButton ( "Floppy", this );
111: pic_button->resize( 29, 29 );
112: pic_button->move( 220, 290 );
113: pic_button->setPixmap( floppy_xpm );
114:
115: }
Listing 4: gallery.cpp

Penting diingat bahwa widget diturunkan dari kelas QWidget. Kelas ini memiliki
beberapa fungsi dasar penanganan widget yang umum. Dua diantaranya digunakan di
gallery.cpp, yaitu move dan resize, masing-masing untuk memindahkan widget ke
lokasi yang baru dan untuk memodifikasi ukuran (dimensi) widget tersebut. Untuk lebih
rincinya, silakan merujuk ke dokumentasi Qt [3].

Sebuah label adalah teks statik yang diletakkan begitu saja, biasanya untuk memberikan
keterangan widget lain. Pada contoh di atas misalnya, terdapat dua buah label: "Name"
dan "Profession" yang masing-masing menjelaskan sedikit makna dari widget-widget di
sebelahnya. Label dibentuk dengan kelas QLabel (dan akibatnya membutuhkan file
qlabel.h supaya ter-include-kan). Contoh pembuatan QLabel pada listing program yang
diberikan relatif sederhana, menggunakan konstruktor:
QLabel::QLabel ( const QString & text, QWidget * parent,
const char * name, WFlags f )
Di sini text menyatakan string yang ditampilkan sementara parent selalu menunjuk ke
widget yang menjadi empunya label tersebut. Berikut-berikutnya akan jelas bahwa ketika
mengkonstruksi sebuah widget dari sebuah window, argument parent hampir selalu
this. Baik name dan flag f adalah opsional dan dapat diabaikan untuk sementara.
Perhatikan bahwa sebuah label dapat saja terdiri atas beberapa baris. Bagaimana cara
membuatnya ? Cukup dengan mengatur text pada konstruktornya. Bila misalnya text ini
adalah "dua baris\n teks, nih!", maka hasilnya adalah string yang disajikan dalam dua
baris, semata-mata karena adanya karakter '\n' yang berfungsi sebagai line feed. Anda
dapat mencobanya sendiri kalau penasaran.

Sebuah edit box adalah kotak isian yang lazimnya dimanfaatkan untuk menerima
masukan dari user. Edit box ini biasanya hanya untuk string dalam satu baris saja. Dengan
Qt, edit box dibuat menggunakan kelas QLineEdit dari file header qlineedit.h. Panjang
maksimum string yang bisa dimasukkan adalah 32767 karakter.

Created By Muhammad Syahrizal 61


Konstruksi QLineEdit malah lebih sederhana dibandingkan QLabel:
QLineEdit::QLineEdit ( QWidget * parent, const char * name )
Lagi-lagi di sini parent menentukan pemilik objek QLineEdit yang dibuat dan diisi
this). Argumen name, karena tidak wajib, maka diacuhkan saja.

Kalaulah Anda cermat, maka bentuk konstruktor yang sebenarnya digunakan oleh
program Gallery adalah:
QLineEdit::QLineEdit ( const QString & contents, QWidget * parent,
const char * name )
Tambahan argument contents menentukan isian awal dari edit box ini. Dengan cara ini,
edit box yang baru dibuat tidak akan kosong begitu saja, seperti ditunjukkan pada contoh
program yang diberikan.

Sebuah combo box juga berfungsi untuk menerima masukan dari user sebagaimana edit
box. Bedanya adalah bahwa combo box biasanya menawarkan pilihan untuk user,
biasanya dengan tombol panah di ujungnya yang jikalau diklik akan mendaftarkan
item-item yang dapat dipilih. Bahkan, bisa jadi sebuah combo box cuma mengijinkan
masukan dari pilihan item yang tersedia dan tidak memungkinkan input sembarang.

Bagaimana menghasilkan combo box ? Gunakan kelas QComboBox dari file header
qcombobox.h dengan pilihan konstruktor:
QComboBox::QComboBox ( bool rw, QWidget * parent=0, const char * name )
atau yang lebih pendek:
QComboBox::QComboBox ( QWidget * parent=0, const char * name )
Argumen rw menentukan apakah combo box yang dibuat bersifat read-and-write. Bila
diisi FALSE, maka yang terjadi adalah read-only, yaitu bahwa combo box hanya
menerima input dari pilihan item yang disediakan saja.

Salah satu fungsi anggota paling penting dari QComboBox adalah insertItem.
Sebagaimana dicontohkan pada gallery.cpp di atas, fungsi ini digunakan untuk
menambahkan (atau lebih tepatnya menyisipkan) item baru pada daftar pilihan combo
box tersebut.

Dua widget lain yang tidak kalah seringnya dipergunakan adalah radio button dan check
box. Masing-masing sering digunakan untuk mengaktifkan atau menonaktifkan pilihan
tertentu, dengan perbedaan kecil bahwa umumnya radio button berlaku untuk pilihan
yang eksklusif (hanya satu di antaranya yang aktif). Masing-masing widget ini dibentuk
dari kelas QRadioButton (file header qradiobutton.h) dan kelas QCheckBox (file
header qcheckbox.h). Perhatikan konstruktornya di bawah ini:
QRadioButton::QRadioButton ( const QString & text, QWidget * parent,
const char * name )
QCheckBox::QCheckBox ( const QString & text, QWidget * parent,
const char * name )

Sering sekali secara visual sejumlah radio button atau check box digabungkan dalam
kelompok tertentu. Dengan Qt, hal ini dapat dilakukan menggunakan kelas
QButtonGroup dengan konstruktor:
QButtonGroup::QButtonGroup ( int strips, Orientation orientation,
QWidget * parent, const char * name )
(Jangan lupa untuk menyertakan file header qbuttongroup.h).
Di sini strip menentukan jumlah radio button atau check box yang dikelompokkan,

Created By Muhammad Syahrizal 62


orientation mengatur orientasi, bisa bernilai Qt::horizontal atau Qt::vertical,
masing-masing untuk arah mendatar dan tegak.

Dengan mengumpulkan radio button atau check box dalam sebuah grup, maka argument
parent pada konstruksi objeknya tidak bisa lagi menunjuk this. Hal ini jelas misalnya
dari pembuatan check box dengan caption "Linux" pada contoh program yang diberikan:
QCheckBox* linux_check = new QCheckBox ( "Linux", bg );

Jelas bahwa parent kini adalah bg yang tidak lain tidak bukan adalah objek dari kelas
QButtonGroup yang digunakan untuk mengumpulkan tiga buah check box,
masing-masing dengan caption "Linux", "BSD", dan "Solaris". Hal yang sama berlaku
juga untuk group Browser, yang kali ini membawahi tiga buat radio button yang tersusun
horizontal.

Fungsi setChecked dari kelas QRadioButton dan QCheckBox dapat digunakan untuk
mengaktifkan ataupun menonaktifkan widget yang dimaksud. Khusus untuk radio button,
bila salah satunya (dalam kelompok yang sama) diaktifkan (setChecked( TRUE )), maka
yang lainnya akan otomatis dinonaktifkan.

Widget penting lainnya adalah slider, yaitu sebuah penggeser yang memberikan nilai
berdasarkan sebuah skala ukuran yang tetap. Slider semacam ini cocok misalnya untuk
pengatur volume audio. Qt menyediakan kelas QSlider (dan file header qslider.h)
untuk menghasilkan objek berupa sebuah slider. Simak konstruktornya:
QSlider::QSlider ( Orientation orientation, QWidget * parent,
const char * name )
Di sini orientation menentukan apakah slider tersebut mendatar (bila bernilai
QSlider::Horizontal) ataukah tegak (untuk QSlider::Vertical).
Setelah objek slider dikonstruksi, fungsi setRange dapat dijalankan untuk mengatur
rentang nilai yang bisa diatur dari penunjuk slider. Menempatkan penunjuk pada posisi
awal bisa dilakukan dengan fungsi setValue.

Widget terakhir yang ditunjukkan program Gallery adalah button. Terdapat tiga variasi
dari button yang disajikan, yaitu normal, toggle, serta button dengan bitmap. Button yang
normal tentulah tidak asing lagi, mengingat button ini telah diperkenalkan sebelumnya
(program qclick). Button dengan kemampuan toggle dibuat dengan cara memanggil
fungsi setToggleButton( TRUE ). Jadi cukup sederhana dan tidak ada tambahan sesuatu
yang lain. Pun button dengan pixmap tidak lain adalah button biasa yang diberikan
bitmap, kali ini dengan fungsi setPixmap. Program Gallery mencontohkan pixmap
(berupa gambar disket) dalam format XPM, namun sesungguhnya Qt mendukung pula
format-format lain seperti BMP, PNG, GIF, dan JPEG.

Sekedar informasi tambahan, XPM adalah format pixmap untuk X. Tidak umum seperti
GIF, BMP, JPEG, dan PNG yang merupakan format data binary, XPM adalah dalam teks
ASCII biasa (Anda dapat memodifikasinya dengan editor teks). Hal ini menyebabkan file
*.xpm dapat begitu saja di-include-kan dalam program dan pixmapnya bisa langsung
digunakan (dan karenanya menjadi pilihan tepat untuk sebuah icon ataupun pixmap kecil
pada button). Untuk mengkonversi dari format lain ke XPM ataupun sebaliknya, paling
gampang menggunakan GIMP [4].

Created By Muhammad Syahrizal 63


Patut dicatat bahwa file program gallery.cpp memerlukan file gallery.moc. File
terakhir yang akan di-include-kan dalam program ini dapat dengan menjalankan MOC
(Meta Object Compiler). Akan dilihat bahwa file .moc akan dihasilkan secara otomatik
pada saat kompilasi.

File main.cpp akan merangkaikan user interface yang dibuat sebelumnya ke dalam
sebuah program utuh, sebagaimana ditunjukkan berikut ini:
1: // main.cpp - part of Gallery
2: #include <qapplication.h>:
3: #include "gallery.h"
4:
5: int main( int argc, char ** argv )
6: {
7: QApplication a( argc, argv );
8: Gallery g;
9: a.setMainWidget( &g );
10: g.show();
11: return a.exec();
12: }
Listing 5: main.cpp

Melakukan Kompilasi
Melakukan proses compile dan link secara manual akan amat menjemukan. Dengan
bantuan make, semuanya bisa menjadi lebih sederhana. Makefile yang diberikan di sini
relatif generik dan bisa diadaptasi dengan mudah untuk program-program Qt lainnya:
1: QTDIR = /usr/lib/qt2
2: QTLIB = $(QTDIR)/lib
3: QTINCLUDE = $(QTDIR)/include
4: QTMOC = $(QTDIR)/bin/moc
5:
6: TARGET = gallery
7: OBJECTS = gallery.o main.o
8: MOCS = gallery.moc
9:
10: CC = g++
11: CFLAGS = -Wall -O2
12: LIBS = -lqt
13:
14: $(TARGET): $(MOCS) $(OBJECTS)
15: $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) -L$(QTLIB)
-I$(QTINCLUDE)
16:
17: %.o: %.cpp
18: $(CC) $(CFLAGS) -I$(QTINCLUDE) -c $< -o $@
19:
20: %.moc: %.h
21: $(QTMOC) $< -o $@
22:
23: clean:
24: rm $(OBJECTS) $(TARGET) $(MOCS)
Listing 6: Makefile untuk Gallery

Bila Anda masih kurang jelas tentang penggunaan Makefile, silakan merujuk ke manual
GNU Make [5] (atau dengan menggunakan perintah info make). Bagi yang ingin lebih
canggih lagi, kelak akan digunakan autoconf dan automake sebagai pengganti Makefile
Sekarang kompilasi program Gallery dengan mengetikkan: make. Bila tidak ada sesuatu
yang salah, maka akan segera tercipta file executable gallery. Jika file ini dieksekusi,
akan tampil sebuah window yang kira-kira serupa sebagaimana screenshot yang telah
ditunjukkan.

Created By Muhammad Syahrizal 64


Bagi yang teliti, dari Makefile di atas, terlihat aturan (rule) yang digunakan untuk
menghasilkan file gallery.moc yang sudah disinggung sebelumnya. Secara manual, file
ini bisa dihasilkan dengan menjalankan perintah:
moc gallery.h -o gallery.moc
Utility moc sendiri merupakan bagian dari Qt dan sudah tersedia ketika Qt pertama kali
diinstal.

Selamat ber-Qt-ria !

Tanya Jawab

Tanya: Mengapa Qt dan bukan GTK ?


Jawab: Karena Qt adalah fondasi dari KDE. Bila sebaliknya Anda ingin menguasai
pemrograman di GNOME, maka gunakanlah GTK. Lepas dari hal ini, karena Qt sendiri
tersedia untuk Unix/X11, Windows, dan Mac(segera), maka Qt adalah pilihan tepat untuk
mengembangkan aplikasi yang cross-platform. Keuntungan Qt lainnya adalah API yang
beragam dan mudah dipelajari, serta ketersediaan dokumentasi yang lengkap.

Tanya: Bila saya membuat program dengan Qt, apakah program ini hanya dapat
dijalankan di KDE ?
Jawab: Tidak. Selama terdapat library Qt pada sistem yang digunakan, maka program
tersebut tetap dapat dijalankan, tidak perduli apakah user menggunakan KDE, GNOME,
WindowMaker, twm, atau window manager lainnya.

Tanya: Setahu saya KDE 2 menggunakan Qt 2.x. Kalau demikian, apakah program saya
yang juga berbasis Qt 2.x bisa dijalankan di KDE 1.x ?
Jawab: Bila Anda cukup cermat, berdasarkan pertanyaan sebelumnya, maka jawabannya
adalah: ya. Perhatikan bahwa screenshot contoh program qhello pada tulisan ini diambil
di SuSE Linux 7.0, masih dengan KDE 1.1.2.

Tanya: Nah, sekarang bila program Qt saya mau digunakan oleh user yang tidak
mempunyai library Qt, bagaimana caranya ?
Jawab: Gunakan static-linking yang akan memaksa Qt ikut serta pada executable yang
dihasilkan (ini adalah salah satu yang digunakan di Opera for Linux).

Tanya: Alih-alih C++, bisakah saya menggunakan ANSI C untuk memanfaatkan Qt ?


Jawab: Tentu saja, karena sudah tersedia binding dari Qt untuk C "murni" (bukan C++).
Jangankan C, Anda pun bisa menggunakan Perl, Python, Ruby, dan bahkan Java.

Tanya: Bagaimana perbedaan konsep signal/slot dengan callback ?


Jawab: Signal/slot mempunyai keuntungan bahwa penggunaannya lebih sederhana
dibandingkan callback. Untuk pemrograman berorientasi objek (OOP), hal ini menjadi
lebih menyederhanakan persoalan. Lagipula, signal/slot bersifat typesafe dalam arti
bahwa slot hanya akan menerima signal yang mempunyai nama serta argumen yang sama
persis dengan yang sebelumnya didaftarkan.

Tanya: Dapatkah lebih dari satu slot dihubungkan ke satu signal ?

Created By Muhammad Syahrizal 65


Jawab: Tidak ada batasan mengenai hal ini. Satu signal dapat saja digunakan untuk
memicu beberapa slot (dan kemudian menghasilkan sejumlah event). Demikian juga,
satu slot boleh saja diaktifkan oleh sejumlah signal yang berbeda.

Tanya: Pada contoh program qhello dan qclick, mengapa Meta Object Compiler tidak
digunakan ?
Jawab: Hal ini karena tidak ada Q_OBJECT pada source codenya. Mudah dipahami bahwa
untuk program sesederhana qhello, tidak perlu dibuat sebuah widget baru, yang berarti
juga tidak ada kelas baru yang memanfaatkan Q_OBJECT.

Tanya: Saya terus gagal untuk melakukan compile.


Jawab: Periksa source code Anda (file gallery.cpp). Kemungkinan Anda
meng-include-kan gallery.h, seharusnya adalah gallery.moc.

Tanya: Mengapa tidak digunakan tmake yang sudah tersedia pada Qt untuk
menghasilkan Makefile ?
Jawab: Program Gallery relatif sederhana sehingga Makefile mudah saja dibuat secara
manual. Tentu bila Anda menginginkan, tmake dapat saja dipergunakan dengan sedikit
penyesuaian.

Tanya: Ada begitu banyak widget yang disediakan Qt. Bagaimanakah saya bisa
mempelajari semuanya ?
Jawab: Gampangnya adalah dengan merujuk ke dokumentasi Qt. Biasanya ini bisa
dijumpai di /usr/lib/qt2/doc (atau di tempat lain, sesuai lokasi instalasi Qt). Tips:
untuk cepat mencapai lokasi ini, gunakan fasilitas Bookmark di Konqueror.

Setelah berkenalan dengan Qt dan melihat bagaimana cara mengkomposisikan


widget-widget menjadi suatu bentuk user-inteface, akan menarik untuk menengok
metoda yang harus dilakukan untuk membangun sebuah window utama program
(lengkap dengan toolbar dan menu) sebagaimana lazimnya aplikasi yang berbasis grafis
(GUI).

Menu, Toolbar, dan Statusbar


Sudah barang tentu program "Hello World" hanyalah sekedar program demonstrasi yang
terlalu bersahaja. Berikut ini, akan diulas bagaimana membangun program aplikasi
sebagaimana umumnya, yaitu mencakup pembuatan window utama, membubuhkan
menu, serta menambahkan toolbar dan statusbar. Jangan khawatir karena dengan Qt,
semuanya menjadi mudah dan sederhana.

Program qsimpleapp akan terdiri dari empat file source code, yaitu qsimpleapp.h,
qsimpleapp.cpp, main.cpp, dan icons.h. Sebuah Makefile juga dibutuhkan untuk
memudahkan proses kompilasi. Berikut adalah source code untuk file-file tersebut.
1: // qsimpleapp.h
2: #ifndef __QSIMPLEAPP_H
3: #define __QSIMPLEAPP_H
4:
5: class QMultiLineEdit;
6: class QPopupMenu;
7: class QString;
8: class QToolBar;
9:
10: #include <qmainwindow.h>

Created By Muhammad Syahrizal 66


11:
12: class QSimpleWindow: public QMainWindow
13: {
14: Q_OBJECT
15:
16: public:
17: QSimpleWindow();
18:
19: protected:
20: void initMenu();
21: void initToolbar();
22: void load( const char *fileName );
23:
24: private slots:
25: void fileNew();
26: void fileOpen();
27: void fileSave();
28: void fileSaveAs();
29: void filePrint();
30: void fileClose();
31:
32: void editUndo();
33: void editRedo();
34: void editCut();
35: void editCopy();
36: void editPaste();
37: void editFind();
38:
39: void settingsToggleToolbar();
40: void settingsToggleStatusbar();
41: void configure();
42:
43: void about();
44: void aboutQt();
45:
46: private:
47:
48: QString filename;
49: QMultiLineEdit *e;
50: QToolBar *toolbar;
51: int menuid_toolbar, menuid_statusbar;
52:
53: };
54:
55: #endif
Listing 1: qsimpleapp.h

File qsimpleapp.h adalah file header utama. Pada file ini didefinisikan kelas
QSimpleWindow yang diturunkan dari QMainWindow. Nantinya instance dari objek ini
kelas ini akan dijadikan widget utama program.

Sekedar penjelasan ringkas, fungsi initMenu() adalah untuk menginisialisasi menu,


fungsi initToolbar() untuk mengatur toolbar, dan fungsi load() dipergunakan untuk
membuka dan mengambil dokumen dari file tertentu.

Sejumlah slot baru juga dideklarasikan di sini, bisa dilihat setelah private slots:.
Masing-masing slot ini akan dikoneksikan agar dapat menerima signal yang berasal dari
menu. Dengan demikian, slot fileNew() akan dipanggil bila ada signal yang dihasilkan
dengan memilih New dari menu File, slot slotOpen untuk Open dari menu File, dan
seterusnya.

Created By Muhammad Syahrizal 67


Implementasi dari kelas QSimpleWindow sendiri terletak di file qsimpleapp.cpp berikut
ini:
1: // qsimpleapp.cpp - Qt example program
2: #include <qpixmap.h>
3: #include <qtoolbar.h>
4: #include <qtoolbutton.h>
5: #include <qpopupmenu.h>
6: #include <qmenubar.h>
7: #include <qkeycode.h>
8: #include <qmultilineedit.h>
9: #include <qfileinfo.h>
10: #include <qstatusbar.h>
11: #include <qmessagebox.h>
12: #include <qapplication.h>
13: #include <qaccel.h>
14:
15: #include "qsimpleapp.moc"
16:
17: #include "icons.h"
18:
19: QSimpleWindow::QSimpleWindow()
20: : QMainWindow( 0, "QSimpleWindow", WDestructiveClose )
21: {
22: initMenu();
23: initToolbar();
24:
25: e = new QMultiLineEdit( this, "editor" );
26: e->setFocus();
27: setCentralWidget( e );
28: statusBar()->message( "Ready", 2000 );
29: resize( 450, 600 );
30:
31: menuBar()->setItemChecked( menuid_toolbar, TRUE );
32: menuBar()->setItemChecked( menuid_statusbar, TRUE );
33:
34: setCaption("Untitled - QSimpleApp");
35: }
36:
37:
38: // initialize menu
39: void QSimpleWindow::initMenu()
40: {
41: QPopupMenu * file = new QPopupMenu( this );
42: menuBar()->insertItem( "&File", file );
43:
44: file->insertItem( QPixmap(filenew_xpm), "&New", this,
SLOT(fileNew()), CTRL+Key_N );
45: file->insertItem( QPixmap(fileopen_xpm), "&Open", this,
SLOT(fileOpen()), CTRL+Key_O );
46: file->insertItem( QPixmap(filesave_xpm), "&Save", this,
SLOT(fileSave()), CTRL+Key_S );
47: file->insertItem( "Save &as...", this, SLOT(fileSaveAs()) );
48: file->insertSeparator();
49: file->insertItem( QPixmap(fileprint_xpm), "&Print...", this,
SLOT(filePrint()), CTRL+Key_P );
50: file->insertSeparator();
51: file->insertItem( QPixmap(fileclose_xpm), "&Close", this,
SLOT(fileClose()), CTRL+Key_W );
52: file->insertItem( "&Quit", qApp, SLOT(closeAllWindows() ),
CTRL+Key_Q );
53:
54: QPopupMenu * edit = new QPopupMenu ( this );
55: menuBar()->insertSeparator();
56: menuBar()->insertItem("&Edit", edit);
57: edit->insertItem( QPixmap(editundo_xpm), "Und&o", this,
SLOT(editUndo()), CTRL+Key_U );
58: edit->insertItem( "Redo", this, SLOT(editRedo()) );

Created By Muhammad Syahrizal 68


59: edit->insertSeparator();
60: edit->insertItem( QPixmap(editcut_xpm), "C&ut", this,
SLOT(editCut()), CTRL+Key_X);
61: edit->insertItem( QPixmap(editcopy_xpm), "&Copy", this,
SLOT(editCopy()), CTRL+Key_C );
62: edit->insertItem( QPixmap(editpaste_xpm), "&Paste", this,
SLOT(editPaste()), CTRL+Key_V );
63: edit->insertSeparator();
64: edit->insertItem( QPixmap(editfind_xpm), "&Find...", this,
SLOT(editFind()) );
65:
66: QPopupMenu *settings = new QPopupMenu ( this );
67: menuBar()->insertSeparator();
68: menuBar()->insertItem("&Settings", settings);
69: menuid_toolbar = settings->insertItem ( "Show &Toolbar", this,
SLOT(settingsToggleToolbar()) );
70: menuid_statusbar = settings->insertItem ( "Show &Statusbar",
this, SLOT(settingsToggleStatusbar()) );
71: settings->insertSeparator();
72: settings->insertItem ( QPixmap(configure_xpm), "Configure...",
this, SLOT(configure()) );
73:
74: QPopupMenu * help = new QPopupMenu( this );
75: menuBar()->insertSeparator();
76: menuBar()->insertItem( "&Help", help );
77: help->insertItem( QPixmap(helpabout_xpm), "&About...", this,
SLOT(about()) );
78: help->insertItem( "About &Qt...", this, SLOT(aboutQt()) );
79: }
80:
81: // initialize toolbar
82: void QSimpleWindow::initToolbar()
83: {
84: toolbar = new QToolBar( this );
85:
86: new QToolButton( QPixmap(filenew_xpm), "New", QString::null,
87: this, SLOT(fileNew()), toolbar, "open file" );
88: new QToolButton( QPixmap(fileopen_xpm), "Open", QString::null,
89: this, SLOT(fileOpen()), toolbar, "open file" );
90: new QToolButton( QPixmap(filesave_xpm), "Save", QString::null,
91: this, SLOT(fileSave()), toolbar, "save file" );
92:
93: new QToolButton( QPixmap(fileprint_xpm), "Print",
QString::null,
94: this, SLOT(filePrint()), toolbar, "print file" );
95:
96: toolbar->addSeparator();
97:
98: new QToolButton( QPixmap(editfind_xpm), "Find", QString::null,
99: this, SLOT(editFind()), toolbar, "find");
100:
101: toolbar->addSeparator();
102:
103: new QToolButton( QPixmap(editcut_xpm), "Cut", QString::null,
104: this, SLOT(editCut()), toolbar, "cut");
105: new QToolButton( QPixmap(editcopy_xpm), "Copy", QString::null,
106: this, SLOT(editCopy()), toolbar, "copy");
107: new QToolButton( QPixmap(editpaste_xpm), "Paste",
QString::null,
108: this, SLOT(editPaste()), toolbar, "paste");
109: new QToolButton( QPixmap(editundo_xpm), "Undo", QString::null,
110: this, SLOT(editUndo()), toolbar, "undo");
111:
112: }
113:
114: // creates a new blank file
115: void QSimpleWindow::fileNew()
116: {

Created By Muhammad Syahrizal 69


117: QSimpleWindow *f = new QSimpleWindow;
118: f->show();
119: }
120:
121: // opens and loads from file
122: void QSimpleWindow::fileOpen()
123: {
124: }
125:
126: // loads given file
127: void QSimpleWindow::load( const char *fileName )
128: {
129: // do file loading here
130:
131: // update caption and titlebar
132: QFileInfo fi(fileName);
133: QString fn = fi.fileName();
134: setCaption( fn + " - QSimpleApp" );
135: statusBar()->message( fn + " loaded", 2000 );
136: }
137:
138: // saves active
139: void QSimpleWindow::fileSave()
140: {
141: if ( filename.isEmpty() ) {
142: fileSaveAs();
143: return;
144: }
145:
146:
147: // do file saving here
148:
149:
150: // update caption and statusbar
151: QFileInfo fi(filename);
152: QString fn = fi.fileName();
153: setCaption( fn + " - QSimpleApp" );
154: statusBar()->message( fn + " saved", 2000 );
155: }
156:
157: // saves to a different file
158: void QSimpleWindow::fileSaveAs()
159: {
160: }
161:
162: // prints current document
163: void QSimpleWindow::filePrint()
164: {
165: }
166:
167: // closes this window
168: void QSimpleWindow::fileClose()
169: {
170: close();
171: }
172:
173: // reverts last action
174: void QSimpleWindow::editUndo()
175: {
176: }
177:
178: // redoes last action
179: void QSimpleWindow::editRedo()
180: {
181: }
182:
183:
184: void QSimpleWindow::editCut()

Created By Muhammad Syahrizal 70


185: {
186: }
187:
188: void QSimpleWindow::editCopy()
189: {
190: }
191:
192: void QSimpleWindow::editPaste()
193: {
194: }
195:
196: void QSimpleWindow::editFind()
197: {
198: }
199:
200: void QSimpleWindow::settingsToggleToolbar()
201: {
202: bool isToolbar = menuBar()->isItemChecked( menuid_toolbar );
203: isToolbar = !isToolbar;
204: if(isToolbar) toolbar->show(); else toolbar->hide();
205: menuBar()->setItemChecked( menuid_toolbar, isToolbar );
206: }
207:
208: void QSimpleWindow::settingsToggleStatusbar()
209: {
210: bool isStatusbar = menuBar()->isItemChecked( menuid_statusbar );
211: isStatusbar = !isStatusbar;
212: if(isStatusbar) statusBar()->show(); else statusBar()->hide();
213: menuBar()->setItemChecked( menuid_statusbar, isStatusbar );
214: }
215:
216: void QSimpleWindow::configure()
217: {
218: }
219:
220: void QSimpleWindow::about()
221: {
222: QMessageBox::about( this, "QSimpleApp",
223: "This is a very simple framework example "
224: "for Qt-based application.");
225: }
226:
227: void QSimpleWindow::aboutQt()
228: {
229: QMessageBox::aboutQt( this, "QSimpleApp" );
230: }
Listing 2: qsimpleapp.cpp

Pada source code di atas, bisa dilihat beberapa hal yang cukup penting.
Toolbar dibuat di dalam fungsi initToolbar(). Dapat dilihat bahwa caranya tidak
terlalu rumit, yakni cukup dengan membuat objek baru dari QToolBar, kemudian
menyisipkan button yang diinginkan (dari QToolButton). Kelas QToolButton dapat
dikonstruksi langsung sambil memberikan argumen yang dibutuhkan. Pada contoh ini,
terdapat 6 argumen, masing-masing adalah icon yang ditampilkan, teks untuk caption,
teks untuk grup, slot yang dipanggil jika button diklik (misalnya SLOT(fileNew())),
toolbar yang menjadi induk button ini, serta nama buttonnya. Untuk icon, semuanya
disimpan di file header icons.h dalam format X Pixmap. Caption untuk button biasanya
tidak diperlukan kecuali toolbarnya diatur untuk menampikan icon dengan teks. Garis
vertikal pembatas icon dihasilkan dengan fungsi QToolBar::addSeparator()
Agak sedikit berbeda, susunan menu justru dibangun dari beberapa pop-up menu
menggunakan kelas QPopupMenu yang disisipkan ke menu utama. Kelas

Created By Muhammad Syahrizal 71


QMainWindow menyediakan fungsi menuBar() untuk mendapatkan menu utama ini.

Dengan sendirinya, pop-up menu yang dihasilkan tinggal disisipkan saja, menggunakan
QMenuBar::insertItem. Sementara itu, menyusun pop-up menu sendiri tidaklah sulit,
sebagaimana ditunjukkan dalam fungsi initMenu. Patut dicatat bahwa untuk item menu
yang tidak memiliki icon khusus, argumen pertama untuk gambar icon bisa diabaikan
saja. Pada saat membuat item-item menu, sudah langsung ditetapkan slot yang akan
menerima signal dari item menu tersebut berikut kombinasi tombol shortcutnya, sebagai
contoh SLOT(fileSave()) untuk menu File -> Save dengan shortcut Ctrl+S. Biasanya
hal ini juga disesuaikan dengan caption dari masing-masing item yakni dengan
menggarisbawahi karakter shortcutnya. Dalam contoh sebelumnya, hal ini berarti
karakter S pada item Save harus ditampilkan secara underline yang bisa dilakukan
dengan melekatkan tanda & di depannya (ditulis sebagai "&Save").

Menu Settings memerlukan penanganan khusus. Diinginkan agar user dapat


menampilkan atau menyembunyikan toolbar dan statusbar menggunakan item "Show
toolbar" dan "Shot statusbar". Hal ini bisa dilakukan dengan mengoneksikan signal dari
item menu yang dimaksud dengan slot settingsToggleToolbar() dan
settingsToggleStatusbar(). Perlu ditambilkan juga semacam checkmark pada item
menunya sendiri, karenanya id untuk kedua item ini disimpan pada variabel
menuid_toolbar dan menuid_statusbar supaya selanjutnya bisa diatur dengan fungsi
QMenuBar::isItemChecked dan QMenuBar::setItemChecked

Bagaimana dengan status bar ? Beruntunglah bahwa QMainWindow juga sudah


menyediakan fungsi statusBar() untuk mendapatkan status bar window yang aktif.
Dengan demikian, pesan-pesan tertentu dengan gampang ditampilkan menggunakan
QStatusBar::message(). Untuk panggilan fungsi ini, parameter pertama adalah
teksnya dan parameter kedua (yang sebenarnya opsional) adalah durasi teks tersebut
ditampilkan (dalam mikrodetik). Dengan cara ini, mudah menyajikan pesan tertentu pada
status bar yang akan menghilang sendiri setelah beberapa saat. Bila diinginkan teks di
status bar ini tidak menghilangkan, cukup gunakan satu parameter saja ketika memanggil
QStatusBar::message().
QMessageBox adalah kelas statik yang bisa dipergunakan untuk menampilkan pesan
tertentu. Pada contoh ini, QMessageBox digunakan di slot about() dan aboutQt().
Menarik juga untuk disimak betapa sederhananya instruksi untuk menghasilkan window
baru, yaitu pada slot fileNew. Cukup buat satu instance baru dari window tersebut !
Slot-slot lainnya, yaitu fileOpen, fileSave, dan seterusnya masih tidak berisi apa-apa
karena memang belum ada fungsionalitas khusus dari contoh program ini. Anda tentu
bisa melengkapinya sendiri jika diinginkan.
Bila Anda cukup jeli, terlihat bahwa alih-alih qsimpleapp.h, yang di-include-kan di
qsimpleapp.cpp adalah qsimpleapp.moc. Hal ini karena qsimpleapp.cpp
membutuhkan kelas QSimpleApp yang sudah dimodifikasi dengan Meta Object
Compiler (moc). File qsimpleapp.moc sendiri dihasilkan oleh Meta Object Compiler
(moc) dari file qsimpleapp.h.

Kelas QSimpleWindow yang demikian panjang lebar tidak akan berarti apa-apa bila tidak
dipergunakan. Di bawah ini adalah main.cpp yang membuat aplikasi sesungguhnya
dengan QSimpleWindow sebagai widget utamanya.
1: // Qt Simple Application

Created By Muhammad Syahrizal 72


2: #include <qapplication.h>
3: #include "qsimpleapp.h"
4:
5: int main( int argc, char ** argv )
6: {
7: QApplication a( argc, argv );
8:
9: QSimpleWindow * mw = new QSimpleWindow();
10: mw->show();
11:
12: a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
13:
14: return a.exec();
15: }
Listing 3: main.cpp

Tidak kalah penting adalah icons.h. Icon-icon yang (mudah-mudahan) indah dari
screenshot program di atas, baik untuk menu maupun toolbar, berasal dari file header ini
(yang di-include-kan dari qsimpleapp.cpp).
1: // icons.h - part of Qt example program
2:
3: #ifndef __ICONS_H
4: #define __ICONS_H
5:
6: const static char * configure_xpm[] = {
7: "16 16 10 1",
8: " c None",
9: ". c #FFFFFF",
10: "+ c #000000",
11: "@ c #DCDCDC",
12: "# c #585858",
13: "$ c #A0A0A0",
14: "% c #FFFFFF",
15: "& c #C3C3C3",
16: "* c #303030",
17: "= c #808080",
18: " ++++++ ",
19: " +=#@@$++ ",
20: " +&##@&$+ ",
21: "+++ ++&#@$+ ",
22: "+%$++ +#@@$+ ",
23: "+%@@@+##@@@$+ ",
24: "+#%%@@@@@@@@$++ ",
25: "*%##%%@@@@@@@$$+",
26: "+&@%####$%%@@@@$",
27: " ++&@&&$###%%@@@",
28: " +++$&&&$##%%@",
29: " ++++@@$##%",
30: " ++@@$#",
31: " ++@@",
32: " ++",
33: " "};
34:
35: const static char * editcopy_xpm[] = {
36: "16 16 8 1",
37: " c None",
38: ". c #FFFFFF",
39: "+ c #000000",
40: "@ c #FFFFFF",
41: "# c #303030",
42: "$ c #FFFFC0",
43: "% c #A0A0A0",
44: "& c #DCDCDC",
45: "++++++ ",
46: "+@@@@++ ",
47: "+@@@@+$+ ",

Created By Muhammad Syahrizal 73


48: "+@##@+@$+ ",
49: "+@@@@+++++++ ",
50: "+@##@@%%%+@++ ",
51: "+@@@@@$@$+@+&+ ",
52: "+@###@##$+@+@&+ ",
53: "+@@@$@$$$+@+++++",
54: "+@##@###$+@@%%%+",
55: "+@$@$$$$$+@@@@&+",
56: "+++++++++##@##@+",
57: " +@@@@@@@@+",
58: " +@##@###@+",
59: " +@@@@@@@@+",
60: " ++++++++++"};
61:
62: const static char * editcut_xpm[] = {
63: "16 16 6 1",
64: " c None",
65: ". c #FFFFFF",
66: "+ c #000000",
67: "@ c #808080",
68: "# c #DCDCDC",
69: "$ c #FFFFFF",
70: " ",
71: " ++++ ++ ",
72: "++ ++ +$#+",
73: "++ ++ +$#+ ",
74: " ++ + +$#+ ",
75: " ++++++ +$#+ ",
76: " +++++$#+ ",
77: " ++$#+ ",
78: " +$#++ ",
79: " +++++@#+ ",
80: " ++++++ +$#+ ",
81: " ++ + +$#+ ",
82: "++ ++ +$#+ ",
83: "++ ++ +$#+",
84: " ++++ ++ ",
85: " "};
86:
87: const static char * editfind_xpm[] = {
88: "16 16 13 1",
89: " c None",
90: ". c #FFFFFF",
91: "+ c #000000",
92: "@ c #C0FFFF",
93: "# c #585858",
94: "$ c #FFFFFF",
95: "% c #00C0C0",
96: "& c #303030",
97: "* c #808080",
98: "= c #C3C3C3",
99: "- c #008080",
100: "; c #00FFFF",
101: "gt; c #004040",
102: " +++ # ",
103: " ++%@%++ ",
104: " +-@@@@@-+ ** ",
105: " +@@$$$@@+ *###",
106: "+%@$$$@@@%+ ###&",
107: "+@@$$@@@@@+ && ",
108: "+%@$@@@@@%+ ",
109: " +@@@@@@@+ ",
110: " +-@@@@@-+; ",
111: " ++%@%++%++ ",
112: " +++ gt;+#=+ ",
113: " # +&#=+ ",
114: " # +&#=+ ",
115: " ** +&#=+",

Created By Muhammad Syahrizal 74


116: "*### # +&#+",
117: "###& ++ "};
118:
119: const static char * editpaste_xpm[] = {
120: "16 16 9 1",
121: " c None",
122: ". c #FFFFFF",
123: "+ c #000000",
124: "@ c #A0A0A0",
125: "# c #FFFFFF",
126: "$ c #FFFFC0",
127: "% c #303030",
128: "& c #C0C000",
129: "* c #DCDCDC",
130: " ++ ",
131: " ++++++&&+++++ ",
132: "+@@@@+&++&+@@@+ ",
133: "+*@@+&&&&&&+@@+ ",
134: "+*@@++++++++@@+ ",
135: "+*@@@@+####++@+ ",
136: "+*@@@@+####+$++ ",
137: "+*@@@@+#%%#+#$++",
138: "+*@@@@+####+++++",
139: "+*@@@@+#%%##@@@+",
140: "+*@@@@+#####$#$+",
141: "+*@@@@+#%%%#%%$+",
142: "+*@@@@+###$#$$$+",
143: "+@@@@@+#%%#%%%$+",
144: " ++++++#$#$$$$$+",
145: " ++++++++++"};
146:
147: const static char * editundo_xpm[] = {
148: "16 16 6 1",
149: " c None",
150: ". c #FFFFFF",
151: "+ c #000000",
152: "@ c #00C000",
153: "# c #008000",
154: "$ c #004000",
155: " ",
156: " ++++ ",
157: " ++@@@@++ ",
158: "+ +@@@@####+ ",
159: "+# +@@@##++$##+ ",
160: "+@+@@@#++ ++$+ ",
161: "+@@@@#+ +$+",
162: "+@@@@+ +++",
163: "+@@@@+ +++",
164: "+###### +++",
165: "++++++++ ++ ",
166: " +++ ",
167: " +++ ",
168: " ++++ ",
169: " +++ ",
170: " "};
171:
172: const static char * fileclose_xpm[] = {
173: "16 16 7 1",
174: " c None",
175: ". c #800000",
176: "+ c #C00000",
177: "@ c #000000",
178: "# c #FFFFFF",
179: "$ c #800000",
180: "% c #FFC0C0",
181: " @@@@@@@@ ",
182: " @%%%%%%%%@ ",
183: " @%%+++++++$@ ",

Created By Muhammad Syahrizal 75


184: " @%%+++++++++$@ ",
185: "@%%+##++++##++$@",
186: "@%++###++###++$@",
187: "@%+++######+++$@",
188: "@%++++####++++$@",
189: "@%++++####++++$@",
190: "@%+++######+++$@",
191: "@%++###++###++$@",
192: "@%++##++++##++$@",
193: " @$++++++++++$@ ",
194: " @$++++++++$@ ",
195: " @$$$$$$$$@ ",
196: " @@@@@@@@ "};
197:
198: const static char * filenew_xpm[] = {
199: "16 16 11 1",
200: " c None",
201: ". c #5D5D5D",
202: "+ c #FFFFFF",
203: "@ c #000000",
204: "# c #FFFFC0",
205: "$ c #DCDCDC",
206: "% c #303030",
207: "& c #585858",
208: "* c #C3C3C3",
209: "= c #A0A0A0",
210: "- c #400000",
211: " @@%@@@%@@ ",
212: " %$$$$$*%*@ ",
213: " @$+++++&+$@ ",
214: " @$+++++&$+*@ ",
215: " @$+++++&&&%@ ",
216: " @$++++++$*=@ ",
217: " @$++++++#+$@ ",
218: " @$+++++++++@ ",
219: " @$++++#+#+#@ ",
220: " @$+++++++#+@ ",
221: " @$++#+#+#+#@ ",
222: " @$+++++#+#+@ ",
223: " %$#+#+#+#+#@ ",
224: " @$+++#+#+##@ ",
225: " @$#+#+#+###@ ",
226: " @@@@@@-@@%@@ "};
227:
228: const static char * fileopen_xpm[] = {
229: "16 16 8 1",
230: " c None",
231: ". c #5D5D5D",
232: "+ c #000000",
233: "@ c #A0A0A0",
234: "# c #C3C3C3",
235: "$ c #DCDCDC",
236: "% c #FFA858",
237: "& c #FFDCA8",
238: " ++++ ",
239: " ++ ++++ + ",
240: " + ++++ ",
241: " +++ ",
242: " ++++ ",
243: " ++++ ",
244: "+%&&%+++++++ ",
245: "+&&&&%%%%%%%+ ",
246: "+&&+++++++++++++",
247: "+&%+$$$$$$$$$$$+",
248: "+&+$####@#@#@@+ ",
249: "+%+$###@#@#@@@+ ",
250: "++$###@#@#@@@+ ",
251: "++$##@#@#@@@@+ ",

Created By Muhammad Syahrizal 76


252: "+$##@#@#@@@@+ ",
253: "+++++++++++++ "};
254:
255: const static char * fileprint_xpm[] = {
256: "16 16 12 1",
257: " c None",
258: ". c #FFFFFF",
259: "+ c #FFFFFF",
260: "@ c #A0A0A0",
261: "# c #DCDCDC",
262: "$ c #000000",
263: "% c #585858",
264: "& c #FFDCA8",
265: "* c #C3C3C3",
266: "= c #303030",
267: "- c #808080",
268: "; c #404000",
269: " %$% ",
270: " %++*%$ ",
271: " ;++++++@% ",
272: " %+++++++@$",
273: " $%++++++++=$",
274: " $-*+++++++@-$",
275: " $@%+&+&++++%$ ",
276: " $@@@%%&+&+&@$% ",
277: "$@@@@@@%%%&+=%$ ",
278: "$##@@@@@@@%%%@@$",
279: "$######@@@@@@@%$",
280: "$#########@@@%%$",
281: " $$%########%%%$",
282: " $$%#####%%$ ",
283: " $$%##%$ ",
284: " $$$ "};
285:
286: const static char * filesave_xpm[] = {
287: "16 16 11 1",
288: " c None",
289: ". c #5D5D5D",
290: "+ c #000000",
291: "@ c #303030",
292: "# c #FFFFFF",
293: "$ c #800080",
294: "% c #DCDCDC",
295: "& c #C3C3C3",
296: "* c #000080",
297: "= c #0000FF",
298: "- c #585858",
299: "++++++++++++++++",
300: "+@+$=$*$=$*$=+@+",
301: "+#+##########+++",
302: "+@+##########+@+",
303: "+@+#$*$=$*$=#+@+",
304: "+@+##########+@+",
305: "+@+#$*$=$*$*#+@+",
306: "+@+##########+@+",
307: "+@@++++++++++@@+",
308: "+@@@@@@@@@@@@@@+",
309: "+@@@++++++++@@@+",
310: "+@@+#%#%%%&%+@@+",
311: "+@@+%@-&%&%&+@@+",
312: "+@@+#@-%&%&&+@@+",
313: "++@+%&%&%&&&+@@+",
314: " +++++++++++++++"};
315:
316: const static char * helpabout_xpm[] = {
317: "16 16 5 1",
318: " c None",
319: ". c #FFFFFF",

Created By Muhammad Syahrizal 77


320: "+ c #000000",
321: "@ c #0000FF",
322: "# c #000080",
323: " +++++++ ",
324: " +@#+++@#++ ",
325: " +@#+ +@@#+ ",
326: " +@+ +@#+ ",
327: " +@#+ +@#+ ",
328: " +@#+ +@#+ ",
329: " ++ +@#+ ",
330: " +@#+ ",
331: " +@#+ ",
332: " +@#+ ",
333: " +@#+ ",
334: " ++ ",
335: " ",
336: " ++ ",
337: " +@#+ ",
338: " ++ "};
339:
340: #endif
Listing 4: icons.h

Proses kompilasi dilakukan dengan menggunakan Makefile. Ini adalah serupa dengan
Makefile yang pernah disajikan di bagian pertama seri tulisan ini, hanya dilakukan
modifikasi di bagian TARGET, OBJECTS, dan MOCS. Sekedar menyegarkan ingatan,
sebagaimana telah diungkapkan di bagian pertama seri tulisan ini, Anda mungkin perlu
menyesuaikan QTDIR sesuai dengan direktori instalasi Qt pada sistem Anda.
1: QTDIR = /usr/lib/qt2
2: QTLIB = $(QTDIR)/lib
3: QTINCLUDE = $(QTDIR)/include
4: QTMOC = $(QTDIR)/bin/moc
5:
6: TARGET = qsimpleapp
7: OBJECTS = qsimpleapp.o main.o
8: MOCS = qsimpleapp.moc
9:
10: CC = g++
11: CFLAGS = -Wall -O2
12: LIBS = -lqt
13:
14: $(TARGET): $(MOCS) $(OBJECTS)
15: $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) -L$(QTLIB)
-I$(QTINCLUDE)
16:
17: %.o: %.cpp
18: $(CC) $(CFLAGS) -I$(QTINCLUDE) -c $< -o $@
19:
20: %.moc: %.h
21: $(QTMOC) $< -o $@
22:
23: clean:
24: rm $(OBJECTS) $(TARGET) $(MOCS)
Listing 5: Makefile untuk QSimpleApp

Sekarang kompilasi program QSimpleApp dengan mengetikkan: make. Dengan


menjalankan file executable qsimpleapp, akan muncul sebuah window yang kira-kira
serupa sebagaimana screenshot pada awal tulisan. Program tersebut tidak mempunyai
fungsionalitas yang jelas alias sekedar demo. Kendati demikian, diharapkan kerangka
program yang dibangun di sini dapat dipergunakan untuk mengembangkan program lain
yang lebih fungsional.

Created By Muhammad Syahrizal 78


Sebagai latihan, berangkat dari QSimpleApp, Anda dapat membuat editor teks dengan
mudah. Untuk ini, dokumentasi Qt tentang QMultiLineEdit akan sangat menolong. Pada
instalasi Qt, disertakan juga contoh program editor teks yang dapat dipelajari.

Proses Kompilasi

Dengan Makefile, kerumitan melakukan compile-and-link (dan juga menjalankan moc)


tidak dijumpai karena hal ini secara otomatis dikerjakan oleh make. Sekedar agar dapat
mengetahui apa yang sebenarnya terjadi, untuk melakukan compile program di atas
secara manual (tidak menggunakan Makefile), maka berikut adalah langkah-langkahnya:
• Guna memudahkan, set dahulu variabel lingkungan yang sesuai, dalam hal ini adalah
QTDIR, QTINCLUDE, dan QTLIB. Bisa dilakukan dengan perintah seperti ini:
• export QTDIR=/usr/lib/qt2
• export QTINCLUDE=$(QTDIR)/include
• export QTLIB=$(QTDIR)/lib

Tentu saja ini harus disesuaikan lokasi instalasi Qt pada sistem Anda. Untuk shell selain
bash, Anda juga harus mengubah untuk mengatur environment variable (lihat manual
dari shell yang Anda gunakan).
• File qsimpleapp.moc dapat dihasilkan dengan menjalankan Meta Object Compiler
seperti berikut ini:
• $(QTDIR)/bin/moc qsimpleapp.h -o qsimpleapp.moc
• Selanjutnya, compile kedua file cpp yang ada, sebagaimana diilustrasikan di bawah ini:
• g++ -c qsimpleapp.cpp
• g++ -c main.cpp
• Akhirnya, link semua file objek untuk menghasilkan programnya:
• g++ -o qsimplepp qsimpleapp.o main.o -I$(QTINCLUDE) -L$(QTLIB)
-lqt

Tanya Jawab

Tanya: Saya terus gagal untuk melakukan compile.


Jawab: Periksa source code Anda (file qsimpleapp.cpp). Kemungkinan Anda
meng-include-kan qsimpleapp.h, seharusnya adalah qsimpleapp.moc.

Tanya: Terkadang, setelah mengakhiri program, muncul pesan kesalahan "Segmentation


Fault". Mengapa ?
Jawab: Masalah dependensi terkadang menyebabkan file hasil Meta Object Compiler
tidak sinkron dengan program utama. Solusinya adalah melakukan kompilasi ulang
semua file (gampangnya dengan menjalankan make clean, baru kemudian make seperti
biasa).
Tanya: Bagaimana membuat item pada menu utama yang punya sub-menu lagi ?
Jawab:. Anda bisa menyisipkan item tersebut dengan fungsi
QPopupMenu::insertItem ( const QString & text, QPopupMenu * popup). Di
sini text adalah teks untuk item tersebut sedangkan popup merupakan sub-menu dari
item ini. Jangan lupa untuk membuat sub-menunya terlebih dahulu sebelum memanggil
fungsi di atas.

Tanya: Pada GTK, tiap menu mempunyai handle khusus yang jika diklik akan
menyebabkan menu tersebut seakan terlepas dari program utama dan mengambang
(floating menu). Bagaimana cara menghasilkan yang semacam ini di Qt ?

Created By Muhammad Syahrizal 79


Jawab: Gunakan fungsi QPopupMenu::insertTearOffHandle() sebelum menyisipkan
item pertama pada sebuah menu (dengan demikian, handle ini akan diletakkan paling
atas). Anda akan mendapatkan hasil persis seperti yang Anda inginkan.

Tanya: Bagaimana menyisipkan combobox di toolbar ?


Jawab: Gunakan QMenuData::insertItem ( QWidget * widget ). Sebagai widget,
masukkan combobox yang dimaksud. Karena fungsi ini bisa digunakan untuk
menyisipkan widget apa saja, ini berarti tidak hanya terbatas untuk combobox semata.

Tanya: Kalau kita lihat browser seperti Netscape, toolbarnya mempunyai button yang
relatif lebih besar dan dilengkapi dengan teks. Apakah hal ini bisa diwujudkan di Qt ?
Jawab: Tentu saja. Untuk menghasilkan button berukuran besar, gunakan gambar
(pixmap) yang ukuran lebih besar (Qt akan menyesuaikan ukuran toolbar secara
otomatis). Contoh program di atas memakai pixmap kecil, hanya 16x16 piksel. Bilamana
pixmapnya misalnya 24x24 piksel, Anda akan mendapatkan toolbar yang serupa dengan
dengan Netscape atau program-program lain. Tentang label pada toolbar, ini bisa
diaktifkan dari fungsi QMainWindow::setUsesTextLabel( bool enable ). Panggil dari
konstruktor window dengan enable diset ke TRUE. Mudah bukan ?

Tanya: Icon-icon yang digunakan pada contoh program QSimpleApp cukup menarik.
Bagaimana menghasilkan icon semacam ini ?
Jawab: Pada dasarnya, icon-icon ini "milik" KDE. Bila Anda menggunakan KDE 2,
maka file-file icon bisa dilihat di subdirektori share/icons/ dari direktori instalasi KDE
(misalnya untuk SuSE, ini berarti /opt/kde2). Untuk contoh QSimpleApp, saya
mengambil beberapa icon ukuran 16x16 locolor. Karena format aslinya adalah PNG,
dengan menggunakan GIMP, icon-icon ini dikonversi dulu ke X Pixmap (alias XPM) dan
dikumpulkan menjadi satu dalam sebuah file header.

Qt bukanlah penyedia widget semata. Qt lebih dari sekedar toolkit untuk mengkonstruksi
antarmuka grafis atau GUI. Kali ini akan dibahas bagaimana Qt memudahkan
penanganan struktur data. Seperti biasa, tersedia pula program contoh untuk melukiskan
secara lebih jelas bagaimana hal ini bisa diwujudkan.

Manipulasi String dengan QString

Dalam bahasa C dan C++, sebuah string direpresentasikan sebagai array dari char
dengan karakter 0 atau null sebagai pertanda akhir string. Yang semacam ini sering
kemudian disebut sebagai null-terminated string. Pustaka standar C juga menyediakan
sejumlah fungsi untuk melakukan manipulasi string, bisa dilihat di file header string.h.
Problem utama penggunaan string sebagai array char adalah keterbatasan dalam
fleksibilitas penanganan memori. Hal ini karena string sering dialokasikan secara
dinamik, sebagaimana array, sehingga membutuhkan pula proses dealokasi memori. Bila
tidak dilakukan dengan tepat, alokasi/dealokasi ini bisa menyebabkan si programer sakit
kepala mengingat kesalahan sedikit saja bisa berakibat fatal: segmentation fault karena
salah dealokasi atau boros penggunaan memori (memory leak) karena lupa melakukan
dealokasi. Belum lagi masalah dereferensi pointer yang harus dilakukan dengan hati-hati.
Masalah lain untuk string muncul ketika program yang dikembangkan harus berurusan
dengan karakter yang bukan latin, misalnya huruf-huruf Kanji dari Jepang. Mengingat
string adalah array dari char dan char hanya 8 bit, maksimal kombinasi karakter yang

Created By Muhammad Syahrizal 80


ditampung adalah 256 karakter. Hampir pada semua kasus, ke-256 karakter ini akan diisi
dengan karakter ASCII. Lantas, bagaimana dengan orang-orang Rusia atau Urdu yang
juga tidak mau ketinggalan bermain program komputer ? Bagaimana mereka harus
merepresentasikan semua huruf-huruf yang non-latin ?

Solusi dari masalah ini adalah penggunaan Unicode, yaitu sebuah standar untuk
menyimpang karakter atau string secara lebih baik sehingga sanggup menampung semua
aneka karakter dari semua bahasa-bahasa di dunia. Triknya sederhana: memperluas
kemungkinan kombinasi karakter dari 256 menjadi 65536 dengan mengubah representasi
satu karakter menjadi 16-bit (tidak lagi 8-bit). Lebih jauh tentang Unicode, berikut
pemetaan karakter-karakternya, bisa dilihat di www.unicode.org.
Sayang sekali Unicode belum diadopsi sebagai standar untuk digunakan di bahasa C
ataupun C++. Untuk mengatasi hal ini, Qt menyediakan kelas QString, sebuah kelas yang
dapat dipergunakan untuk menyimpan dan mengolah string dan sudah mendukung
Unicode. Kalau string adalah array dari char, maka QString adalah array dari QChar,
sebuah kelas yang mewakili satu karakter Unicode. Kelas QString ini juga dilengkapi
sekian puluh fungsi-fungsi yang sangat berfaedah untuk memanipulasi string dan
pastinya akan menjadi 'teman baik' seorang programmer (Tidak percaya ? Sembari
maupun setelah membaca tulisan ini silakan merujuk ke referensi Qt tentang QString,
mudah dipahami bahwa fungsionalitas yang disediakan QString memang lengkap dan
yang betul-betul dibutuhkan).
Bagaiamana membuat string dengan QString ? Mudah sekali. Bisa dilakukan misalnya
sebagai berikut:
QString s = "Hello"
atau:
QString s("Hi there")
Karena QString bisa melakukan konversi secara otomatis, maka beralih dari string (atau
char*) bisa dilakukan semudah:
char msg[] = "Guten Morgen !";
QString s = msg;
Sebaliknya, casting dari QString ke char* juga dimungkinkan. Lihat yang berikut ini.
QString s = "hi";
printf( "%s\n", (const char*) s );
ataupun:
cout << s;
Pun mengalihkan objek QString ke stream tidak akan menimbulkan masalah:
QString ask = "Who are you?";
cout << ask << endl;
Fungsi uint QString::length akan mengembalikan panjang string (mirip dengan
strlen). Sebagai contoh, bila str adalah "Linux", maka str.length() menghasilkan 5.
Fungsi bool QString::isNull() dan bool QString::isEmpty() digunakan untuk
memeriksa apakah string NULL dan apakah string tersebut kosong. Perhatikan di sini
bahwa empty != null. Yang dimaksud dengan empty string adalah string yang tidak berisi
apa-apa (length() akan menghasilkan 0). Sementara itu null string bisa dianalogikan
dengan NULL pada pointer. Terdapat juga fungsi statik QString::null yang akan
mengembalikan null string. Lazimnya, dua fungsi ini digunakan pada pemeriksaan
kondisi tertentu. Potongan kode berikut mengilustrasikannya:
// do nothing if null
if( s.isNull() ) return;
// empty or not ?
if( s.isEmpty() ) cout << "string is empty" << endl;
cout <<Your string is << s << endl;

Created By Muhammad Syahrizal 81


Catatan: pada kode di atas, alih-alih s.isNull(), bisa juga digunakan s ==
QString::null.

Bagaimana mencomot sebagian string ? Ada fungsi QString QString::left( uint len
), QString QString::right( uint len ), dan QString QString::mid( uint index,
uint len ) yang masing-masing akan menghasilkan sebuah string baru yang merupakan
bagian tertentu dari string yang dipanggil. Contoh berikut menunjukkan bagaimana hasil
pemanggilan ketiga fungsi ini:
QString s = "Linus Torvalds" ;
QString p = s.left( 4 ) ; // Linu
QString q = s.right( 3 ); // lds
QString r = s.mid( 6, 3 ); // Tor
Kalau begitu, sekarang bagaimana menggabungkan string ? Dibandingkan pustaka
standar C yang hanya menyediakan strcat, Qt memberikan fungsi QString&
QString::append( const QString& s ) dan QString& QString::prepend( const
QString& s ) yang akan membubuhkan string s berturut-turut ke akhir dan awal string.
QString name = "Maddog" ;
name.append( "Hall" ); // Maddog Hall
name.prepend( "John" ); // John Maddog Hall
Ada pula QString& QString::insert( uint index, const QString& s ) yang akan
menyisipkan string s pada posisi index. Lihat contoh ini:
QString jfk = "John Kennedy" ;
cout << jfk.insert( 5,"F. " ) << endl; // John F. Kennedy
Dokumentasi Qt yang rinci dan lengkap menerangkan lebih banyak lagi mengenai kelas
QString dan QChar ini.
Program pig.cpp di bawah ini mengilustrasikan penggunaan kelas QString. Yang
dilakukan program ini - lazim dikenal sebagai Pig Latin - adalah menerima sebuah kata
dan mencetak versi kebalikannya, yakni bila huruf-huruf pada kata tersebut ditulis dari
arah kanan ke kiri.

Berikut adalah listing programnya:


1: // pig.cpp - Pig Latin
2: #include <iostream.h>
3: #include <qstring.h>
4:
5: int main( int argc, char **argv )
6: {
7: if( argc < 2 ) return -1;
8:
9: QString name = argv[1];
10: QString rev;
11:
12: for(int i = name.length() - 1; i >= 0; i--)
13: rev += name[i];
14:
15: cout << rev << endl;
16:
17: return 0;
18: }
Listing 1: pig.cpp

Lakukan compile dengan perintah:


g++ -o pig pig.cpp -lqt -I/usr/lib/qt2/include -L/usr/lib/qt2/lib
Catatan: Tidak perlu Makefile karena programnya cukup sederhana. Sesuaikan
/usr/lib/qt2 dengan direktori instalasi Qt.
Sekarang, bila program ini dijalankan, misalnya dengan perintah ./pig Linux, maka

Created By Muhammad Syahrizal 82


hasilnya xuniL. Silakan mencobanya sendiri.
Sebagai latihan, program ini bisa dimodifikasi agar tidak hanya menerima parameter
pertama program saja. Dengan demikian, yang di-Pig-Latin bisa saja sebuah kalimat
utuh, bukan hanya satu kata.

Program pig.cpp juga mencontohkan bagaimana membuat aplikasi yang berbasis Qt,
tetapi tidak menggunakan GUI (sering juga disebut aplikasi console). Dapat dilihat
bahwa hal ini bisa diwujudkan dengan gampang, cukup dengan tidak menggunakan
kelas-kelas yang merupakan widget (seperti QApplication, QMainWindow, dan
lain-lain).

Kawan

Mungkin bagi sebagian pembaca program Pig Latin di atas tidak begitu berdaya pikat.
Karenanya marilah beranjak mengulas sebuah program contoh lainnya, yaitu sebuah
aplikasi kecil untuk mendata nama, alamat e-mail, dan nomor telfon, yang dibaptis
sebagai program Kawan.

Sedikit tentang berfungsinya program Kawan ini akan dijelaskan terlebih dahulu. Tujuan
program adalah menyajikan data, dalam hal ini datanya berasal dari sebuah file bernama
kawan.dat. Bisa dikatakan bahwa file ini akan bertindak sebagai basis data mini. Untuk
mudahnya, file kawan.dat ini merupakan file teks ASCII biasa yang bisa disunting di
sembarang editor. Tiap-tiap baris pada file ini akan menyimpan satu record. Karena
dibutuhkan tiga field, yaitu nama, alamat e-mail, dan nomor telfon, maka untuk
masing-masing baris, terdapat tiga string yang dipisahkan oleh karakter : (titik dua)
sebagai pembatas field.

Jika sekiranya, deskripsi di atas membingungkan, di bawah ini adalah contoh sebuah file
kawan.dat. File data ini juga yang digunakan untuk menghasilkan screenshot di atas.
Esther:funkfyflo00@hotmail.com:0175 6969224
Ailsa:ailsa_gini@hotmail.com:0160 98534128
Elin:elin77@web.de:0179 6761591
Lia:fidia17@yahoo.com:0162 4160266
Rochim:rochim_h@yahoo.de:0170 8459166
Nano:estananto@yahoo.de:0179 5024705
Koredianto:kore76@yahoo.com:0175 9265806
Nova:nuzera@yahoo.com:0179 5158845
Sindy:sdewiana@yahoo.com:0179 3684614

Listing 2. Contoh file kawan.dat

Lebih dari itu, program Kawan juga diinginkan punya fasilitas untuk mengedit,
menghapus, serta menambah data baru yang dapat diakses melalui menu program.
Secara fungsional dapat disebutkan bahwa minimal program Kawan ini harus bisa:
• mengambil data dari file
• menyimpan data ke file
• mendaftar dan menyajikan data
• menghapus sebuah record
• mengedit record
• menambah record baru
Mengambil data dari file bukan pekerjaan yang susah. Prosedurnya pun relatif sederhana:
buka file kawan.dat, baca baris per baris, untuk tiap barisnya pisahkan ketiga field,

Created By Muhammad Syahrizal 83


tambahkan sebagai record baru. Adapun penyimpanan data ke file adalah proses
kebalikannya: untuk tiap record buat sebuah string dan simpan sebagai satu baris ke file
data.

Untuk menyajikan data, digunakan widget yang bernama QListView. Tiap-tiap record
akan berupa satu QListViewItem untuk widget QListView ini. Pada screenshot yang
ditunjukkan sebelumnya, widget QListView adalah widget utama yang berada di tengah
window.

Guna mengimplementasikan program Kawan ini, masih digunakan pendekatan yang


sama sebagaimana telah dikupas di bagian pertama dan kedua seri tulisan ini. Akan
terdapat tiga buah source code, masing-masing untuk program utama (main.cpp),
definisi kelas Kawan (kawan.h), serta implementasi kelas Kawan (kawan.cpp). Juga
dibutuhkan sebuah Makefile untuk memudahkan proses kompilasi.

Di bawah ini adalah listing program untuk file kawan.h.


1: // kawan.h
2:
3: #ifndef __KAWAN_H
4: #define __KAWAN_H
5:
6: class QString;
7: class QListView;
8: class QListViewItem;
9: #include <qlist.h>
10: #include <qmainwindow.h>
11:
12: class Kawan: public QMainWindow
13: {
14: Q_OBJECT
15:
16: public:
17: Kawan();
18:
19: protected:
20: void initMenu();
21: void initToolbar();
22: void loadData();
23: void saveData();
24:
25: private slots:
26:
27: void slotEntryAdd();
28: void slotEntryEdit();
29: void slotEntryDelete();
30: void slotAbout();
31:
32: private:
33:
34: QListView *list;
35: QList<QListViewItem> entries;
36:
37: };
38:
39: #endif
Listing 3. kawan.h

File kawan.h hanya berisi definisi kelas Kawan. Tidak ada sesuatu yang istimewa di sini.

Created By Muhammad Syahrizal 84


Anda juga bisa melihat bahwa terdapat tiga slot bernama slotEntryAdd(),
slotEntryEdit(), dan slotEntryDelete() yang masing-masing digunakan untuk
menambah, mengedit, serta menghapus record. Sebagaimana sudah disebutkan bahwa
QListView digunakan untuk menyajikan daftar record, yang pada file header di atas
diletakkan dalam pointer list (lihat baris 34). Yang baru di sini adalah variabel bernama
entries yang merupakan sebuah objek dari kelas QList. Patut dijelaskan di sini bahwa
QList adalah sebuah template class yang berarti bahwa harus diberikan kelas yang akan
menjadi item dari QList tersebut. Untuk kasus ini, item tersebut adalah QListViewItem.

Bagaimana implementasi kelas Kawan ? Lihatlah terlebih dahulu file kawan.cpp berikut
ini:
1: // kawan.cpp - Simple contact manager
2:
3: #include <qapplication.h>
4: #include <qfile.h>
5: #include <qlistview.h>
6: #include <qmenubar.h>
7: #include <qmessagebox.h>
8: #include <qstatusbar.h>
9: #include <qtextstream.h>
10:
11: #include "kawan.moc"
12:
13: const char* datafile = "kawan.dat";
14:
15: Kawan::Kawan() : QMainWindow( 0, "Kawan", WDestructiveClose )
16: {
17: entries.setAutoDelete( TRUE );
18:
19: initMenu();
20:
21: list = new QListView( this );
22: list->addColumn( "Name" );
23: list->addColumn( "E-mail" );
24: list->addColumn( "Phone" );
25: list->setAllColumnsShowFocus( TRUE );
26: setCentralWidget( list );
27:
28: loadData();
29:
30: resize( 400, 250 );
31: }
32:
33: void Kawan::loadData()
34: {
35: QFile f( datafile );
36: if ( !f.open( IO_ReadOnly ) )
37: return;
38:
39: entries.clear();
40:
41: QTextStream stream( &f );
42: while ( !stream.eof() )
43: {
44: QStringList s = QStringList::split( ":", stream.readLine(),
TRUE );
45: QString name = s[0].stripWhiteSpace();
46: QString email = s[1].stripWhiteSpace();
47: QString phone = s[2].stripWhiteSpace();
48: QListViewItem* e = new QListViewItem( list, name, email, phone
);
49: entries.append( e );
50: }

Created By Muhammad Syahrizal 85


51:
52: f.close();
53:
54: statusBar()->message( QString("%1 entries").arg( entries.count()
), 2000 );
55: }
56:
57: void Kawan::saveData()
58: {
59: QFile f( datafile );
60: if ( !f.open( IO_WriteOnly ) )
61: return;
62:
63: QTextStream stream( &f );
64:
65: QListIterator<QListViewItem> it( entries );
66: for(; it.current(); ++it )
67: {
68: QListViewItem* e = it.current();
69: QString s = QString( "%1:%2:%3" ).arg( e->text(0) ).
70: arg( e->text(1) ).arg( e->text(2) );
71: stream << s << endl;
72: }
73:
74: f.close();
75: }
76:
77: void Kawan::initMenu()
78: {
79: QPopupMenu * entry = new QPopupMenu( this );
80: menuBar()->insertItem( "&Entry", entry );
81: entry->insertItem( "Add", this, SLOT( slotEntryAdd() ) );
82: entry->insertItem( "Delete", this, SLOT( slotEntryDelete() ) );
83: entry->insertItem( "Edit", this, SLOT( slotEntryEdit() ) );
84: entry->insertSeparator();
85: entry->insertItem( "Close", this, SLOT( close() ) );
86:
87: QPopupMenu * help = new QPopupMenu( this );
88: menuBar()->insertSeparator();
89: menuBar()->insertItem( "&Help", help );
90: help->insertItem( "&About...", this, SLOT( slotAbout()) );
91: }
92:
93: void Kawan::slotEntryAdd()
94: {
95: }
96:
97: void Kawan::slotEntryEdit()
98: {
99: }
100:
101: void Kawan::slotEntryDelete()
102: {
103: QListViewItem* e = list->currentItem();
104: if( e )
105: {
106: list->takeItem( e );
107: saveData();
108: statusBar()->message( "Deleted", 1000 );
109: }
110: }
111:
112: void Kawan::slotAbout()
113: {
114: QMessageBox::about( this, "Kawan",
115: "<b>Kawan 0.1</b>"
116: "<p>Simple contact manager</p>"
117: "<p>Programmed by Ariya Hidayat<br>"

Created By Muhammad Syahrizal 86


118: "ariya@infolinux.co.id</p>" );
119: }
Listing 4. kawan.cpp

Ada beberapa hal menarik untuk kelas Kawan ini.


Di awal sekali, bisa dilihat bahwa "kawan.dat" ditetapkan sebagai nama file data untuk
program ini.

Pada konstruktor kelas Kawan, bisa dilihat bagaimana inisialisasi list sebagai sebuah
widget QListView. QListView bisa menampung sekian kolom, masing-masing
ditambahkan dengan QListView::addColumn. Perhatikan pula terjadi AutoDelete pada
entries (yang merupakan QList). Dengan QList::setAutoDelete, bisa diatur apakah
AutoDelete akan diaktifkan atau tidak. Bila aktif, hal ini berarti apa saja yang
ditambahkan ke entries akan dihapus secara otomatik dari memori manakala entries juga
menjadi invalid.

Fungsi Kawan::loadData bertugas membaca record-record dari file data. Di sini


digunakan QFile untuk mengakses file (low-level) dan QTextStream untuk bekerja
dengan isi dari file tersebut (high-level). Mula-mula tiap baris dari file data diletakkan
dalam sebuah string dan kemudian dipisahkan berdasarkan karakter : (titik dua). Dengan
Qt, hal ini menjadi mudah karena tersedia QStringList yang mempunyai fungsi
QStringList::split (yang tidak asing dengan Perl atau Python bisa melihat
kesamaannya di sini). Sebetulnya QStringList tidak lain adalah list dari beberapa
QString. Dengan hanya sekitar 20 baris program, fungsionalitas untuk mengambil record
dari file data sudah terwujudkan.

Fungsi Kawan::saveData adalah kebalikan dari loadData, yaitu untuk menyimpan


record ke file data. Tidak lebih mudah dan juga tidak lebih sulit, fungsi saveData ini
cukup sederhana: proses record satu demi satu, untuk tiap recordnya susun sebuah string
yang kemudian ditulis ke file. Lagi-lagi akses ke file menggunakan QFile dan
QTextStream. Loop untuk membaca masing-masing item dalam variabel entries
dilakukan dengan iterator, yakni QListIterator. Pembaca yang paham dengan
penggunaan STL (Standard Template Library) tentunya tidak akan asing lagi dengan
konsep iterator ini. Ringkasnya, iterator ini adalah objek yang bisa digunakan untuk
bergerak mengakses entri-entri pada sebuah objek lain. Karena entries berasal dari
kelas QList, maka iterator yang digunakan adalah QListIterator.

Mengkomposisikan string di Qt jauh lebih gampang dibandingkan dengan C atau C++


biasa. Mengapa ? Hal ini tidak lain karena tersedianya QString::arg yang terbilang
powerful untuk urusan ini. Fungsi akan menghasilkan sebuah string baru (masing sebagai
QString tentunya) yang sama dengan format yang diberikan tetapi dengan mengganti %d
dengan argumen yang diberikan. Di sini d adalah sebuah integer. Fungsi arg hanya akan
mensubstitusi integer d yang terkecil. Dengan demikian, bila s berisi "Val %1", maka
s.arg( 0.707 ) akan menghasilkan " Val 0.707". Cermati juga bahwa dengan keindahan
polymorphism di C++, arg dapat menerima apa saja: integer, double, char, QString, dan
lain-lain.
Lazimnya, fungsi arg ini diatur secara seri (atau cascade) untuk menghasilkan sebuah
string yang terformat rapi. Ilustrasi kecil, perhatikan potongan kode di bawah:
QString name = "Joe";
double pi = 3.14;

Created By Muhammad Syahrizal 87


QString formatstr = "Name is %1 and PI is %2";
cout << formatstr.arg( name ).arg( pi ) << endl;
Hasilnya adalah:
Name is Joe and PI is 3.14
Di sini %1 akan digantikan dengan name dan %2 digantikan dengan pi. Alokasi dan
dealokasi memori diatur secara otomatis. Lebih cepat dan gampang dibandingkan
sprintf(), bukan ?
Kembali ke program Kawan, QString::arg dimanfaatkan untuk menghasilkan string
untuk menampung sebuah record sesuai dengan format file data kawan.h (baris 68-71).
Fungsi Kawan::initMenu akan mengkonstruksi menu untuk program contoh ini. Saat
sekarang, menu utamanya hanya dua: Entry dan Help. Untuk menu Entry, ada empat
submenu: Add, Delete, Edit, dan Close yang masing-masing dihubungkan dengan empat
slot berturut-turut: slotEntryAdd, slotEntryDelete, slotEntryEdit, dan close.
Kecuali yang terakhir, tiga yang pertama adalah slot yang khusus dimiliki Kawan.
Sementara itu, menu Help hanya berisi submenu About (terhubung ke slot slotAbout).
Sisa file adalah implementasi keempat slot yang baru saja disebutkan (slot close sudah
diwarisi dari QMainWindow). Perhatikan bahwa baik slotAdd dan slotEdit belum
berisi apa-apa, keduanya akan dibahas di bagian empat seri tulisan ini. Dus, program
Kawan ini sebenarnya juga kehilangan dua fungsionalitas: menambah dan menyunting
record.

Slot untuk menghapus record, Kawan::slotEntryDelete, relatif pendek. Slot ini


memanfaatkan fungsi QList::takeItem untuk menghapus sebuah item dari QList. Item
yang mana yang dihapus sendiri ditentukan dari QListView::currentItem. Sebuah
blok if diperlukan di sini karena QListView::currentItem bisa mengembalikan NULL
jika memang tidak ada item yang disorot oleh user. Setelah sebuah record dihapus hal ini
berarti data mengalami perubahan. Oleh karenanya saveData dipanggil untuk
menyimpan data yang baru ke file.

Sebetulnya program sekecil Kawan tidak membutuhkan About Box. Fungsi


Kawan::slotAbout sendiri sengaja ditambahkan untuk mengilustrasikan salah satu fitur
Qt, yaitu kemampuannya menampilkan rich-text. Yang dimaksud sebagai rich-text di sini
adalah teks yang tidak hanya sekedar susunan karakter biasa, tetapi lebih ke teks yang
bisa diformat, apakah itu bold, italics, dan sebagainya.
Bila diamati, terlihat bahwa QMessageBox::about dipanggil dengan string yang mirip
dengan kode-kode HTML. Mudah ditebak bahwa sebuah teks yang akan diformat
sebagai rich-text diatur dengan menempatkan tag-tag HTML di dalam teks tersebut.
Hanya ada dua tag yang digunakan di sini: yaitu <b> untuk menghasilkan cetak tebal
(bold) dan <p> untuk berganti baris (paragraph).

Kelas Kawan yang sudah lengkap didefinisikan dan diimplementasikan masih belum
cukup untuk membangun sebuah aplikasi Qt yang utuh. Dibutuhkan rutin utama yang
menghasilkan QApplication yang kemudian menggunakan objek dari kelas Kawan
sebagai window utama. Hal ini diwujudkan di file source code yang ketiga, yaitu
main.cpp. Adapun listing file tersebut adalah:
1: // main.cpp
2:
3: #include <qapplication.h>
4: #include "kawan.h"
5:
6: int main( int argc, char ** argv )

Created By Muhammad Syahrizal 88


7: {
8: QApplication a( argc, argv );
9:
10: Kawan *w = new Kawan();
11: w->show();
12:
13: a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
14:
15: return a.exec();
16: }
Listing 5. main.cpp

Untuk memudahkan proses kompilasi, digunakan Makefile berikut ini:


1: QTDIR = /usr/lib/qt2
2: QTLIB = $(QTDIR)/lib
3: QTINCLUDE = $(QTDIR)/include
4: QTMOC = $(QTDIR)/bin/moc
5:
6: TARGET = kawan
7: OBJECTS = kawan.o main.o
8: MOCS = kawan.moc
9:
10: CC = g++
11: CFLAGS = -Wall -O2
12: LIBS = -lqt
13:
14: $(TARGET): $(MOCS) $(OBJECTS)
15: $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) -L$(QTLIB)
-I$(QTINCLUDE)
16:
17: %.o: %.cpp
18: $(CC) $(CFLAGS) -I$(QTINCLUDE) -c $< -o $@
19:
20: %.moc: %.h
21: $(QTMOC) $< -o $@
22:
23: clean:
24: rm $(OBJECTS) $(TARGET) $(MOCS)
Listing 6. Makefile

Kalau Anda cukup teliti, bisa dilihat bahwa Makefile ini nyaris sama seperti yang
sudah-sudah (lihat bagian 1 dan 2 seri tulisan ini). Yang berbeda hanya baris 6, 7, dan 8
untuk menyesuaikan dengan nama programnya. Sekedar mengingatkan lagi, jangan lupa
menyesuaikan QTDIR dengan direktori instalasi Qt pada sistem Anda.
Sekarang proses kompilasi bisa dilakukan dengan mudah, cukup jalankan perintah make.
Jika tidak ada sesuatu yang salah, maka program kawan sudah siap untuk digunakan.
Jangan lupa juga untuk membuat file kawan.dat yang dibutuhkan untuk program ini.
Bonus untuk program Kawan, daftar yang disajikan bisa disortir dengan mudah. Tidak
lain tidak bukan yakni dengan mengklik pada judul kolomnya, apakah itu untuk Name,
E-mail, maupun Phone. Anda bisa mencobanya sendiri.
Sebagai latihan, Anda bisa menambahkan toolbar untuk program Kawan ini. Tentunya
hal ini tidak terlalu susah mengingat hal-hal yang berkenaan dengan toolbar sudah
dikupas di bagian kedua seri tulisan ini. Untuk icon (atau pixmap) pada toolbar ini, Anda
bisa mengambilnya dari mana saja, sepanjang ukurannya tepat.

Tanya Jawab

Tanya: Bagaimana menghilangkan spasi kosong yang tidak perlu pada string ?
Jawab: Gunakan fungsi QString QString::stripWhiteSpace(). Misalnya QString s

Created By Muhammad Syahrizal 89


= " some text ", maka s.stringWhiteSpace() menghasilkan string baru "some text".

Tanya: Saya biasa memformat string dengan sprintf(). Dengan QString, bagaimana
hal ini bisa dilakukan ?
Jawab: Untunglah sprintf() juga merupakan metoda dalam kelas QString. Hal ini
berarti mirip dengan sprintf() biasa, Anda dapat melakukannya ke dalam sebuah string
dari QString. Sebagai ilustrasi, coba periksa hasil dari QString s; s.sprintf( "%g",
M_PI ); (jangan lupa meng-include-kan math.h). Alternatif lain adalah menggunakan
metoda arg(), sebagaimana ditunjukkan pada program contoh.

Tanya: Untuk kelas-kelas yang saya buat sendiri dan tidak berasal dari Qt, apakah harus
digunakan QString untuk menangani string ? Bukankan char* saja sudah cukup ?
Jawab: Bila Anda yakin tidak akan menggunakan Unicode, hal ini bukan masalah.
Namun demikian, mengingat begitu mudahnya operasi string dilakukan dengan kelas
QString, tidak ada salahnya untuk menggunakan kelas QString. Anda akan diuntungkan
juga karena tidak perlu melacak bug yang diakibatkan kesalahan alokasi dan dealokasi
memori atau dereferensi pointer yang tidak tepat.

Tanya: Operasi manipulasi karakter dan string dengan menggunakan kelas QString
bukankan tidak efisien dan menurunkan kecepatan program ?
Jawab: Kelas QString dirancang agar tidak melakukan copy yang tidak perlu, yaitu
dengan menerapkan shallow copy. Hal ini berarti dua string yang sama tidak akan
memiliki dua instance yang berbeda. Secara tidak langsung, hal ini mengurangi sekali
ketidakefisienan QString sehingga tidak mempunyai pengaruh yang signifikan terhadap
kecepatan eksekusi program. Bila dibandingkan dengan fasilitas yang diberikan,
menggunakan QString merupakan kompromi yang baik antara kemudahan dan efisiensi.

Tanya: Jika saya menggunakan QList, sering muncul masalah Segmentation fault.
Jawab: Kemungkinan besar Anda mencoba menghapus objek yang sudah tidak valid
lagi, misalnya dengan operator delete. Bila objek ini telah disisipkan ke dalam sebuah
QList dan Anda sudah mengaktifkan setAutoDelete( TRUE ), maka tidak perlu lagi
menghapus objek ini secara manual. AutoDelete berarti bahwa objek yang terdapat pada
sebuah QList akan dihapus bersamaan ketika QList tersebut juga menghilang dari
memory.
Tanya: Dengan QList::append, sebuah item disisipkan di akhir. Bagaimana untuk
menyisipkannya di awal sehingga item ini menjadi item yang pertama dalam sebuah
QList ?
Jawab: Mudah saja. Gunakan QList::prepend.

Tanya: Apakah QList dan QListView berhubungan ?


Jawab: Tidak. QList adalah kelas yang digunakan untuk menampung sejumlah entri,
mirip seperti sebuah list biasa. QListView adalah widget yang lumrahnya digunakan
untuk mendaftar sejumlah data. Keduanya tidak saling tergantung dan bisa digunakan
terpisah.

Tanya: Saya perhatikan QList ini serupa dengan kelas-kelas yang ada pada STL
(Standard Template Library). Adakah kelas Qt yang lain yang mirip penggunannya
dengan STL ?
Jawab: Ada banyak. Selain QList terdapat juga QMap, QArray, QDict, QStack, dan

Created By Muhammad Syahrizal 90


lain-lain. Silakan merujuk ke manual Qt untuk lebih jelasnya. Kelas-kelas Qt yang ini
seperti memang serupa dengan STL sehingga sering dinamakan juga sebagai QTL (Qt
Template Library).

Tanya: Jika saya hitung-hitung, untuk menghasilkan program semacam Kawan


dibutuhkan sekitar 180 kode C++ (mencakup semua file source code dan juga
Makefile-nya). Tidakkah ini terlalu banyak untuk program sesederhana itu ?
Jawab: Tidak juga. Anda tentu bisa mengimplementasikan fungsionalitasnya yang sama
dan tidak menggunakan Qt, tetapi dengan library lainnya semisal Xlib, Motif, maupun
GTK. Bisa dijamin bahwa program yang menggunakan Qt (sebagaimana Kawan di atas)
lebih pendek, ringkas, dan mudah dipahami.

Tanya: Saya tertarik dengan screenshot program Kawan. Sepertinya windownya cukup
unik. Bagaimana menghasilkan window semacam ini ?
Jawab: Yang ditampilkan sebagai screenshot sebetulnya adalah dekorasi IceWM yang
bernama MenschMaschine. Jadi, tidak ada yang aneh dengan programnya. Anda tinggal
menggunakan IceWM sebagai window manager, mengaktifkan MenschMaschine, dan
semua program akan memiliki dekorasi window yang dimaksud. Cara lain (yaitu yang
dilakukan untuk menghasilkan screenshot di atas) adalah dengan menggunakan dekorasi
IceWM ini di KDE 2.2.

Programer yang kawakan mestilah sudah paham bagaimana rumitnya mengatur tata letak
dari elemen-elemen user-interface. Untuk mengatasi hal ini, Qt menggunakan
pendekatan seperti yang diterapkan di Java dalam penataan widget-widget, yakni dengan
sebuah kelas khusus QLayout untuk melakukan layout secara mudah dan fleksibel.

Tata Letak: Pengaturan Geometri Widget

Sebelum melihat bagaimana user interface dapat dibangun dengan kelas-kelas widget
yang disediakan oleh Qt, ada baiknya disentuh sedikit mengenai geometry management.
Bagi yang pernah memprogram di Windows, misalnya dengan Visual Basic atau Delphi,
jelas bahwa menyusun elemen user interface, seperti button, checkbox, list, dan lain-lain
dilakukan dengan meletakkan elemen- elemen tersebut pada posisi tertentu. Namun
demikian, buat yang sedikit punya pengalaman dengan Motif ataupun Java,
elemen-elemen user interface tidak disusun pada posisi yang tepat. Hal ini berarti lokasi
relatif sebuah button dapat berubah, manakala window di mana button tersebut berada
mengalami perubahan ukuran.
Bagaimana melakukan ini di Qt? Beruntunglah bahwa Qt menyediakan kelas QLayout
yang memang berguna untuk menata widget-widget dengan cara yang sederhana tetapi
cukup powerful. Pada prakteknya, yang dipakai bukanlah QLayout tetapi kelas turunan
dari QLayout, yaitu QGridLayout dan QBoxLayout. Yang belakangan disebut malahan
punya turunan lagi: QHBoxLayout dan QVBoxLayout. Semuanya akan dikupas satu per
satu di bawah ini.
Kelas QHBoxLayout dipergunakan untuk menyusun widget-widget secara mendatar atau
horizontal, Fragmen kode yang digunakan untuk menghasilkan tampilan di atas ditunjukkan
di bawah ini:
QBoxLayout *layout = new QHBoxLayout( this );
layout->setMargin( 10 );
layout->setSpacing( 3 );

Created By Muhammad Syahrizal 91


layout->addWidget( new QPushButton ( "Mars", this ) );
layout->addWidget( new QPushButton ( "Jupiter", this ) );
layout->addWidget( new QPushButton ( "Saturnus", this ) );
layout->addWidget( new QPushButton ( "Uranus", this ) );
layout->addWidget( new QPushButton ( "Neptunus", this ) );

Jadi, bisa dilihat bahwa tekniknya adalah membuat objek dari QHBoxLayout dan
kemudian menambahkan widget-widgetnya ke dalam objek ini dengan menggunakan
fungsi QHBoxLayout::addWidget(). Widget yang pertama kali dimasukkan ke
QHBoxLayout akan berada di posisi paling kiri (lihat button Mars pada contoh di atas).
Dua fungsi yang tercantum di potongan kode di atas adalah QHBoxLayout:setMargin()
dan QHBoxLayout::setSpacing(). Fungsi yang pertama adalah untuk menentukan
margin, yaitu jumlah pixel yang mengelilingi objek layout ini. Dalam contoh kasus ini,
Anda bisa membayangkan bahwa sekelompok button ini - dari Mars hingga Neptunus
dikurung oleh pagar yang tidak nampak, yang berukuran 10 pixel. Adapun setSpacing
menentukan ruang kosong (juga dalam pixel) sebagai jarak antara satu widget dengan
widget lainnya. Jelas bahwa baik margin maupun spacing harus diatur agar menghasilkan
susunan yang baik.

Menghasilkan yang seperti screenshot di atas masih mirip dengan contoh sebelumnya,
perhatikan yang berikut ini:
QBoxLayout *layout = new QVBoxLayout( this );
layout->setMargin( 10 );
layout->setSpacing( 3 );
layout->addWidget( new QPushButton ( "Jules Verne", this ) );
layout->addWidget( new QPushButton ( "Victor Hugo", this ) );
layout->addWidget( new QPushButton ( "William Shakespeare", this ) );
Sama saja, bukan ? Hanya di sini digunakan QVBoxLayout, bukan QHBoxLayout.
Widget pertama dari QVBoxLayout akan diletakkan paling atas, sebagaimana yang
terjadi dengan Jules Verne.
Kelas layout yang terakhir, yaitu QGridLayout dipergunakan ketika widget-widgetnya
seakan-akan disusun dalam sebuah matriks atau tabel. Karenanya, juga harus ditentukan
terlebih dahulu jumlah baris dan jumlah kolom dari grid yang harus dihasilkan.
QGridLayout *layout = new QGridLayout( this, 2, 2 );
layout->setMargin( 10 );
layout->setSpacing( 3 );
layout->addWidget( new QPushButton ( "Harry", this ), 0, 0 );
layout->addWidget( new QPushButton ( "Ron", this ), 0, 1 );
layout->addWidget( new QPushButton ( "Hermione", this ), 1, 0 );
layout->addWidget( new QPushButton ( "Hagrid", this ), 1, 1 );
Sebagai catatan, lepas dari jenis layout mana yang akan digunakan, file header yang
di-include-kan cukup qlayout.h. Jadi tidak ada file header terpisah untuk
masing-masing kelas penting seperti lumrahnya tradisi Qt.

Program Kawan: Versi 0.2


Sesuai yang dijanjikan di bagian ketiga seri tulisan ini, tibalah masanya untuk membahas
mengenai program Kawan versi yang lebih baru - sebut saja versi 0.2. Seperti bisa dilihat
di bagian ketiga, program Kawan versi sebelumnya masih belum mempunyai fasilitas
menambah dan mengedit data. Kedua hal inilah yang akan dilengkapi sekarang.
Per desain, penambahan maupun penyuntingan data akan menyebabkan sebuah kotak
dialog baru ditampilkan ke user, sudah beserta field-field yang akan ditambahkan atau
diedit oleh user tersebut. Karenanya, akan dibutuhkan dua buah kelas baru: EditDialog
dan AddDialog. Bisa dilihat bahwa kedua dialog ini akan mirip secara tampilan dan

Created By Muhammad Syahrizal 92


hanya berbeda sedikit secara fungsi. Oleh karenanya, diputuskan untuk membuat kelas
AddDialog sebagai turunan dari kelas EditDialog. Kedua-duanya akan diletakkan di
sebuah file terpisah dan tidak digabungkan ke program utama Kawan. Dengan demikian,
walhasil akan ada dua tambahan file baru: edit.h untuk deklarasi EditDialog dan
AddDialog serta edit.cpp untuk implementasinya.
Mula-mula, marilah kita lihat file header kawan.h yang sama sekali tidak mengalami
perubahan dibandingkan versi 0.1.
1: // kawan.h
2:
3: #ifndef __KAWAN_H
4: #define __KAWAN_H
5:
6: class QString;
7: class QListView;
8: class QListViewItem;
9: #include <qlist.h>
10: #include <qmainwindow.h>
11:
12: class Kawan: public QMainWindow
13: {
14: Q_OBJECT
15:
16: public:
17: Kawan();
18:
19: protected:
20: void initMenu();
21: void initToolbar();
22: void loadData();
23: void saveData();
24:
25: private slots:
26:
27: void slotEntryAdd();
28: void slotEntryEdit();
29: void slotEntryDelete();
30: void slotAbout();
31:
32: private:
33:
34: QListView *list;
35: QList<QListViewItem> entries;
36:
37: };
38:
39: #endif
Listing 1. kawan.h

Bagaimanakah membuat sebuah dialog untuk digunakan sebagai EditDialog dan


AddDialog ? Dengan kekayaan API dari Qt serta kemudahan penggunakan kelas di C++,
maka proses pembangunan sebuah kotak dialog cukup sederhana: turunkan saja dari
kelas QDialog. Untuk jelasnya, perhatikan listing file edit.h yang mendeklarasikan
kelas EditDialog berikut ini.
1: // edit.h
2:
3: #ifndef __EDIT_H
4: #define __EDIT_H
5:
6: #include <qdialog.h>
7: class QLineEdit;
8: class QPushButton;
9: class QString;

Created By Muhammad Syahrizal 93


10:
11: class EditDialog: public QDialog
12: {
13: Q_OBJECT
14:
15: public:
16: EditDialog( QWidget* parent, const QString& _name,
17: const QString& _email, const QString& _phone );
18: private:
19: QPushButton *button_dismiss;
20: QPushButton *button_cancel;
21: QLineEdit *edit_name;
22: QLineEdit *edit_email;
23: QLineEdit *edit_phone;
24:
25: private slots:
26: void slotDismiss();
27: void slotCancel();
28:
29: public:
30: QString name;
31: QString email;
32: QString phone;
33: };
34:
35: class AddDialog: public EditDialog
36: {
37: public:
38: AddDialog( QWidget* parent );
39: };
40:
41: #endif
Listing 2. edit.h

Juga bisa disaksikan, seperti sudah disinggung beberapa menit yang lalu, kelas
AddDialog yang digunakan untuk menambah entri baru akan dijadikan kelas turunan dari
EditDialog.
Rancangan dialognya sendiri adalah bahwa terdapat tiga buah kotak isian,
masing-masing untuk nama, e-mail, serta nomor telfon. Ini bersesuaian dengan field-field
yang ada di program Kawan. Terdapat pula dua buat tombol perintah, masing-masing
untuk mengaktifkan penyuntingan (Dismiss) dan membatalkannya (Cancel). Jenis widget
yang akan dimanfaatkan hanya dua, yaitu QPushButton dan QLineEdit. Kalau Anda
cermati, ada dua buah slot pada EditDialog yakni slotDismiss dan slotCancel.
Masing-masing akan terhubung ke tombol perintah (button) yang bersesuaian.
Berikut bisa diperhatikan implementasi EditDialog dan AddDialog pada file edit.cpp.
1: // edit.cpp
2:
3: #include <qdialog.h>
4: #include <qlabel.h>
5: #include <qlayout.h>
6: #include <qlineedit.h>
7: #include <qpushbutton.h>
8:
9: #include "edit.moc"
10:
11: EditDialog::EditDialog( QWidget* parent, const QString& _name,
12: const QString& _email, const QString& _phone ):
13: QDialog( parent, "EditDialog", TRUE )
14: {
15: QBoxLayout *topLayout = new QVBoxLayout( this, 3 );
16:
17: setCaption( "Edit" );
18:

Created By Muhammad Syahrizal 94


19: // edit fields
20: edit_name = new QLineEdit( this );
21: edit_name->setText( _name );
22: edit_email = new QLineEdit( this );
23: edit_email->setText( _email );
24: edit_phone = new QLineEdit( this );
25: edit_phone->setText( _phone );
26:
27: // arrange the fields
28: QGridLayout *grid = new QGridLayout( topLayout, 3, 3 );
29: grid->setSpacing( 4 );
30: grid->setMargin( 5 );
31: grid->addWidget( new QLabel( "Name", this ), 0, 0 );
32: grid->addWidget( new QLabel( "E-mail", this ), 1, 0 );
33: grid->addWidget( new QLabel( "Phone", this ), 2, 0 );
34: grid->addWidget( edit_name, 0, 1 );
35: grid->addWidget( edit_email, 1, 1 );
36: grid->addWidget( edit_phone, 2, 1 );
37:
38: // flexible spacer
39: QWidget *spacer = new QWidget( this );
40: spacer->setSizePolicy ( QSizePolicy( QSizePolicy::Expanding,
41: QSizePolicy::Expanding ));
42: topLayout->addWidget( spacer );
43:
44: // command buttons
45: button_dismiss = new QPushButton( "Dismiss", this );
46: connect( button_dismiss, SIGNAL( clicked() ),
47: this, SLOT( slotDismiss() ) );
48: button_cancel = new QPushButton( "Cancel", this );
49: connect( button_cancel, SIGNAL( clicked() ),
50: this, SLOT( slotCancel() ) );
51:
52: // arrange the buttons
53: QBoxLayout *buttons = new QHBoxLayout( topLayout, 2 );
54: buttons->addWidget( button_dismiss );
55: buttons->addWidget( button_cancel );
56:
57: setMinimumWidth( 250 );
58: }
59:
60: void EditDialog::slotDismiss()
61: {
62: name = edit_name->text();
63: email = edit_email->text();
64: phone = edit_phone->text();
65: done ( 1 );
66: }
67:
68: void EditDialog::slotCancel()
69: {
70: done ( 0 );
71: }
72:
73: AddDialog::AddDialog( QWidget* parent ):
74: EditDialog( parent, QString::null, QString::null, QString::null )
75: {
76: setCaption( "Add" );
77: }
Listing 3. edit.cpp

Widget-widget untuk EditDialog diatur dengan menggunakan layout yang ditata vertikal,
jadi memanfaatkan QVBoxLayout. Namun demikian, untuk menghasilkan penataan
kotak isian nama, e-mail, dan nomor telefon, maka disusunlah layout lain (kali ini dengan
QGridLayout) di dalam baris pertama layout yang utama (disebut sebagai topLayout

Created By Muhammad Syahrizal 95


pada program). Hal yang demikian sering dinamakan sebagai layout bertingkat. Bila
Anda cukup teliti, layout bertingkat juga digunakan sekali lagi untuk mengatur peletakan
tombol Dismiss dan Cancel.
Terlihat bahwa baik slotDismiss maupun slotCancel memanggil fungsi
QDialog::done(). Argumen yang diberikan ke fungsi ini akan menjadi nilai kembali
(return value) dari kotak dialog tersebut. Lumrahnya, nilai ini dipergunakan kelak di
program utama untuk memeriksa apakah user menekan Dismiss atau membatalkan
semuanya karena menekan Cancel.
Pada konstruktor EditDialog terdapat tiga buah string yang dikirimkan yang akan
berfungsi sebagai nilai awal untuk kotak isian, masing-masing untuk nama, e-mail, dan
nomor telfon. EditDialog juga mempunyai variabel anggota (yang bersifat public) untuk
menampung hasil penyuntingan dari user.
Bagaimana untuk AddDialog ? Sangat sederhana, AddDialog hanyalah EditDialog
dengan nilai isian awal untuk nama, e-mail, dan nomor telfon sama dengan string null.
Yang perlu diubah hanya title dari dialog ini (bukan lagi Edit, tetapi menjadi Add).
Begitu kotak dialog untuk mengedit atau menambah data sudah tersedia, kini saatnya
memodifikasi program utama kawan.cpp agar dapat menggunakan kotak dialog tersebut.
1: // kawan.cpp - Simple contact manager
2:
3: #include <qapplication.h>
4: #include <qfile.h>
5: #include <qlistview.h>
6: #include <qmenubar.h>
7: #include <qmessagebox.h>
8: #include <qstatusbar.h>
9: #include <qtextstream.h>
10:
11: #include "edit.h"
12:
13: #include "kawan.moc"
14:
15: const char* datafile = "kawan.dat";
16:
17: Kawan::Kawan() : QMainWindow( 0, "Kawan", WDestructiveClose )
18: {
19: entries.setAutoDelete( TRUE );
20:
21: initMenu();
22:
23: list = new QListView( this );
24: list->addColumn( "Name" );
25: list->addColumn( "E-mail" );
26: list->addColumn( "Phone" );
27: list->setAllColumnsShowFocus( TRUE );
28: setCentralWidget( list );
29:
30: loadData();
31:
32: resize( 400, 250 );
33: }
34:
35: void Kawan::loadData()
36: {
37: QFile f( datafile );
38: if ( !f.open( IO_ReadOnly ) )
39: return;
40:
41: entries.clear();
42:
43: QTextStream stream( &f );
44: while ( !stream.eof() )

Created By Muhammad Syahrizal 96


45: {
46: QStringList s = QStringList::split( ":", stream.readLine(),
TRUE );
47: QString name = s[0].stripWhiteSpace();
48: QString email = s[1].stripWhiteSpace();
49: QString phone = s[2].stripWhiteSpace();
50: if( !name.isEmpty() )
51: {
52: QListViewItem* e = new QListViewItem( list, name, email, phone
);
53: entries.append( e );
54: }
55: }
56:
57: f.close();
58:
59: statusBar()->message( QString("%1 entries").arg( entries.count()
), 2000 );
60: }
61:
62: void Kawan::saveData()
63: {
64: QFile f( datafile );
65: if ( !f.open( IO_WriteOnly ) )
66: return;
67:
68: QTextStream stream( &f );
69:
70: QListIterator<QListViewItem> it( entries );
71: for(; it.current(); ++it )
72: {
73: QListViewItem* e = it.current();
74: QString s = QString( "%1:%2:%3" ).arg( e->text(0) ).
75: arg( e->text(1) ).arg( e->text(2) );
76: if( !e->text(0).isEmpty() )
77: stream << s << endl;
78: }
79:
80: f.close();
81: }
82:
83: void Kawan::initMenu()
84: {
85: QPopupMenu * entry = new QPopupMenu( this );
86: menuBar()->insertItem( "&Entry", entry );
87: entry->insertItem( "Add", this, SLOT( slotEntryAdd() ) );
88: entry->insertItem( "Delete", this, SLOT( slotEntryDelete() ) );
89: entry->insertItem( "Edit", this, SLOT( slotEntryEdit() ) );
90: entry->insertSeparator();
91: entry->insertItem( "Close", this, SLOT( close() ) );
92:
93: QPopupMenu * help = new QPopupMenu( this );
94: menuBar()->insertSeparator();
95: menuBar()->insertItem( "&Help", help );
96: help->insertItem( "&About...", this, SLOT( slotAbout()) );
97: }
98:
99: void Kawan::slotEntryAdd()
100: {
101: AddDialog *d = new AddDialog( this );
102: if( d->exec() )
103: {
104: QListViewItem* e = new QListViewItem( list, d->name,
105: d->email, d->phone );
106: entries.append( e );
107: saveData();
108: statusBar()->message( "Added", 1000 );
109: }

Created By Muhammad Syahrizal 97


110: delete d;
111: }
112:
113: void Kawan::slotEntryEdit()
114: {
115: QListViewItem* e = list->currentItem();
116:
117: if( e )
118: {
119: EditDialog *d = new EditDialog( this, e->text(0),
120: e->text(1), e->text(2) );
121: if ( d->exec() )
122: {
123: e->setText( 0, d->name );
124: e->setText( 1, d->email );
125: e->setText( 2, d->phone );
126: saveData();
127: statusBar()->message( "Modified", 1000 );
128: }
129: delete d;
130: }
131: }
132:
133: void Kawan::slotEntryDelete()
134: {
135: QListViewItem* e = list->currentItem();
136: if( e )
137: {
138: list->takeItem( e );
139: saveData();
140: statusBar()->message( "Deleted", 1000 );
141: }
142: }
143:
144: void Kawan::slotAbout()
145: {
146: QMessageBox::about( this, "Kawan",
147: "<b>Kawan 0.2</b>"
148: "<p>Simple contact manager</p>"
149: "<p>Programmed by Ariya Hidayat<br>"
150: "ariya@infolinux.co.id</p>" );
151: }
Listing 4. kawan.cpp

Dari listing kawan.cpp di atas, terdapat perubahan berarti dari slotEntryAdd dan
slotEntryEdit. Keduanya tidak lagi kosong tetapi sudah berisi perintah-perintah.
Prinsipnya sederhana: buat dialognya (entah dengan EditDialog atau AddDialog) dan
panggil fungsi QDialog:exec(). Karena fungsi ini akan menghasilkan nilai kembalian
tertentu, sementara pada implementasi EditDialog dan AddDialog nilai kembalian ini
diatur sama dengan non-zero bila tombol Dismiss diaktifkan, maka dapat diketahui
dengan mudah apakah Dismiss atau Cancel yang dipilih user. Selanjutnya, jika memang
bukan Cancel, informasi field nama, e-mail, dan nomor telfon akan diambil dari kotak
dialog tersebut. Untuk slotEntryEdit field-field yang baru akan menggantikan isi field
yang lama. Untuk slotEntryAdd, field-field ini akan dijadikan satu entri data yang baru.
Tidak terlalu susah, bukan ?

Patut juga dicatat, fungsi saveData segera dipanggil setelah terjadi perubahan data
dengan tujuan agar data-data yang baru langsung tersimpan ke file kawan.dat.
Bila dibandingkan dengan versi 0.1, pada fungsi saveData dan loadData ada
perombakan kecil, yaitu pengabaian entri data yang isinya hanya null-string. Catatan:

Created By Muhammad Syahrizal 98


sebetulnya ini adalah bug kecil yang baru ditemukan penulis segera setelah tulisan naik
cetak.
Program utama main.cpp berikut ini juga adalah file yang tidak mengalami perubahan
apa-apa dibandingkan versi 0.1-nya.
1: // main.cpp
2:
3: #include <qapplication.h>
4: #include "kawan.h"
5:
6: int main( int argc, char ** argv )
7: {
8: QApplication a( argc, argv );
9:
10: Kawan *w = new Kawan();
11: w->show();
12:
13: a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
14:
15: return a.exec();
16: }
17:
Listing 5. main.cpp

Untuk melakukan kompilasi program, digunakan Makefile berikut ini. Lagi-lagi tidak
ada perubahan berarti pada Makefile ini kecuali penambahan edit.moc dan edit.o.
1: QTDIR = /usr/lib/qt2
2: QTLIB = $(QTDIR)/lib
3: QTINCLUDE = $(QTDIR)/include
4: QTMOC = $(QTDIR)/bin/moc
5:
6: TARGET = kawan
7: OBJECTS = kawan.o edit.o main.o
8: MOCS = kawan.moc edit.moc
9:
10: CC = g++
11: CFLAGS = -Wall -O2
12: LIBS = -lqt
13:
14: $(TARGET): $(MOCS) $(OBJECTS)
15: $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) -L$(QTLIB)
-I$(QTINCLUDE)
16:
17: %.o: %.cpp
18: $(CC) $(CFLAGS) -I$(QTINCLUDE) -c $< -o $@
19:
20: %.moc: %.h
21: $(QTMOC) $< -o $@
22:
23: clean:
24: rm $(OBJECTS) $(TARGET) $(MOCS)
25:
26:
27:
Listing 6. Makefile

Jika Anda sudah sukses melakukan kompilasi dan menghasilkan file executable kawan,
maka program baru ini siap untuk digunakan. Begitu Anda jalankan, tampilan awalnya
tidak berbeda sama sekali dengan versi sebelumnya. Cobalah aktifkan About dari menu
Help, kotak dialog About yang tampil akan menunjukkan bahwa progam Kawan ini
sekarang sudah bernomor versi 0.2.

Created By Muhammad Syahrizal 99


Mengedit data bisa dilakukan dengan menyorot data yang diinginkan dan memilih Edit
dari menu Entry. Adapun tampilan dari kotak dialog Edit ini bisa dilihat berikut ini.
Begitu field-fieldnya sudah dimodifikasi dan Dismiss diaktifkan, maka bisa dilihat bahwa
daftar yang ada sudah menyajikan perubahan yang baru saja dibuat oleh user.
Nah, kini fungsi program Kawan sebagai contact manager sudah lengkap. Sebagai
latihan, Anda bisa memodifikasi program ini agar tidak hanya menyimpan nama, e-mail,
dan nomor telfon, tetapi juga misalnya alamat, pekerjaan, tanggal lahir, dan sebagainya.

Latihan: Melayout Gallery

Masih ingatkan Anda akan program Gallery yang pernah disajikan sebagai contoh di seri
pertama tulisan ini ? Bila Anda perhatikan dengan teliti, widget-widget program Gallery
ini sama sekali tidak dilayout, melainkan hanya diletakkan begitu saja, sudah ditentukan
di posisi pixel mana dia akan berada.

Setelah membahas tuntas mengenai aneka ragam penggunaan QLayout, sebagai latihan
maka Anda bisa merombak program Gallery tersebut supaya kini tertata dengan baik
(atau bisa dikatakan sudah merujuk ke konsep geometry-management).
Sekedar petunjuk, widget-widget ini bisa disusun secara vertikal sebagai 6 baris. Khusus
untuk baris pertama, kedua, dan terakhir, maka bisa dilakukan layout bertingkat untuk
meletakkan label, edit box, dan button dengan baik.

Bonus: Dari Source Code ke Kode HTML

Pernah ada yang bertanya, bagaimana saya menyiapkan naskah untuk tulisan ini ? Nah,
sebagaimana kebiasaan saya pribadi, tulisan ini disusun dalam format HTML dengan
menggunakan Emacs sebagai penyunting teksnya. Tidak ada yang aneh dalam hal ini
kecuali mungkin sedikit hal unik mengenai penyisipan source code dari file-file yang
dibahas. Untuk alasan keterbacaan, nomor baris harus dibubuhkan pada tiap-tiap baris
dalam file source code, ini membuat file tersebut tidak bisa disisipkan begitu saja ke
Emacs. Trik yang elegan adalah membuat kode-kode Lisp untuk melakukan hal ini secara
otomatik. Akan tetapi, karena tulisan ini bercerita tentang pemrograman Qt/KDE, tidak
ada salahnya menyusun program kecil untuk kebutuhan ini yang kemudian dinamakan
sebagai source2html.
1: // source2html.cpp
2:
3: #include <iostream.h>
4: #include <qfile.h>
5: #include <qregexp.h>
6: #include <qstring.h>
7: #include <qtextstream.h>
8:
9: int main( int argc, char **argv )
10: {
11: if( argc < 2 ) return -1;
12:
13: QString filename = argv[1];
14:
15: QFile f( filename );
16: if ( !f.open( IO_ReadOnly ) )
17: return -1;
18:
19: cout << "<html><head><title>" << filename << "</title></head>"
<< endl;

Created By Muhammad Syahrizal 100


20: cout << "<body>" << endl;
21: cout << "<pre>"<< endl;
22:
23: QTextStream t(&f);
24: int i = 1;
25: while ( !t.eof() )
26: {
27: QString s = t.readLine();
28: s.replace( QRegExp("&"), "&amp;" );
29: s.replace( QRegExp("<"), "&lt;" );
30: s.replace( QRegExp(">"), "&gt;" );
31: cout << QString("%1: %2").arg( i, 3 ).arg( s ) << endl;
32: i++;
33: }
34: f.close();
35:
36: cout << "</pre>"<< endl;
37: cout << "</body>"<< endl;
38: cout << "</html>"<< endl;
39:
40: return 0;
41: }
Listing 7. source2html.cpp

Tidak ada yang rumit dari program di atas. Prinsip kerjanya sederhana: buka file input,
baca baris demi baris, cetak kembali dengan nomor baris. Mudah bukan ? Oh ya, baris
28-30 diperlukan karena karakter khusus seperti &, <, dan > harus dikodekan sebagai
&amp;, &lt;, dan &gt.
Karena program ini kecil dan hanya satu file saja, kompilasi bisa dilakukan semudah ini:
g++ -o source2html source2html.cpp -lqt -I/usr/lib/qt2/include
-L/usr/lib/qt2/lib
Jangan lupa sesuaikan /usr/lib/qt2 dengan direktori instalasi Qt pada sistem Anda.
Setelah terbentuk file executable source2html, maka utility kecil ini siap digunakan.
Untuk menghasilkan versi HTML dari source code bernama contoh.cpp, gunakan
perintah berikut:
source2html contoh.cpp
Kode-kode HTML akan tertampilkan ke layar (standard output). Anda bisa melakukan
redirecting ke file ataupun diproses lagi dengan filter. Selamat mencoba !

Tanya Jawab

Tanya: Mengapa harus ada geometry management? Bukankah kita bisa meletakkan
widget-widget pada posisi (per pixel) yang diinginkan ?
Jawab: Meski terlihat menyulitkan, geometry management bisa menjadi
menguntungkan. Hal ini terjadi manakala widget-widget diatur dalam sebuah window
yang bisa berubah-ubah ukurannya. Dengan meletakkan widget di posisi yang pasti,
perubahan ukuran window tidak akan berpengaruh apa-apa terhadap keadaan widget
tersebut. Sebaliknya, menggunakan konsep geometry management, perubahan ukuran
window bisa menyebabkan widget-widget tertentu beralih tempat, memanjang, atau
memendek. Selain itu, perhatikan bahwa kebanyakan aplikasi KDE mendukung
penggunaan banyak bahasa, tidak hanya Inggris. Sekarang bayangkan bila ukuran sebuah
push-button hanya sebesar yang diperlukan captionnya - misalnya "Save", apa yang
terjadi bila program ini kemudian mendukung bahasa lain, katakanlah bahasa Jerman
atau bahasa Indonesia ? Caption yang sudah berubah - menjadi "Speichern" untuk bahasa
Jerman bisa tidak muat pada push-button tersebut. Dengan geometry-management, hal ini
tidak akan terjadi karena push-button ini akan menyesuaikan ukuran dirinya sendiri.

Created By Muhammad Syahrizal 101


Malahan, mungkin saja window yang menjadi ditumpangi button tersebut juga membesar
dengan sendirinya.

Tanya: Saya terus gagal untuk melakukan compile.


Jawab: Salah satu kesalahan paling yang cukup sering dilakukan adalah meng-include
file header dan bukan file moc. Periksa source code Anda, apakah meng-include-kan
edit.h yang seharusnya adalah edit.moc.

Tanya: Saya memodifikasi program Kawan yang sudah saya buat sebelumnya, tetapi
mengapa kerap kali muncul pesan kesalahan "Segmentation Fault". Bagaimana bisa
demikian ?
Jawab: Dalam kebanyakan kasus, ini disebabkan ketidaksinkronan antara file hasil Meta
Object Compiler (berekstensi .moc) dengan header file (bereksensi .h). Pemecahan:
melakukan kompilasi ulang dengan menjalankan make clean sebelum make.

Tanya: Apakah QLayout bisa digunakan di window utama ?


Jawab: Tentu saja. Dalam contoh yang diketengahkan di bagian ini (dan juga
bagian-bagian sebelumnya dari tulisan ini), window utama program masih begitu
sederhananya dan hanya terdiri atas satu widget utama sehingga tidak perlu susah-susah
dilayout. Akan tetapi, Anda tentu masih ingat program Gallery yang muncul di bagian
pertama. Program Gallery ini menggunakan penataan manual untuk meletakkan widget,
yaitu di posisi yang ditentukan per piksel. Dengan memanfaatkan QLayout, program
Gallery bisa dimodifikasi agar menggunakan juga manajemen geometri yang sudah
dikupas di atas.

Tanya: Bisakah layout digunakan bertingkat ?


Jawab: Sangat bisa. Jikalau Anda cermati, kotak dialog Edit dari program Kawan
menggunakan layout bertingkat, yaitu layout di dalam layout. Untuk mendesain susunan
widget yang kompleks, layout bertingkat bisa menjadi amat berguna. Namun, perhatikan
bahwa layout bertingkat meningkatkan kerumitan program sehingga harus dipergunakan
secara berhati-hati.

Tanya: Bagaimana menyisipkan ruang kosong fleksibel di antara widget ?


Jawab: Triknya adalah menggunakan widget yang bebas untuk berubah ukurannya,
sesuai dengan ruang yang tersedia. Dengan demikian, widget inilah yang akan menjadi
"ruang kosong;". Untuk ini, bisa dimanfaatkan widget dari kelas QWidget yang memang
tidak ada bentuk tampilannya alias kosong saja, seolah tidak ada apa-apa di situ. Catatan:
trik ini sudah digunakan di edit.cpp yang dibahas di tulisan ini, lihat saja baris 38-42.

Tanya: Nah, sekarang bagaimana menyisipkan ruang kosong yang tidak fleksibel di
antara widget ?
Jawab: Masih menggunakan trik yang sama: bentuk sebuah widget dari QWidget,
kemudian atur dengan setSizePolicy untuk memaksa ukurannya tidak berubah (yakni
QSizePolicy::Fixed). Jangan lupa untuk menentukan ukuran widget ini dengan
resize.

Tanya: Tentang program kecil source2html, mengapa tidak menggunakan Perl atau
Python saja ?
Jawab: Seperti sudah disebutkan, program ini sekaligus berfungsi mendemonstrasikan

Created By Muhammad Syahrizal 102


Qt, karenanya dibuat dengan Qt. Pada praktisnya, Anda bisa saja meramu sebuah script
pendek dalam Perl, Python, atau bahkan shell script biasa untuk fungsi yang sama.

Tanya: Siapakah empat nama yang disajikan di contoh QGridLayout ?


Jawab: Empat nama ini - bersama juga Albus Dumbledore - semestinya tidak asing
untuk anak kecil. Akan tetapi tidak bisa dipungkiri juga bahwa tidak semua Muggle
mengetahui keberadaan mereka...

Berbekal pengetahuan tentang Qt yang selama ini telah dibahas, sekarang adalah saatnya
untuk menampilkan sebuah studi kasus pengembangan aplikasi contoh yang cukup
berguna dalam kehidupan nyata, yaitu sebuah editor multifile bernama...

Expad

Sebuah editor teks dikatakan multifile jika dapat menyunting beberapa file sekaligus.
Lazimnya kemampuan seperti ini dimiliki oleh aplikasi-aplikasi office, misalnya
StarOffice atau Microsoft Office (di Windows). Yang akan diulas di sini tentu saja
aplikasi yang lebih sederhana karena hanya bertugas mengedit file teks biasa saja, namun
punya keunggulan menampung sejumlah file pada satu window aplikasi.
Mula-mula marilah kita definisikan spesifikasi dari editor yang akan dinamakan Expad
ini. Syarat utama tentu bahwa editor dapat menampilkan dan menangani file-file teks
sekaligus, dengan jumlah yang tidak dibatasi. Untuk mudahnya, sekian banyak file teks
ini tidak dipisah-pisah dengan menggunakan window editor sendiri-sendiri. Akan lebih
indah jikalau digunakan tab untuk memilih file yang akan diaktifkan. Kira-kira hal
demikian serupa dengan memilih lembar kerja di aplikasi spreadsheet (seperti Microsoft
Excel di Windows). Guna kemudahan user, tab ini harus diletakkan di bagian atas.
Untuk memilih-milih file yang akan diedit, Expad diharapkan dapat menampilkan
struktur direktori pada sebuah panel tersendiri. Selain mendaftar direktori, panel ini juga
menyajikan daftar file-file pada direktori yang aktif. Dengan panel ini, user bisa

Created By Muhammad Syahrizal 103


berpindah direktori dengan mudah dan juga dapat memilih file yang ingin disunting. Jadi
begitu menyorot file tertentu dan mengkliknya, maka file ini akan dimuatkan ke editornya
dan siap dimodifikasi.

Sebagai pelengkap, Expad juga akan memiliki toolbar untuk mengakses fungsi-fungsi
yang sering diperlukan dengan mudah dan cepat. Adapun yang akan dimasukkan ke
toolbar adalah fungsi operasi file (new, open, save) dan fungsi penyuntingan (cut, copy,
paste, undo).

Dari deskripsi sederhana tentang fungsionalitas Expad ini mestinya sudah dapat
disketsakan secara kasar apa-apa saja yang perlu diimplementasikan. Yang jelas
dibutuhkan adalah window utama aplikasi harus selalu ada dan ini diturunkan dari widget
QMainWindow. Untuk Expad, window utama ini akan disebut sebagai ExpadWindow.
Dua elemen lain yang akan menjadi bawahan dari ExpadWindow adalah editor teks
dengan tab dan panel yang menyajikan daftar direktori dan file. Yang pertama akan
berupa widget ExpadTab dan yang kedua adalah DirList. Widget ExpadTab berasal dari
widget QTabWidget yang sudah disediakan Qt yang memang khusus dipergunakan kalau
ingin memanfaatkan tab-tab, lumrahnya dijumpai pada pembuatan kotak dialog yang
kompleks. Sementara itu DirList mewarisi widget QListView, dimodifikasi untuk bisa
mendaftar direktori/file. Tentang QListView, contoh pemakaiannya sudah pernah
disinggung di bagian empat seri tulisan ini.
File header expad.h di bawah ini agaknya bisa berbicara lebih banyak daripada
segerobak kata-kata.
1: // expad.h
2: #ifndef __EXPAD_H
3: #define __EXPAD_H
4:
5: #include <qmainwindow.h>
6: #include <qaction.h>
7: #include <qwidget.h>
8: #include <qlist.h>
9: #include <qstring.h>
10: #include <qmultilineedit.h>
11: #include <qtabwidget.h>
12: #include <qprinter.h>
13: #include <qsplitter.h>
14: #include <qlistview.h>
15:
16: class Editor: public QMultiLineEdit
17: {
18: Q_OBJECT
19:
20: public:
21: Editor( QWidget * parent=0, const char * name=0 );
22: void load();
23: void save();
24: QString filename();
25: QString title();
26: void setFilename( const QString& fn );
27:
28: private:
29: QString m_filename;
30: QString m_shortname;
31: };
32:
33: class DirListItem: public QListViewItem
34: {
35: protected:
36: bool m_isDir;

Created By Muhammad Syahrizal 104


37: bool m_isReadable;
38: QString m_name;
39:
40: public:
41: DirListItem( QListView*, const QString&, bool, bool );
42: QString text( int ) const;
43: bool isDir(){ return m_isDir; }
44: bool isReadable(){ return m_isReadable; }
45: QString shortName(){ return m_name; }
46: };
47:
48: class DirList: public QListView
49: {
50: Q_OBJECT
51:
52: public:
53: DirList( QWidget* parent=0, const char* name=0 );
54: void setDir( const QString& );
55: QString dir(){ return m_dir; }
56:
57: protected slots:
58: void slotDoubleClicked( QListViewItem* item );
59:
60: signals:
61: void selected( const QString& filename );
62:
63: protected:
64: QString m_dir;
65:
66: };
67:
68: class ExpadTab: public QTabWidget
69: {
70: Q_OBJECT
71:
72: public:
73: ExpadTab( QWidget * parent=0, const char * name=0, WFlags f=0 ):
74: QTabWidget( parent, name, f ) {};
75:
76: int count();
77:
78: void addEditor( Editor* e, const QString& t );
79: Editor* currentEditor();
80: void removeEditor( Editor* e );
81: void open( const QString& filename = "" );
82: void save();
83: };
84:
85: class ExpadWindow: public QMainWindow
86: {
87: Q_OBJECT
88:
89: public:
90: ExpadWindow();
91:
92: protected:
93:
94: void initActions();
95: void initMenu();
96: void initToolbar();
97:
98: private slots:
99:
100: void fileNew();
101: void fileOpen();
102: void fileSave();
103: void fileSaveAs();
104: void fileClose();

Created By Muhammad Syahrizal 105


105: void fileCloseAll();
106: void fileQuit();
107:
108: void editUndo();
109: void editRedo();
110: void editCut();
111: void editCopy();
112: void editPaste();
113: void editSelectAll();
114:
115: void about();
116:
117: void tabChanged( QWidget* );
118: void openFile( const QString& filename );
119:
120: private:
121:
122: // main widgets
123: QSplitter* splitter;
124: ExpadTab *tabs;
125: DirList* dirlist;
126:
127: // actions
128: QAction* ma_FileNew;
129: QAction* ma_FileOpen;
130: QAction* ma_FileSave;
131: QAction* ma_FileSaveAs;
132: QAction* ma_FileClose;
133: QAction* ma_FileCloseAll;
134: QAction* ma_FileQuit;
135:
136: QAction* ma_EditUndo;
137: QAction* ma_EditRedo;
138: QAction* ma_EditCut;
139: QAction* ma_EditCopy;
140: QAction* ma_EditPaste;
141: QAction* ma_EditSelectAll;
142:
143: QAction* ma_About;
144: };
145:
146: #endif
Listing 1. expad.h

Bisa dilihat, ada beberapa widget yang harus dikonstruksi. Kelas Editor adalah kelas yang
akan digunakan oleh ExpadTab untuk menangani satu file yang disunting. Karena Expad
bisa membuka beberapa file sekaligus, akan ada satu instance dari Editor untuk
masing-masing file. Dengan menggunakan antarmuka tab yang dimiliki ExpadTab
(diwarisi dari QTabWidget), maka satu Editor akan berupa satu tab dari ExpadTab. Hal
ini akan menghasilkan tampilan yang sesuai dengan rancangan.
Sementara itu widget DirList tidak seberapa kompleks, tidak lain karena DirList adalah
QListView yang diperluas supaya punya kemampuan mendaftar direktori/file. Untuk
kelengkapan widget ini, perlu adanya kelas DirListItem (diturunkan dari
QListViewItem). Masing-masing item pada DirList, entah direktori ataupun file, akan
merupakan instance dari DirListItem.

Lepas dari definisi kelas-kelas tadi, ada sejumlah QAction di ExpadWindow. Apakah
sebenarnya QAction ini ? Sebelumnya, simak terlebih dahulu implementasi
widget-widget yang digunakan Expad dalam file program utama expad.cpp berikut ini:
1: // expad.cpp - Multiple-file text editor - Ariya Hidayat 2001
2:

Created By Muhammad Syahrizal 106


3: #include <qaccel.h>
4: #include <qaction.h>
5: #include <qapplication.h>
6: #include <qdir.h>
7: #include <qfiledialog.h>
8: #include <qfileinfo.h>
9: #include <qkeycode.h>
10: #include <qlayout.h>
11: #include <qlistview.h>
12: #include <qmenubar.h>
13: #include <qmessagebox.h>
14: #include <qmultilineedit.h>
15: #include <qpopupmenu.h>
16: #include <qsplitter.h>
17: #include <qstatusbar.h>
18: #include <qtabwidget.h>
19: #include <qtabbar.h>
20: #include <qtextstream.h>
21: #include <qtoolbar.h>
22:
23: #include "expad.moc"
24: #include "icons.h"
25:
26: const char * icon_expad_xpm[] = {
27: "32 32 20 1",
28: " c None",
29: ". c #808000",
30: "+ c #525254",
31: "@ c #000000",
32: "# c #FFFFFF",
33: "$ c #DCDCDC",
34: "% c #FFDCA8",
35: "& c #C3C3C3",
36: "* c #585858",
37: "= c #303030",
38: "- c #A0A0A0",
39: "; c #000000",
40: "> c #808080",
41: ", c #FFC0C0",
42: "' c #404000",
43: ") c #C0C000",
44: "! c #FFFFC0",
45: "~ c #FFA858",
46: "{ c #C0C0FF",
47: "] c #400000",
48: " ************=@ ",
49: " *&&&&&&&&&---'@ ",
50: " ******&#########$&*>@ ",
51: " *&&&&*&##########$*&>@ ",
52: " *&###*&###########*#&>@ ",
53: " *&###*&##---######*##$>@ ",
54: " *&###*&###########*$##&>@ ",
55: " *&###*&##------###*&$##$>@ ",
56: " *&###*&###########>******=@ ",
57: " *&###*&##------####$$&&->*@ ",
58: " *&###*&#############$$&&->@ ",
59: " *&###*&##############$$&&>@ ",
60: " *&###*&##---------####$$&-@ ",
61: " *&###*&################$$-@ ",
62: " *&###*&##-------------#$$&@ ",
63: " *&###*&##################-@ ",
64: " *&###*&##-------------###&@ ",
65: " *&###*&##################-@ ",
66: " *&###*&##----------######&@ ",
67: " *&###*&##################-@ ",
68: " *&###*&##################-= ",
69: " *&###*&##-------------###-= ",
70: " *&###*&##################-= ",

Created By Muhammad Syahrizal 107


71: " *&###*&##-------------###-= ",
72: " *&###*&##################-= ",
73: " *&###*&##################-= ",
74: " *&###*&&&-----------------= ",
75: " *&###@==================]=@ ",
76: " *&#####################-= ",
77: " *&#####################-= ",
78: " *&&---------------------= ",
79: " ========================= "};
80:
81: static const char* icon_folder_xpm[]={
82: "16 16 17 1",
83: " c None",
84: ". c #020202",
85: "+ c #A1741D",
86: "@ c #CC943A",
87: "# c #8D6819",
88: "$ c #C5C2BE",
89: "% c #2B2B2B",
90: "& c #E2DCD5",
91: "* c #484848",
92: "= c #ACA69C",
93: "- c #737373",
94: "; c #7A5A12",
95: "> c #6A6A6A",
96: ", c #EEEEEE",
97: "' c #CEA975",
98: ") c #563A06",
99: "! c #AD6A0E",
100: " .* ",
101: " .$,**% ",
102: " *#)-=$,*.*-. ",
103: " %&,'#)-=$,,,. ",
104: " %'@'&,'+)-=$,*",
105: " %@!@'''&,'#)-*",
106: " %@++!!@@'$&,'*",
107: " %+;###+!!@@'&*",
108: " *,,=#;##++!!'*",
109: " *,,,,&=#;##+@*",
110: " *,,,&&&&$=#;#*",
111: " %$&&&&&$$$$$>*",
112: " .%>$$$$$$$=>*",
113: " .%>=$$==>*",
114: " .%>==>*",
115: " .%% "};
116:
117: // -------- implementation of Editor ---------
118:
119: Editor::Editor( QWidget * parent, const char * name ):
120: QMultiLineEdit( parent, name )
121: {
122: m_filename = m_shortname = "";
123: setFont( QFont( "adobe-courier" ) );
124: }
125:
126: QString Editor::filename()
127: {
128: return m_filename;
129: }
130:
131: QString Editor::title()
132: {
133: return m_shortname;
134: }
135:
136: void Editor::setFilename( const QString& fn )
137: {
138: m_filename = fn;

Created By Muhammad Syahrizal 108


139: QFileInfo fi( m_filename );
140: m_shortname = fi.fileName();
141: if( m_shortname.isEmpty())
142: m_shortname = "Untitled";
143: }
144:
145: void Editor::load()
146: {
147: if( filename().isEmpty() ) return;
148:
149: QFile f( filename() );
150:
151: if( f.open( IO_ReadOnly ) )
152: {
153: setAutoUpdate( FALSE );
154: clear();
155: QTextStream t( &f );
156: while ( !t.eof() ) {
157: QString s = t.readLine();
158: append( s );
159: }
160: f.close();
161: setAutoUpdate( TRUE );
162: repaint();
163: setEdited( FALSE );
164: }
165: }
166:
167: void Editor::save()
168: {
169: if( filename().isEmpty() ) return;
170:
171: QFile f( filename() );
172:
173: if ( f.open( IO_WriteOnly ) )
174: {
175: QTextStream t( &f );
176: t << text();
177: f.close();
178: }
179:
180: setEdited( FALSE );
181: }
182:
183: // -------- implementation of DirListItem ---------
184:
185: DirListItem::DirListItem( QListView* parent, const QString& name,
186: bool dir, bool readable ):
187: QListViewItem( parent, name )
188: {
189: m_name = name;
190: m_isDir = dir;
191: m_isReadable = readable;
192:
193: if( m_isDir ) setPixmap( 0, icon_folder_xpm );
194:
195: }
196:
197: QString DirListItem::text( int column ) const
198: {
199: if( column == 0 ) return m_name;
200: else if( column == 1 ) return m_isDir ? "Directory" : "File";
201: else return QString::null;
202: }
203:
204: // -------- implementation of DirList ---------
205:
206: DirList::DirList( QWidget* parent, const char* name ):

Created By Muhammad Syahrizal 109


207: QListView( parent, name )
208: {
209: m_dir = "";
210: addColumn( "Name" );
211: addColumn( "Type" );
212:
213: setDir( "/" );
214: setMinimumSize( 100, 50 );
215: setSorting( -1 );
216:
217: connect( this, SIGNAL( doubleClicked( QListViewItem* ) ),
218: this, SLOT( slotDoubleClicked( QListViewItem* ) ) );
219: }
220:
221: void DirList::setDir( const QString& dir )
222: {
223: QDir d( dir );
224:
225: if( !d.exists() ) return;
226:
227: m_dir = dir;
228:
229: d.setSorting( QDir::Name | QDir::DirsFirst | QDir::IgnoreCase );
230: const QFileInfoList *list = d.entryInfoList();
231: QFileInfoListIterator it( *list );
232: QFileInfo *fi;
233:
234: clear();
235: it.toLast();
236:
237: while ( ( fi = it.current() ) )
238: {
239: if( fi->fileName() != "." )
240: {
241: QListViewItem* item;
242: item = new DirListItem( this, fi->fileName(),
243: fi->isDir(), fi->isReadable() );
244: }
245: --it;
246: }
247: }
248:
249: void DirList::slotDoubleClicked( QListViewItem* i )
250: {
251: DirListItem* item = (DirListItem*) i;
252: if( item )
253: if( item->isReadable() )
254: {
255: QString fullName = m_dir + "/" + item->shortName();
256: if( item->isDir() ) setDir( fullName );
257: else emit selected( fullName );
258: }
259: }
260:
261: // -------- implementation of ExpadTab ---------
262:
263: int ExpadTab::count()
264: {
265: return tabBar()->count();
266: }
267:
268: void ExpadTab::addEditor( Editor* e, const QString& t )
269: {
270: if( !e ) return;
271: addTab( e, t );
272: setCurrentPage( count() - 1 );
273: e->show();
274: show();

Created By Muhammad Syahrizal 110


275: }
276:
277: void ExpadTab::removeEditor( Editor* e )
278: {
279: if( !e ) return;
280: removePage( e );
281: delete e;
282: show();
283: }
284:
285: Editor* ExpadTab::currentEditor()
286: {
287: return (Editor*) currentPage();
288: }
289:
290: // -------- implementation of ExpadWindow ---------
291:
292: const char* app = "Expad";
293:
294: ExpadWindow::ExpadWindow()
295: : QMainWindow( 0, "ExpadWindow", WDestructiveClose )
296: {
297: initActions();
298: initMenu();
299: initToolbar();
300:
301: splitter = new QSplitter( this );
302: setCentralWidget( splitter );
303:
304: dirlist = new DirList( splitter);
305: splitter->setResizeMode( dirlist, QSplitter::KeepSize );
306: connect( dirlist, SIGNAL( selected( const QString& ) ),
307: this, SLOT( openFile( const QString& ) ) );
308:
309: tabs = new ExpadTab( splitter );
310: connect( tabs, SIGNAL( currentChanged( QWidget* ) ),
311: this, SLOT( tabChanged( QWidget* ) ) );
312:
313: setIcon( icon_expad_xpm );
314:
315: fileNew();
316:
317: statusBar()->message( "Ready", 2000 );
318: resize( 450, 400 );
319: }
320:
321: void ExpadWindow::initActions()
322: {
323: ma_FileNew = new QAction( this );
324: ma_FileNew->setText( "New" );
325: ma_FileNew->setAccel( CTRL + Key_N );
326: ma_FileNew->setIconSet( QPixmap( filenew_xpm ) );
327: connect( ma_FileNew, SIGNAL( activated() ),
328: this, SLOT( fileNew() ) );
329:
330: ma_FileOpen = new QAction( this );
331: ma_FileOpen->setText( "Open" );
332: ma_FileOpen->setAccel( CTRL + Key_O );
333: ma_FileOpen->setIconSet( QPixmap( fileopen_xpm ) );
334: connect( ma_FileOpen, SIGNAL( activated() ),
335: this, SLOT( fileOpen() ) );
336:
337: ma_FileSave = new QAction( this );
338: ma_FileSave->setText( "Save" );
339: ma_FileSave->setAccel( CTRL + Key_S );
340: ma_FileSave->setIconSet( QPixmap( filesave_xpm ) );
341: connect( ma_FileSave, SIGNAL( activated() ),
342: this, SLOT( fileSave() ) );

Created By Muhammad Syahrizal 111


343:
344: ma_FileSaveAs = new QAction( this );
345: ma_FileSaveAs->setText( "Save As" );
346: connect( ma_FileSaveAs, SIGNAL( activated() ),
347: this, SLOT( fileSaveAs() ) );
348:
349: ma_FileClose = new QAction( this );
350: ma_FileClose->setText( "Close" );
351: ma_FileClose->setAccel( CTRL + Key_W );
352: connect( ma_FileClose, SIGNAL( activated() ),
353: this, SLOT( fileClose() ) );
354:
355: ma_FileCloseAll = new QAction( this );
356: ma_FileCloseAll->setText( "Close All" );
357: connect( ma_FileCloseAll, SIGNAL( activated() ),
358: this, SLOT( fileCloseAll() ) );
359:
360: ma_FileQuit = new QAction( this );
361: ma_FileQuit->setText( "Quit" );
362: ma_FileQuit->setAccel( CTRL + Key_X );
363: connect( ma_FileQuit, SIGNAL( activated() ),
364: this, SLOT( fileQuit() ) );
365:
366: ma_EditUndo = new QAction( this );
367: ma_EditUndo->setText( "Undo");
368: ma_EditUndo->setAccel( CTRL + Key_Z );
369: ma_EditUndo->setIconSet( QPixmap( editundo_xpm ) );
370: connect( ma_EditUndo, SIGNAL( activated() ),
371: this, SLOT( editUndo() ) );
372:
373: ma_EditRedo = new QAction( this );
374: ma_EditRedo->setText( "Redo");
375: connect( ma_EditRedo, SIGNAL( activated() ),
376: this, SLOT( editRedo() ) );
377:
378: ma_EditCut = new QAction( this );
379: ma_EditCut->setText( "Cut");
380: ma_EditCut->setAccel( CTRL + Key_X );
381: ma_EditCut->setIconSet( QPixmap( editcut_xpm ) );
382: connect( ma_EditCut, SIGNAL( activated() ),
383: this, SLOT( editCut() ) );
384:
385: ma_EditCopy = new QAction( this );
386: ma_EditCopy->setText( "Copy");
387: ma_EditCopy->setAccel( CTRL + Key_C );
388: ma_EditCopy->setIconSet( QPixmap( editcopy_xpm ) );
389: connect( ma_EditCopy, SIGNAL( activated() ),
390: this, SLOT( editCopy() ) );
391:
392: ma_EditPaste = new QAction( this );
393: ma_EditPaste->setText( "Paste");
394: ma_EditPaste->setAccel( CTRL + Key_V );
395: ma_EditPaste->setIconSet( QPixmap( editpaste_xpm ) );
396: connect( ma_EditPaste, SIGNAL( activated() ),
397: this, SLOT( editPaste() ) );
398:
399: ma_EditSelectAll = new QAction( this );
400: ma_EditSelectAll->setText( "Select All");
401: ma_EditSelectAll->setAccel( CTRL + Key_A );
402: connect( ma_EditSelectAll, SIGNAL( activated() ),
403: this, SLOT( editSelectAll() ) );
404:
405: ma_About = new QAction( this );
406: ma_About->setText( "About...");
407: connect( ma_About, SIGNAL( activated() ),
408: this, SLOT( about() ) );
409: }
410:

Created By Muhammad Syahrizal 112


411: // initialize menu
412: void ExpadWindow::initMenu()
413: {
414: QPopupMenu *file_menu = new QPopupMenu( this );
415: menuBar()->insertItem( "&File", file_menu );
416: ma_FileNew->addTo( file_menu );
417: ma_FileOpen->addTo( file_menu );
418: file_menu->insertSeparator();
419: ma_FileSave->addTo( file_menu );
420: ma_FileSaveAs->addTo( file_menu );
421: file_menu->insertSeparator();
422: ma_FileClose->addTo( file_menu );
423: ma_FileCloseAll->addTo( file_menu );
424: file_menu->insertSeparator();
425: ma_FileQuit->addTo( file_menu );
426:
427: QPopupMenu *edit_menu = new QPopupMenu( this );
428: menuBar()->insertSeparator();
429: menuBar()->insertItem( "&Edit", edit_menu );
430: ma_EditUndo->addTo( edit_menu );
431: ma_EditRedo->addTo( edit_menu );
432: edit_menu->insertSeparator();
433: ma_EditCut->addTo( edit_menu );
434: ma_EditCopy->addTo( edit_menu );
435: ma_EditPaste->addTo( edit_menu );
436: edit_menu->insertSeparator();
437: ma_EditSelectAll->addTo( edit_menu );
438:
439: QPopupMenu *help_menu = new QPopupMenu( this );
440: menuBar()->insertSeparator();
441: menuBar()->insertItem( "&Help", help_menu );
442: ma_About->addTo( help_menu );
443: }
444:
445: // initialize toolbar
446: void ExpadWindow::initToolbar()
447: {
448: QToolBar* toolbar = new QToolBar( this );
449: ma_FileNew->addTo( toolbar );
450: ma_FileOpen->addTo( toolbar );
451: ma_FileSave->addTo( toolbar );
452: toolbar->addSeparator();
453: ma_EditCut->addTo( toolbar );
454: ma_EditCopy->addTo( toolbar );
455: ma_EditPaste->addTo( toolbar );
456: ma_EditUndo->addTo( toolbar );
457: QWidget* spacer = new QWidget( toolbar );
458: spacer->setSizePolicy( QSizePolicy( QSizePolicy::Expanding,
459: QSizePolicy::Expanding ) );
460: setRightJustification( TRUE );
461: }
462:
463: // opens the given file as new document
464: void ExpadWindow::openFile( const QString& filename )
465: {
466: if( !filename.isEmpty() )
467: {
468: Editor* editor = new Editor( tabs );
469: editor->setFilename( filename );
470: editor->load();
471: tabs->addEditor( editor, editor->title() );
472: }
473: }
474:
475: // creates a new blank document
476: void ExpadWindow::fileNew()
477: {
478: Editor* editor = new Editor( tabs );

Created By Muhammad Syahrizal 113


479: editor->setFilename( QString::null );
480: tabs->addEditor( editor, editor->title() );
481: }
482:
483: // opens and loads a document
484: void ExpadWindow::fileOpen()
485: {
486: QString filename;
487: filename = QFileDialog::getOpenFileName( dirlist->dir(),
488: QString::null, this);
489: openFile( filename );
490: }
491:
492: // saves active document
493: void ExpadWindow::fileSave()
494: {
495: Editor* editor = tabs->currentEditor();
496: if( !editor) return;
497:
498: if( editor->filename().isEmpty() ) fileSaveAs();
499: editor->save();
500: }
501:
502: // saves document to a different name
503: void ExpadWindow::fileSaveAs()
504: {
505: Editor* editor = tabs->currentEditor();
506: if( !editor) return;
507:
508: QString filename;
509: filename = QFileDialog::getSaveFileName( dirlist->dir(),
510: QString::null, this);
511: if( !filename.isEmpty() )
512: {
513: editor->setFilename( filename );
514: editor->save();
515: tabs->changeTab( editor, editor->title() );
516: }
517: }
518:
519: // closes active document
520: void ExpadWindow::fileClose()
521: {
522: Editor* editor = tabs->currentEditor();
523: if( !editor ) return;
524:
525: if( editor->edited() )
526: {
527: // confirm user
528: QString msg = QString("The document <b>%1</b> has been changed
since "\
529: "the last save.").arg( editor->title() );
530: int choice = QMessageBox::information( this, "Confirm", msg,
531: "Save Now", "Discard",
"Cancel",
532: 0, 1 );
533: if( choice == 2 ) return;
534: if( choice == 0 ) fileSave();
535: }
536: tabs->removeEditor( editor );
537: }
538:
539: // closes all document
540: void ExpadWindow::fileCloseAll()
541: {
542: while( tabs->currentEditor() )
543: {
544: Editor* editor = tabs->currentEditor();

Created By Muhammad Syahrizal 114


545:
546: if( editor->edited() )
547: {
548: // confirm user
549: QString msg = QString("The document <b>%1</b> has been changed
since "\
550: "the last save.").arg( editor->title() );
551: int choice = QMessageBox::information( this, "Confirm", msg,
552: "Save Now", "Discard",
"Cancel",
553: 0, 1 );
554: if( choice == 2 ) return;
555: if( choice == 0 ) fileSave();
556: }
557: tabs->removeEditor( editor );
558: }
559: }
560:
561: // exits program
562: void ExpadWindow::fileQuit()
563: {
564: fileCloseAll();
565: close();
566: }
567:
568: // reverts last action
569: void ExpadWindow::editUndo()
570: {
571: Editor *e = tabs->currentEditor();
572: if( e ) e->undo();
573: }
574:
575: // redoes last action
576: void ExpadWindow::editRedo()
577: {
578: Editor *e = tabs->currentEditor();
579: if( e ) e->redo();
580: }
581:
582: // cuts selected text
583: void ExpadWindow::editCut()
584: {
585: Editor *e = tabs->currentEditor();
586: if( e ) e->cut();
587: }
588:
589: // copies selected text
590: void ExpadWindow::editCopy()
591: {
592: Editor *e = tabs->currentEditor();
593: if( e ) e->copy();
594: }
595:
596: // pastes from clipboard
597: void ExpadWindow::editPaste()
598: {
599: Editor *e = tabs->currentEditor();
600: if( e ) e->paste();
601: }
602:
603: // selects all text
604: void ExpadWindow::editSelectAll()
605: {
606: Editor *e = tabs->currentEditor();
607: if( e ) e->selectAll();
608: }
609:
610: // displays program information

Created By Muhammad Syahrizal 115


611: void ExpadWindow::about()
612: {
613: QMessageBox::about( this, QString("About %1").arg( app ),
614: "<b>" + QString( app ) + "</b>" +
615: "<p>Multiple-file text editor</p>"
616: "<p>Programmed by Ariya Hidayat<br>"
617: "ariya@infolinux.co.id</p>" );
618: }
619:
620: void ExpadWindow::tabChanged( QWidget* )
621: {
622: Editor* editor = tabs->currentEditor();
623: if( !editor ) return;
624: setCaption( editor->title() + " - " + app );
625: }
Listing 2. expad.cpp

Walaupun terbilang agak panjang, sesungguhnya file expad.cpp dapat dibagi atas
beberapa bagian utama, masing-masing untuk implementasi kelas yang berbeda.
Kelas Editor mewakili widget utama tempat user mengedit isi dari file. Untuk mudahnya
(sebagaimana bisa dicermati dari file header sebelumnya), Editor ini hanya merupakan
modifikasi kecil dari widget QMultiLineEdit. Dibandingkan QMultiLineEdit, widget
Editor ditambahkan fungsi untuk memudahkan menyimpan dan mengambil isi dari file
teks yang sedang disunting. Terdapat juga fungsi filename() yang akan memberikan
nama file yang bersesuaian dengan Editor tersebut. Bila ini adalah widget Editor yang
baru dibuat dan isinya belum pernah disimpan ke file, filename() akan mengembalikan
string kosong.

Penyunting teks lumrahnya bekerja dengan font yang sifatnya fixed-width, yakni yang
lebar per karakternya sama semua, tidak bergantung dari karakter itu sendiri. Jadi baik
huruf m maupun huruf i akan menyita ruang yang sama. Font semacam Courier tergolong
font yang seperti ini. Karenanya, dari awal widget Editor mengatur agar font yang
digunakan adalah font adobe-courier yakni salah satu ragam font Courier yang biasanya
sudah terinstal di sistem Linux. Umpamanya Anda ternyata tidak punya font ini, silakan
ganti dengan yang tersedia, misalnya bitstream-courier atau malah Courier New jika
Anda memasang font-font yang TrueType.

Kelas DirListItem akan merepresentasikan informasi mengenai satu item yang


ditampilkan di widget DirList, baik untuk direktori maupun untuk file. Sebagai kelas
pembantu untuk widget DirList, DirListItem akan memberikan keterangan dalam bentuk
dua kolom: yang pertama untuk nama file atau direktori dan yang kedua untuk jenisnya,
"Directory" ataukah "File". Guna membedakan antara file dan direktori, kelas
DirListItem akan mengatur agar sebuah pixmap kecil bergambar folder dibubuhkan di
bagian kiri jika item tersebut merupakan sebuah direktori.

Widget DirList merupakan panel yang mendaftar isi sebuah direktori tertentu. Hal ini
sendiri dilakukan dengan menggunakan QFileInfoList sebagaimana bisa dilihat di
fungsi DirList::setDir(). Fungsi QDir::entryInfoList sendiri akan
mengembalikan item-item yang dimiliki oleh direktori yang dimaksud dan kemudian bisa
ditelusuri menggunakan iterator bernama QFileInfoListIterator. Dari hasil
penjelajahan iterasi ini akan dibentuk sejumlah DirListItem yang mewakili
masing-masing item yang ditemukan (quiz untuk pembaca: mengapa entri "."
diabaikan?). Perhatikan bahwa karena membuat item baru QListView (dan juga DirList)

Created By Muhammad Syahrizal 116


akan menyebabkan item tersebut ditambahkan di akhir daftar item yang ada sehingga
item yang dibuat pertama akan tampil paling bawah. Karenanya, penelusuran iterator
harus dilakukan dari akhir ke awal agar nantinya justru item yang harusnya urutannya
awal tetap tampil paling atas.

Penting pula untuk diterangkan bagaimana DirList menangani klik-ganda dari user ketika
menyoroti sebuah item. Bila item tersebut berupa file, maka DirList akan membangkitkan
signal bernama selected( const QString& ), lihat lagi file header expad.h. Kelak
signal ini akan dihubungkan dengan slot yang tepat sehingga menghasilkan aksi memuat
file yang diklik ke editor. Sementara itu kejadiannya akan berbeda jika item yang diklik
adalah direktori. DirList segera beralih ke direktori yang dimaksud, tentu apabila
pengaturan permission mengijinkan user masuk ke dalamnya. Dalam kasus direktori ini,
tidak perlu ada signal yang dipicu.

Melihat definisi widget ExpadTab di file header expad.h jelaslah bahwa widget ini persis
seperti induknya, QTabWidget, dengan hanya fungsi-fungsi ekstra untuk menambahkan
sebuah widget Editor baru menjadi salah satu tabnya atau menghapus tab yang sudah ada.
Tab-tab di QTabWidget biasa disebut page dan inilah yang akan di-cast ke widget Editor.
Sederhana saja, bukan ?

Fungsionalitas paling berat ada pada ExpadWindow sebagai widget yang merupakan
window utama. ExpadWindow punya sejumlah slot yang berfungsi melakukan operasi
file, penyuntingan, dan lain-lain.

Begitu banyak QAction yang ada di ExpadWindow mencerminkan pendekatannya yang


sedikit berbeda soal penanganan input dari user. Sebuah QAction sendiri adalah abstraksi
dari suatu tindakan tertentu yang berasal dari user. Contohnya, ma_FileNew adalah action
untuk membuat dokumen baru. Selain melalui menu File, New, user dapat juga memicu
action ini dari tombol yang ada di toolbar maupun menggunakan keyboard dengan
shortcut tertentu, dalam contoh ini adalah Ctrl+N. Keuntungannya adalah bahwa satu
action saja bisa digunakan sebagai representasi item di menu program, button di toolbar,
dan sebagai tombol shortcut sehingga terasa cukup mudah dan praktis.
Dalam fungsi ExpadWindow::initMenu() dan ExpadWindow::initToolbar(),
sejumlah action yang diciptakan di ExpadWindow::initActions() disisipkan ke menu
utama dan ke toolbar hanya dengan memanggil fungsi addTo dari masing-masing action.
Anda tidak perlu lagi membuat item menu khusus atau tombol di toolbar, sebagaimana
yang sudah-sudah (lihat lagi misalnya program QSimpleApp di bagian kedua seri tulisan
ini). Selain menyederhanakan, teknik ini akan mengurangi duplikasi kode program yang
tidak perlu.

Soal urusan layout widget, ExpadWindow tidak menggunakan cara-cara layout yang
pernah dibahas sebelumnya. Ada dua elemen utama dalam satu window, yaitu panel
direktori (DirList) dan editor (ExpadTab). Sudah sewajarnya kedua elemen ini tampil
saling bersisian, namun dengan sebuah pembatas (splitter) yang dapat digerakkan untuk
mengatur pembagian ruangan bagi keduanya. Dengan Qt, hal demikian menjadi mudah
berkat widget QSplitter. Dua widget lain yang ingin dipisahkan tinggal menjadikan si
splitter sebagai parent-nya.

Di konstruktor ExpadWindow dijumpai pemanggilan fungsi setIcon(). Sebenarnya ini

Created By Muhammad Syahrizal 117


adalah untuk mengatur icon dari window utama, terlihat ketika Expad sudah dieksekusi.
Kelak icon yang sama juga muncul pada kotak dialog About.
Pada slot-slot yang mengurusi file, yakni fileNew(), fileOpen(), fileSave(),
fileSaveAs(), fileClose(), serta fileCloseAll(), sebagian besar hanya bertindak
sebagai jembatan untuk memanggil fungsi-fungsi yang tepat dari Editor ataupun
ExpadTab. Yang agak berbeda barangkali hanya fungsi fileClose() dan
fileCloseAll() yang harus mengkonfirmasi user terlebih dahulu tatkala ada dokumen
yang belum disimpan namun hendak ditutup.

Slot-slot lainnya di ExpadWindow berkenaan dengan operasi penyuntingan. Yang ini


malah jauh lebih sederhana, hanya memanggil fungsi penyuntingan yang sama dari salah
satu editor. Ikhwal mana editor yang aktif dideteksi dengan
ExpadTab::currentEditor().
Jangan terlewatkan juga bahwa untuk icon-icon di toolbar, expad.cpp ini membutuhkan
file header icons.h. File ini tidak disertakan lagi di sini (untuk alasan penghematan
tempat) karena Anda bisa mengambil file icons.h yang sama seperti yang sudah
dicantumkan di bagian kedua seri tulisan ini.
Kalaulah Anda masih kebingungan dengan beberapa kelas Qt yang dipergunakan dalam
Expad, dokumentasi referensi Qt memberikan keterangan panjang lebar mengenai
semuanya. Jangan segan-segan untuk senantiasa melongoknya !
Adapun program utamanya yang cukup beberapa belas baris kode adalah:
1: // Expad
2:
3: #include <qapplication.h>
4: #include "expad.h"
5:
6: int main( int argc, char ** argv )
7: {
8: QApplication a( argc, argv );
9:
10: QMainWindow * w = new ExpadWindow();
11: w->show();
12:
13: a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
14:
15: return a.exec();
16: }
Listing 3. main.cpp

Sebagaimana yang sudah-sudah, fungsi main.cpp di atas tidak kurang tidak lebih adalah
menjalinkan window utama ExpadWindow ke dalam sebuah aplikasi utuh.
Berikutnya, inilah Makefile yang digunakan untuk memudahkan proses
compile-and-link. Mudah-mudahan Anda tidak jenuh karena Makefile ini pada pokoknya
selalu saja sama dari dulu, yang disesuaikan hanya bagian TARGET, OBJECTS, dan
MOCS.
1: QTDIR = /usr/lib/qt2
2: QTLIB = $(QTDIR)/lib
3: QTINCLUDE = $(QTDIR)/include
4: QTMOC = $(QTDIR)/bin/moc
5:
6: TARGET = expad
7: OBJECTS = expad.o main.o
8: MOCS = expad.moc
9:
10: CC = g++
11: CFLAGS = -Wall -O2

Created By Muhammad Syahrizal 118


12: LIBS = -lqt
13:
14: $(TARGET): $(MOCS) $(OBJECTS)
15: $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) -L$(QTLIB)
-I$(QTINCLUDE)
16:
17: %.o: %.cpp
18: $(CC) $(CFLAGS) -I$(QTINCLUDE) -c $< -o $@
19:
20: %.moc: %.h
21: $(QTMOC) $< -o $@
22:
23: clean:
24: rm $(OBJECTS) $(TARGET) $(MOCS)
Listing 4. Makefile

Begitu Anda sudah mendapatkan semua file yang dibutuhkan, yaitu expad.h,
expad.cpp, icons.h, main.cpp, dan Makefile, maka kompilasi bisa dilakukan dengan
perintah:
make

Sejenak menggunakan dan mengamati kerja Expad ini (Gambar 1), bisa disimpulkan
bahwa spesifikasi seperti yang dibahas di awal tulisan ini sudah tercapai. Namun
demikian, tentunya ada beberapa penyempurnaan yang masih bisa dilakukan. Anda dapat
menganggapnya sebagai latihan kecil guna lebih mengenal seluk-beluk Qt.
Expad punya fasilitas Close All. Dengan teknik implementasi yang sama, mestinya juga
tidak susah untuk mewujudkan fasilitas Save All. Sementara itu, bisa Anda saksikan
bahwa font yang digunakan di widget Editor selalu sama, yakni adobe-courier. Pilihan
yang lebih baik adalah menyiapkan kotak dialog konfigurasi yang salah satunya
memungkinkan user mengganti font yang digunakan, bahkan juga tata warnanya.
Di sisi lain, DirList bisa mendapatkan sedikit perbaikan. Kalau untuk direktori ada icon
bergambar folder, mengapa tidak ada icon serupa untuk item yang berupa file ? Anda
bahkan bisa membedakan icon yang digunakan untuk file teks (berekstensi txt), file
README, file gambar, dan jenis-jenis lainnya. Sebuah direktori yang tidak bisa dibaca
(alias tidak readable) seharusnya juga mendapatkan icon yang berbeda, misalnya gambar
folder yang terkunci.
Modifikasi-modifikasi kecil di atas bisa dilakukan dengan hanya menambah beberapa
baris program di sana-sini tanpa harus merombak strukturnya secara keseluruhan.

Expad for Windows ?

Ketika mengawali seri pemrograman ini disebutkan bahwa Qt adalah toolkit yang bersifat
portabel. Maknanya adalah bahwa aplikasi-aplikasi yang dibuat sepenuhnya dengan
kelas-kelas yang disediakan oleh Qt benar-benar bersifat cross-platform, bisa
dikompilasi di sistem operasi yang didukung Qt, yaitu aneka varian Unix (termasuk
Linux) dan Windows. Sifat cross-platform ini menyebabkan source-code program sama
sekali tidak perlu diubah manakala dilakukan porting ke sistem operasi lain. Dengan
demikian Anda bisa mendesain program tertentu di Linux, membawa source-codenya ke
Windows, kemudian melakukan kompilasi ulang dan menghasilkan program baru yang
sudah for Windows.

Sayangnya, Qt versi Windows tidaklah diberikan secara cuma-cuma dan juga tidak
open-source. Anda harus membayar untuk mendapatkan lisensi pengembangan aplikasi

Created By Muhammad Syahrizal 119


Windows dengan Qt. Berita baiknya adalah bahwa Trolltech - si pembuat Qt - membuat
perkecualian bahwa Qt/Windows ini tersedia juga dalam edisi non-komersilnya. Dengan
menggunakan library Qt yang disediakan dalam edisi ini, Anda bisa menghasilkan
aplikasi Windows sepanjang aplikasi tersebut juga sifatnya free-software.
Memanfaatkan edisi non-komersil dari Qt/Windows yang bisa didownload di
www.trolltech.com/developer/download/qt-win-noncomm.html, Expad juga dapat
dibuat untuk Windows. Karena library yang disediakan hanya cocok untuk Microsoft
Visual C++, mau tidak mau Anda harus menggunakannya jika ingin mengkompilasi
Expad di Windows. Dengan portabilitas Qt, sama sekali tidak ada file source-code yang
perlu diubah, cukup sesuaikan proses kompilasinya (menggunakan Project di Visual
Studio). Hasilnya adalah Expad for Windows, berpenampilan dan berperilaku
benar-benar serupa dengan versi Linuxnya.

Dari studi kasus pengembangan editor multifile ini bisa Anda saksikan sendiri bagaimana
kekayaan API dari Qt menjadi sangat menolong. Berbekal desain dan rancang bangun
untuk aplikasi yang akan dikembangkan, pekerjaan selanjutnya nyaris seperti
merangkaikan blok-blok siap pakai yang sudah disediakan Qt. Cepat dan nyaman. Kalau
Anda sempat mengenal toolkit yang lain, misalnya GTK atau wxWindows,
mengkonstruksi editor seperti Expad (dengan fitur-fitur yang setara) akan menjadi
berbeda dan susah untuk tidak melampaui batas 1000 baris program. Begitu program
selesai, dengan sifatnya yang portabel, Anda bisa mengkompilasinya di Windows untuk
mendapatkan versi Windows program tersebut dengan mudah dan cepat.

Tanya Jawab

Tanya: Pada saat menjalankan make, muncul pesan kesalahan icons.h: No such file or
directory. Bagaimana ?
Jawab: Ini terjadi karena file expad.cpp membutuhkan file header icons.h (untuk
pixmap di toolbar), tetapi file header ini tidak ditemukan. Sebagaimana sudah disebutkan,
Anda bisa mengambil file icons.h dari bagian kedua seri tulisan ini.
Tanya: Proses compile berjalan lancar. Namun pada saat Expad dijalankan muncul pesan
kesalahan "Segmentation Fault". Mengapa ?
Jawab: Penyebab paling utama biasanya adalah ketidaksinkronan antara file hasil MOC
dengan file header. Solusi: jalankan make clean dahulu sebelum make.
Komunitas eLearning IlmuKomputer.Com

Tanya: Saat Expad dijalankan, saya ingin struktur direktori yang disajikan dimulai dari
home directory, bukan dari root directory. Bagaimana mengubahnya ?
Jawab: Lihatlah konstruktor untuk kelas DirList, tepatnya di baris 213. Perintah setDir(
"/" ) harus diubah, tidak lagi menunjuk ke / (root directory), tetapi ke home directory.
Bagaimana mengambil home directory ? Anda bisa menggunakan fungsi statik
QDir::homeDirPath(). Lihat juga referensi Qt tentang kelas QDir untuk lebih jelasnya.

Tanya: Adakah cara untuk mengganti icon program ?


Jawab: Tentu. Icon program didefinisikan oleh array icon_expad_xpm, lihat file
expad.cpp dari baris 26. Untuk menggantinya, lakukan langkah-langkah berikut. Cari
dahulu icon pengganti, sebaiknya berukuran 32x32 piksel saja. Ubah menjadi format
XPM (X Pixmap), misalnya dengan program pengolah citra seperti Gimp. Selanjutnya

Created By Muhammad Syahrizal 120


tinggal copy-and-paste isi file XPM tersebut menggantikan icon_expad_xpm. Bisa
gunakan editor bisa (bahkan Expad sekalipun!) karena format XPM sebenarnya adalah
file teks biasa.

Tanya: Tampilan struktur direktori menggunakan icon folder yang tidak begitu saya
sukai. Bagaimana menggantinya ?
Jawab: Mirip dengan yang jawaban dari pertanyaan sebelumnya. Di sini yang musti
Anda modifikasi adalah icon_folder_xpm, masih di file expad.cpp mulai baris 81.

Tanya: Bisakah saya mengedit file teks yang berukuran besar, misalnya beberapa MB,
dengan Expad ?
Jawab: Berbeda dengan Notepadnya Windows, widget QMultiLineEdit bisa menangani
teks sebanyak-banyaknya, hanya dibatasi oleh kapasitas memori yang ada. Karena Expad
menggunakan widget ini maka dengan sendirinya Expad akan sanggup mengurusi file
yang ukurannya besar. Hanya saja kemungkinan Anda akan mengalami gangguan
performansi seperti waktu loading yang lambat, pergerakan kursor yang patah-patah, dan
lain-lain.

Tanya: Jika saya mengutak-atik hingga tidak ada file yang dibuka oleh Expad, maka
tiba-tiba setelahnya Expad berperilaku agak aneh. Kenapa bisa demikian ?
Jawab: Ini adalah masalah Qt karena kelas QTabWidget tidak dirancang untuk tidak
mempunyai tab sama sekali. Untuk mengatasinya, Anda bisa memodifikasi program
sehingga jika hanya tinggal satu file yang aktif (berarti hanya satu tab di QTabWidget),
maka perintah Close bukan berarti menutup file tersebut, tetapi hanya menggantinya
dengan editor baru saja.

Tanya: Proses compile berjalan lancar. Namun pada saat Expad dijalankan muncul pesan
kesalahan "Segmentation Fault". Mengapa ?
Jawab: Penyebab paling utama biasanya adalah ketidaksinkronan antara file hasil MOC
dengan file header. Solusinya gampang: jalankan make clean terlebih dahulu sebelum
make.

Tanya: Sering muncul warning seperti ini: const char * configure_xpm[27] defined but
not used saat mengkompilasi Expad. Apakah ini aman?
Jawab: Ini terjadi karena beberapa definisi pixmap di file header icons.h tidak
digunakan semua. Bisa Anda lihat, toolbar Expad ini lebih sederhana dibandingkan
program contoh yang pernah dimuat di edisi kedua, bukan ? Lepas dari masalah itu,
warning tersebut bisa diabaikan saja.

Tanya: Apakah source code untuk Expad juga diedit dengan Expad ?
Jawab: Tentu saja tidak. Hal ini serupa dengan lingkaran ayam dan telur. Bagaimana
Expad bisa digunakan kalau source codenya sedang dibuat ?

Tanya: Bagaimana membubuhkan kemampuan color syntax highlight seperti yang lazim
dijumpai di editor yang canggih ?
Jawab: Untuk ini Anda harus merancang kelas Editor yang digunakan, tidak bisa
langsung diturunkan dari QMultiLineEdit begitu saja. Walaupun ini pekerjaan berat
namun bukan berarti mustahil untuk dilakukan. Silakan mengambil contoh dari program
lain yang punya fasilitas serupa seperti Freddy (freddy.sourceforge.net) atau Kate

Created By Muhammad Syahrizal 121


(kate.sourceforge.net).

Tanya: Saya sudah berhasil pula melakukan kompilasi Expad di Windows akan tetapi
mengapa di titlebar selalu ada imbuhan [Freeware] ?
Jawab: Hal ini sebuah keterbatasan karena digunakan Qt Windows edisi non-komersial
(QT-NC). Jika Anda ingin menghilangkannya silakan gunakan Qt Windows yang lisensi
penuh (dan membayar lebih dari USD 1500 untuk itu). Untuk lebih rincinya, lihatlah
FAQ mengenai ikhwal ini di www.trolltech.com/developer/faq/noncomm.html.

Sejarah KDE

KDE (K Desktop Environment), sebuah lingkungan desktop yang terkenal stabil, mudah
digunakan, dan cocok untuk pemula adalah proyek open-sourcebesar dengan 800 lebih
kontributor dan 2,6 juta baris program. KDEtidaklah serta merta muncul begitu saja
seperti mainan seorang pesulap.Sejak kelahirannya Oktober 1996, proyek KDE sudah
melewati masa balitanyadengan peluh dan segala kericuhan. Tulisan ini
mencobamengangkat beberapa sisi lain dari hikayat perjalanan KDE, mulai darikelahiran
hinggaperkembangannya.

Dari Tubingen ke Penjuru Dunia

Matthias Ettrich adalah seorang mahasiswa Universitas Tubingen, Jerman yang di


pertengahan tahun90-an dikenal sebagai programer LyX. Ketika masa-masa penggunaan
TeX sebagai typesetter yang profesional merambah ke mahasiswa, Matthias melihat
bahwa ada hal yang masih lowong dengan LaTeX: sebuah antarmuka grafis. Tidak ada
yang menyangkal bahwa cetakan hasil typesetting LaTeX sungguh berkualitas, akan
tetapi banyakpula yang mengeluhkan susahnya menggunakan LaTeX sehari-hari.
Memang, bagi kebanyakan orang menjalankan perintah baris yang penuh dengan trik
sana-sini lebih mirip dengan pekerjaan seorang programer tatkala melakukan
compileprogramnya.
LyX adalah aplikasi kecil yang akhirnya menjadi 'bayi' kesayangan Matthias. Apayang
ditawarkan LyX sesungguhnya relatif sederhana: kemudahan menyusun dokumen
dengan tampilan grafis yang menggunakan menu dan fitur ala WYSIWYG (What YouSee
Is What You Get). Namun, sebenarnya sendiri LyX adalah front-end untuk LaTeX.
Dengan kata lain, LyXtetap memanfaatkan LaTeX manakala akan mencetak dokumen.
Hasil akhirnya,seorang user bisa menikmati kecanggihan LaTeX namundengan
kemudahanantarmuka grafis.

Bersyukurlah bahwa Matthias Ettrich tidak berhenti hanya dengan LyX. Di satu
masasekitar musim gugurtahun 1996, ia mengirimkan e-mail ke mailing-list LyX:
To: lyx@via.ecp.fr
Subject: Kool Desktop Environment
From: ettrich@peanuts.informatik.uni-tuebingen.de
Date: Mon, 14 Oct 1996 15:19:00 +0100 (MET)
Reply-To: lyx@zen.via.ecp.fr
Sender: owner-lyx@zen.via.ecp.fr
Hello,
I try to start another project with the goal to make Unix/X11 more
userfriendly. I just want to start this and do little coding, most
of my programming time will still go into the LyX development.
yang diikuti dengan penjelasan panjang lebar mengenai visinya sendiri tentang

Created By Muhammad Syahrizal 122


KoolDesktop Environment, proyek yang sasarannya adalah membuat Unix menjadi
ramah dan mudah digunakan (user-friendly). Belakangan nama Kool
DesktopEnvironment ini diringkaskan menjadi KDE saja, dan malahan akhirnya K pada
KDE tidak lagi berasosiasi dengan Kool.

Karena tujuannya yang relatif ambisius, tentu saja makan waktu cukup lama bagi tim
KDE (yang dikepalai oleh Matthias) untuk menelurkan versi pertama dari KDE.Apalagi,
karena betul-betul dibangun dari awal, maka terdapatbanyak sekali pekerjaan-pekerjaan
berat (yang sifatnya membangun fondasi dasar) yang harusdikerjakan dengan
sungguh-sungguh. Tim ini juga memutuskan untuk menggunakanberbagai lisensi
perangkat lunak open-source untuk KDE dan infrastrukturnya.
Setelah penuh perjuangan mendesain, memprogram, dan menyusun berbagai komponen
yang diperlukan bagi terwujudnya sebuah lingkungan desktop, makamusim panas
tahun1998 menandai dilepasnya KDE 1.0, versi stabil pertamayang dapat diinstalasi dan
dinikmati oleh pengguna Linux. Tidak hanya itu,KDEjuga tersedia untuk varian Unix
yang lain, antara lain FreeBSD,HPUX, dan Sun Solaris.

Tampilan KDE 1.0

KDE versi pertama ini terdiri atas beberapa perangkat dasar. Sesuai namanya, yang
utama ditawarkan KDE adalah lingkungan desktop yang modern,mencakup sistem menu
(KStart), panel seperti taskbar-nya Windows(KPanel), serta window manager (KWM).
Sebagai catatan,sungguhpun KDE mempunyai window managernya sendiri, yakni
KWM, tidak adamasalah jika KDE digunakan bersama window manager lain seperti
WindowMaker atau Enlightment.

Di samping lingkungan desktop, KDE juga menawarkan sejumlah aplikasi yang sangat
bermanfaat. Ada file manager untuk mengurusi file dan harddisk, ControlCenter guna
mengatur berbagai konfigurasi sistem (KControl), imageviewer untuk melongok isi file
gambar , terminal emulator bernama Konsole, e-mail client (KMail), dialer (kppp),
organizer (KOrganizer) dan puluhan aplikasi lainnya. Selain memiliki konsistensi
tampilan (dalam soal menu, ikon, dantata warna), kesemua aplikasi ini juga saling
terintegrasi dengan baik.Sebagai contoh, mengklik file PNG di file manager akan
otomatik mengeksekusi image viewersehingga isi file PNG tersebut bisa dilihat dengan
mudah.

Rendah Hati, Bertangan Dingin

Banyak orang bilang bahwa programer, hacker, developer, maupun jagoan


komputer biasanya congkak danbanyak omong. Nah, Matthias Ettrich adalah
kebalikan dari semua itu. Mengenang perjumpaan penulis dengan Matthias
sekitar dua tahun yang silamdi Karlsruhe, mudah untuk diamati bahwa
memang kesan penampilan yangramah dan menarik langsung tersiratkan
dalam dirinya. Matthias juga samasekalitidak sombong dan malahan
cenderung pemalu sehingga bahkan banyakyang tidak tahu (dan tidak menyangka)
bahwa LyX dan KDE lahir dari tangan dinginnya. Setelah menyelesaikan studi di
UniversitasTubingen, kini Matthias bekerja di Trolltech untuk terus memoles Qt menjadi
toolkit yangprofesional.
Keseragaman dan kerjasama yang baik antar aplikasi KDE dimungkinkan karena

Created By Muhammad Syahrizal 123


kesemuanya dibangun dengan menggunakan pustaka standar KDE, yang lazim disebut
sebagai kdelibs.Pustaka ini mencakup kumpulan rutin yangdibutuhkan untuk
pemrograman aplikasi grafis, fitur network, dan interaksi dengan pengguna. Kehadiran
pustaka seperti ini telah dinanti-nanti oleh banyak orang, terutama programer yang
berkehendak membangun aplikasi berbasis grafis dengan mudah dan nyaman.
Karena menawarkan sesuatu yang baru dan memikat, KDE 1 cepat sekali menarik
perhatian orang. Tercatat SuSE, sebuah distro yang bermarkas di Jerman, menyertakan
KDE 1 pada SuSE versi 6.0. Di sisi lain, meski Red Hatsaatitu belum melirik KDE,
instalasi KDE 1.0 dalam bentuk paket RPM tidakresmi plus petunjuk instalasinya untuk
Red Hat 5.2 telah tersedia danlangsung dicoba oleh banyak orang. Pun tersedia
paket-paket serupa untukdistro lain.

Di sisi lain, kesuksesan KDE 1 tidak membuat tim programer KDE (yang akhirnya kian
bertambah) lantas ongkang-ongkang kaki. Melalui serangkaiankerja keras yang penuh
semangat, versi perombakan pertama yang dirilissebagai KDE 1.1 hadirbulan Februari
1999, yang disusul dengan perbaikankecil (KDE 1.1.1) bulan Mei dalam tahun yang
sama. Tidak kurang, berbagaimedia pun mulai meliput kehadiran sang pendatang baru
ini, mulai darimajalah LinuxJournal, eksebisi LinuxWordExpo, hingga arena CeBIT
1999 diHannover. Walhasil, beberapa penghargaan juga berhasil diraih,antara lain
LinuxWorld Editor Choice Award 1999, "SoftwareInnovation of theYear" CeBIT 1999,
dan Linux Journal 1999 Readers'Choice.

K = Kontroversi ?

Bahagiakah semuanya dengan kedatangan KDE ? Ternyata tidak. Beberapa orang,


termasuk RichardStallman, yang dengan keras menyuarakan kampanye Free Software
menolak kehadiran KDE. Hal ini bukan karena KDE itusendiri yang nyata-nyata
merupakan perangkat lunak yang bebas dan open-source. Alasan utamanya adalah bahwa
mereka tidak merasa nyaman karena KDE dibangun dengan toolkit bernama Qt, keluaran
dari Trolltech AS, sebuah perusahaan software di Oslo, Norwegia. Hingga saat itu, Qt
bukanlah merupakan pustaka yang bersifat open-source. Walhasil, meski KDE
benar-benar tergolong open-source, kehadirannya sendiri ditentukan oleh keberadaan Qt
yang komersil. Di sisi lain, ada pula orang-orangyang tidak peduli dengan urusan lisensi
seperti misalnya Linus Torvalds yang memberikan komentar:
My opinion on licenses is that "he who writes the code gets to
chose his license, and nobody else gets to complain". Anybody
complaining about a copyright license is a whiner.
Persoalan Qt ini meluas sehingga akhirnya muncullah berbagai gagasan untuk mengatasi
permasalahan ini. Yang paling sederhana tentu adalah dengan membuat Qt
menjadisebuah produk open-source. Trolltech sendiri telah diminta oleh berbagai
kalangan untuk melakukannya. Akan tetapi, karena model bisnis Trolltech
tidakmengijinkan hal ini, maka keinginan tersebut tidak dapat diakomodasi.
Lahir pulalah sebuah proyek yang bernama Harmony. Tujuannya adalah menciptakan
versi Qt yang open-source. Pengembangannya sendiri benar-benar di luar Trolltech
dantidak bersangkut paut dengan Qt yang asli. Diharapkan, jika kelak proyek Harmony
tuntas, maka semua perangkat lunak yang memanfaatkan Qt (jelas termasuk KDE) dapat
dialihkan untuk menggunakan pustaka Harmony tanpa perlu mengubah programnya
sedikit pun. Idenya kurang lebih serupa dengan Mesa3D yang merupakan implementasi
open-source dari OpenGL. Dalam perkembangannya, proyek Harmony tidak menarik
bagi banyak developer sehingga mati perlahan-lahan dan resmi ditutup pada Januari

Created By Muhammad Syahrizal 124


1999.

Titisan Viking
Norwegia, negara yang mojok di utara Eropa ini barangkali populer karena bangsa
Vikingnya yang melegenda, sebut saja Eric Si Merah yang menguasai Greenland. Kisah
kerakyatannya juga tidak kalah masyhur, trollalias monster kuno yang mengerikan (dan
setidaknya dicukilkan di Lord of TheRing dan Harry Potter) disebut-sebut berasal dari
daerah mereka. Di abad informasi seperti sekarang, Norwegia bagi kalangan pengamat
software sering langsung terasosiasikan dengan Trolltech, sebuah perusahaan yang
bermarkas di Oslo dan memproduksi tookit bernama Qt (perhatikan sama namaTrolltech
yang masih mengandung troll). Tetapi tunggu dulu, dikota yang sama ada pula Opera
Software yang menghasilkan Opera, browser yang mengklaim diri sebagai yang tercepat
di muka bumi. Bukan kebetulan kalau versi Linux dari Opera dikembangkan
menggunakan Qt. Selain berlandaskan justifikasi teknis, langkah demikian juga seakan
ingin mempertontonkan kekompakan mereka, cucu-cucu bangsa Viking.
Pilihan lain yang akhirnya sukses adalah mengembangkan lingkungan desktopalternatif
yang sejajar dan dapat menggantikan KDE. Inilah yang dirintisoleh Miguel de Icaza
dengan proyek GNOME (GNU Network ObjectModel Environment). Diluncurkan
Agustus1997, GNOME dirancang untuk menjadi produk yang benar-benar sesuai standar
Free Software Foundation. Karenanya, toolkit grafis yang dijadikan pendukung GNOME
adalah GTK+, yakni sebuah pustaka yang sebelumnya dikenal sebagai fondasibagi GIMP
(GNU Image Manipulation Program), yang benar-benarfree software (dengan lisensi
LGPL).

Kehadiran proyek GNOME dan berbagai tekanan-tekanan dari para advokat perangkat
lunak akhirnya mencairkan sikap Trolltech. Akhirtahun 1998, mereka akhirnya
memutuskan untuk melepaskan versi Qt untuk Unix/X11 dengan QPL (Qt
PublicLicense) yang menjadikanQt sebagai produk open-source. Sekitar dua tahun
kemudian, Trolltech juga menambahkan pilihan kemungkinan lisensi dengan GNU
GPL(General Public License)versi 2.
Tentu saja, Qt yang menjadi open-source tidak menyebabkan proyek GNOME
berhenti.Karenasudah terlanjur jalan, maka melewati masa-masa awal
pengembanganyangberliku-liku, tim GNOME dengan komandan Miguel de Icaza
akhirnyamelepas GNOME1.0 pada bulan Maret 1999. Rilis yang dilakukan
diLinuxWord Expo ini gaungnyamendunia dan memikat berbagai pihak yangmencari
alternatif dari KDE.

GNOME yang menjadi pesaing KDE

Persaingan antara KDE dan GNOME semakin diperpanas ketika Red Hat mengemas
GNOME sebagaipilihan default. Linux Mandrake, sebuah distro yangsekarangdikenal
user-friendly, mulanya sendiri lahir sebagai varian Red Hat tetapi menggunakan KDE
sebagai default, versi paling awalnya keluar di bulan yang sama dengan dirilisnya KDE1.
Sementara itu, SuSE tetap setia dengan KDE bahkan hingga saat sekarang.
Banyak pihak yang melihat bahwa perseteruan KDE vs GNOME sebagai hal yangburuk.
Jikalah kedua tim bergabung, maka tentu hasilnya akan lebih dahsyat dan tidak akan
energi yang terbuang percuma. Di sisi lain, justruadanya persaingan seperti ini akan
memancing kemunculan inovasi yangmembuat masing-masing kubu menjadi semakin
kompetitif. Sementara itu,secara teknis sendiri tim developer KDE dan GNOME

Created By Muhammad Syahrizal 125


menggunakan pendekatandan teknologi yang berbeda, dan sudah barang tentu akan
memakan waktu dantenaga untuk saling diselaraskan.
Bagi kebanyakan pemakai komputer, baik KDE ataupun GNOME bisa saja
dianggapsebagai berkah. Toh, kelebihan penggunaan free software adalahadanya
kebebasan penuh. Yang tidak suka KDE tinggal beralih ke GNOME,sementara itu yang
merasa seleranya tidak pas dengan GNOME bisa menggunakan KDE. Benar-benar
pilihan yang bebas !

Setelah edisi pertama lepas, para developer KDE yang jumlahnya sedikit demisedikit
bertambah memfokuskan diri untuk KDE 2. Berbeda dengan KDE 1,maka KDE 2
akandibangun berlandaskan Qt 2. Dibandingkan pendahulunya,versi kedua dari Qt
inimempunyai banyak fitur baru seperti misalnyadukungan Unicode, theme, XML,
danbanyak hal lagi.

KDE 2: Serasa Terlahir Kembali

Mengingat beberapa bagian utama dari Qt 2 sama sekali berbeda dengan Qt 1, mautidak
mau KDE juga mengalami perombakan total. Tidak salah jika dikatakanbahwa KDE 2
adalah versi yang benar-benar baru, berbeda total dengan KDE 1.Tentu saja,
pengembangannya sendiri tetap menyandang tujuan yang tetapsama: menghadirkan
antarmuka grafisyang nyaman dan mudah digunakan.
Beberapa bagian internal KDE juga harus ditulis ulang, baik karena desain awalyang
salah maupun demi efisiensi yang lebih baik. Sebagai contoh, panel di KDE 1 telah
menjelma menjadi Kicker di KDE 2 yang lebih tangkas danmenarik. Teknologi
pendukung seperti KIO pun dibangun untuk memudahkan akses data dengan mudah
keberbagai device, seperti disket, drivejaringan, share pada Windows SMB,d an bahkan
akses data via protokolseperti HTTP dan FTP.
Sadar bahwa Internet adalah tren masa depan, tim KDE juga merancang lingkungan
desktop yang bersifat Internet-ready. Walhasil, dimulailah polesan yanglebih baik
terhadap KMail dan KNode yang menjadi programfavorit untuk akses e-mail dan
newsgroup. Penggunaan KIO dengan baik juga menghasilkan network-transparencyyang
sangat mendukung penggunaan sebuah desktop oleh pemakainya. Sebagai ilustrasi, saat
mengedit sebuahfile, akan sama saja prosedurnya apakah file tersebut bercoko
ldiharddisk lokal maupun tersimpan server FTP yang remote. Tidak perlu repot-repot
upload secara manual.

Generasi kedua KDE

Beberapa programer juga menyadari pentingnya keberadaan sebuah browser web yang
bisa diandalkan. Microsoft mengemas Internet Explorer sebagai bagian dari Windows,
jadi mengapa hal yang sama tidak bisa dilakukan untuk KDE ? Mengingat ketika sekitar
tahun 1999 Mozilla baru dilepas dari Netscape dan terbukti sama sekali tidak stabil, tim
KDE memutuskan untuk mengembangkan sendiri engine untuk membangun sebuah
browser web yang mendukung penuh HTML 4 dan CSS (yang akhirnya dibaptis sebagai
KHTML). Aplikasi baru yang bernama Konqueror muncul ke dunia, sebuah file manager
yang juga browser web (yang pastilah memanfaatkan KHTML).
Seiring dengan semakin stabilnya fondasi lingkungan desktop yang dibangun oleh
berbagailibrary KDE, maka sekelompok programer KDE juga mulai memikirkan untuk

Created By Muhammad Syahrizal 126


mengembangkan tambahan aplikasi KDE yang lebih serius. Karena dunia Linux miskin
dengan IDE(Integrated Development Environment) yang notebene sangat berfaedah
untuk para developer, maka hadirlah KDevelop, sebuah IDE modern yang berbasis KDE.
Dikemas bersama KDE 2, debut pertama KDevelop (juga dilengkapi debuggeryang
terintegrasi) langsung membuat gebrakan yang manis dan lekas menjadi pilihan banyak
programer tatkala ingin mengembangkan aplikasi grafis untuk Linux.
Sebagai sang pendahulu, KDE 1 sering dicemooh terlalu mencoba tampil mirip dengan
Microsoft Windows. Melalu dukungan widget style yang ada ditawarkan Qt2, maka KDE
2 tidak lagi dapat disebut sebagai tiruannya Microsoft Windows.Dengan berbagai pilihan
style yang ada, sebuah desktop yang menggunakan KDE 2 bisa saja dibuat serupa dengan
Mac, Windows, BeOS, Motif, atau berbagai ragam pola tampilan yang lain. Kalau
sebelumnya KDE 1 masih mentoleransi user dengan keterbatasan warna pada
monitornya, maka seiring dengan meluasnya kartu grafisyang menghadirkan kekayaan
True Color, maka KDE 2 juga menghadirkan ikon dan tata warna yang lebih kaya akan
nuansa.
Kira-kira setahun menjelang rilis, diselenggarakan pula KDE Two, sebuah hackfest di
Erlangen, Jerman yang tidak hanya untuk mengikuti tradisi KDE 1.x, tetapi juga menjadi
ajang tukar pikiran sejumlah developer inti KDE yang memang kebanyakan berdomisili
di Eropa.
Belakangan terbukti bahwa menulis ulang KDE sehingga dapat memanfaatkan
sepenuhnya kekuatan Qt 2 memakan waktu dan energi yang besar. Berbeda dengan
KDE1.x yang relatif sederhana, KDE 2 adalah proyek yang lebih serius. Developernya
juga semakin tidak main-main, sebelum akhirnya dirilis Oktober 2000, KDE 2 telah
melewati 5 versi beta dan 1 RC (Release Candidate). Ketika itu adalah Waldo Bastian
(yang bekerjadi SuSE) bertindak selaku sang release coordinator.
Karena meningkatnya dukungan Unicode, maka KDE mulai dapat digunakan
dinegara-negara yang menggunakan aksara non Latin, seperti misalnya Arab, Jepang,
Korea, Rusia,Cina, dan banyak lagi. Memang, standar Unicode mengijinkan karakter
yang lebih universal (yang tidak akan tertampung oleh himpunan karakter ASCII
semata). Hal ini juga berarti secara langsung basis pengguna KDE meningkat drastis,
tidak melulu mereka yang memanfaatkan huruf-huruf Latin saja.
Sekali lagi, kesuksesan rilis KDE 2 juga menyebabkan beberapa perhargaan berhasil
disabet, antara lain Show Favorite dan Linux Community Award diajang LinuxWorld
Expo 2000, Frankfurt, baik Editor's Choice 2000 maupun Reader's Choice 2000 dari
LinuxJournal, Best Open Source Project di LinuxWord Expo 2001 San Francisco,
Reader's Choice Award dari LinuxJournal 2001, dan masih banyak lagi.
Beberapa versi perbaikan yaitu KDE 2.1 dan KDE 2.2 juga menyusul rilis KDE 2.0.
Selain perbaikan bug, terdapat juga penambahan fitur dan optimasi di versi-versi tersebut,
antara lain dengan hadirnya KPersonalizer untukmelakukan kustomisasi desktop dengan
cepat, restrukturisasi Control Center untuk kemudahan, serta peningkatan kualitas
Konqueror.

Tonggak Sejarah KDE

Oktober 1996: KDE lahir dari inisiatif Matthias Ettrich


Agustus 1997: KDE-One, hackfest pertama di Arnsberg (Jerman)
Juli 1998: Versi pertama, KDE 1.0 dirilis setelah 4 versi Betanya diujikan dalam 7 bulan
terakhir
Februari 1999: KDE 1.1, versi perbaikan dari KDE 1.0

Created By Muhammad Syahrizal 127


Oktober 1999: KDE-Two, sebuah acara hack-fest diselenggarakan di Erlangen (Jerman)
September 2000: Trolltech mengumumkan bahwa Qt resmi dilisensi menggunakan GNU
GPL (General Public License)
Oktober 2000: KDE 2.0 dilrilis (setelah melalui 5 versi Beta dan satu Release Candidate)
Februari 2001: KDE 2.1
Agustus 2002: KDE 2.2
April 2002: Generasi ketiga, KDE 3.0 dirilis
Maret 2003: KDE 3.1: stabil, aman, indah

Teknologi KParts untuk Konqueror dan KOffice

Yang namanya teknologi komponen ternyata mulai menjamur. Berbagai pihak yang
berkepentingan dengan pengembangan software hampir tidak melewatkan
kesempatanuntuk menanamkan investasi dalam penelitian di bidang ini. Bisa dimengerti,
dengan membuat sebuah aplikasi terdiri atas jalinan berbagai komponen yang saling
berinteraksi, hal tersebut akan meningkatkan modularitasnya. Belum lagi, kemudahan
mengembangkan satu komponen tanpa terlalu bergantung kepada komponen yang lain.
Tercatat Microsoft-lah yang gigih di garda terdepannya dengan teknologi COM
(ComponentObject Model) yang belakangan diimplementasikan dalam OLE (Object
Linking andEmbedding) dan ActiveX. Sederhananya, tatkala Anda menyisipkan sebuah
laporan keuangan Microsoft Excel dalam dokumen Microsoft Word, maka secara tanpa
sadar Anda sudah menjadi "korban" dari teknologi komponen ala Microsoft.
KDE pun tidak mau ketinggalan. Dipelopori oleh Torben Weis, dicanangkanlah proyek
kecil untuk menghasilkan teknologi komponen di KDE yang dinamakansebagai
OpenPart. Mula-mula OpenPart mengandalkan enkapsulasi interface dengan CORBA
(Common Object Request Broker Architecture) yang relatif populer di dunia middleware.
CORBA memang terbukti andal dan network-ready. Sayang, untuk penggunaan di dunia
desktop, OpenPart yang berbasis CORBA terlalu lamban, bahkan dengan hingga batas
yang susah ditolerir. Belum lagi kompleksitasnya yang cukup tinggi, membuat hanya
sedikit developer yang punya pengetahuan cukup untuk mengembangkan komponen
dengan OpenParts.
Walhasil, terjadilah perombakan besar-besaran. OpenPart ditulis ulang dan direinkarnasi
sebagai KParts. Terbukti, desain yang digagaskan dalam KParts terbilang sederhana dan
mudah dipelajari namun menyimpan potensi yang lengkap untukmembangun komponen
yang modern. Tidak hanya developer inti KDE seperti David Faure atau Simon
Hausmann (yang memang terlibat langsung dipengembangan KParts), banyak
programer KDE pun dapat mengambil manfaat dari teknologi KParts tanpa bersusah
payah menyelami intisari CORBA terlebih dahulu.
Bila Anda sesehari menggunakan Konqueror, maka sesungguhnya Anda telah
mendayagunakan kemampuan KParts. Sebagaimana telah disebutkan, KHTML adalah
engineyang digunakan Konqueror dan diimplementasikan sebagai sebuah komponen
KParts. Masih banyak lagi komponen lain, seperti misalnya untuk menampilkan citra,
mengedit file teks, GhostScript dan sebagainya. Tidak heran jika Konqueror
yangmendukung penuh KParts dapat bertindak sebagai universal viewer bagi file-file
yang dikenali KDE (dan tersedia komponennya). Klik saja sebuah file PDF dalam
Konqueror dan Anda akan dengan mudah melongok isinya. Hal yang sama untuk file
teks, citra JPEG, PNG, PostScript, dan sebagainya.
Konqueror: browser, file manager, sekaligus universal viewer
KOffice, sebuah proyek ambisius yang bertujuan menghasilkan paket office terintegrasi

Created By Muhammad Syahrizal 128


untuk KDE, ternyata juga aplikasi yang dibangun berlandaskan KParts. Pada rilis awal
KOffce 1.1, dengan David Faure yang saat itumasih bekerja untuk Mandrake berperan
selaku release coordinator, terdapatbeberapa aplikasi seperti KWord (pengolah kata),
KSpread (spreadsheet), KPresenter (presentasi), Kivio (diagram dan flowchart), serta
KIllustrator (grafik vektor). Walaupun masih terbilang belia, KOffice sudah cukup
fungsional dan memberikan harapan yang cerah di masa depan. Dengan berbasis KParts,
akan sangat mudah bagi aplikasi-aplikasi KOffice untuk saling bertukar data, seperti
misalnya menyisipkan lembar kerja KSpread di dalam dokumen teks di KWord.

Semakin Mantap dengan KDE 3

Kalau migrasi dari KDE 1 ke KDE 2 dirasakan sebagai perubahan yang


drastis,makaberalih dari KDE 2 ke KDE 3 tidaklah demikian. Hal ini juga dipengaruhi
kenyataan bahwa Qt 3 (yang menjadi fondasi KDE 3), secara hati-hati sudah dirancang
agar tidak membawa perbedaan yang berarti dengan Qt 2. Karenanya,proses rilis KDE 3
sendiri lebih cepat dan tidak lagi berlarut-larut. Hanya sekitar setengah tahun lepas dari
beredarnya KDE 2.2, KDE 3.0 sudah muncul kedunia, dengan Dirk Müller berperan
sebagai releasecoordinator.
Mengingat waktu pengembangannya sendiri relatif singkat, tersisa banyak fitur yang
diwariskan ke KDE 3. Walaupun demikian, perbaikan di sana sini (termasuk berbagai
bugfix) tetap dilakukan seperti peningkatan kecepatan JavaScript dan Dynamic HTML
untuk Konqueror, dukungan IMAP di KMail, style dan theme yang kian lengkap, dan
banyak lagi. Yang menarik adalah bahwa KDE 3 lebih cepat dan lebih irit memori
dibandingkan dengan versi sebelumnya, sesuatu hal yang jarang terjadi di dunia
perangkat lunak komersil.
Sebuah paket aplikasi yang bernama KDE Edutainment juga memulai kiprah pertamanya
berbarengan dengan KDE 3. Terdiri atas beberapa program "belajar sambil bermain",
KDE Edutainment sangat tepat untuk anak-anak dan kaum remaja. Lihat saja koleksi
aplikasinya, KTouch untuk latihan mengetik, KStar yang mensimulasikan peta langit,
KVocTrain guna melatih kosakata, dan banyak lagi.
KDE 3 pun membawa tingkat konfigurasi ke arah yang heboh. Sebuah situs web
www.kde-look.org muncul di tengah komunitas pengguna KDE yang
menawarkankoleksi berbagai macam goodies, mulai dari style baru yang bisa menyulap
KDE seindah MacOS, ikon-ikon bergaya Windows XP, tata warna alternatif, dan banyak
lagi.
Dan, setelah nyaris setahun, barulah keluar KDE 3.1, sebuah perbaikan atasrilis KDE 3.0.
Yang menyolok dari KDE 3.1 adalah karena waktu pengerjaannya cukup lama,bahkan
hingga melewati tiga versi beta dan tujuh RC (Release Candidate). Satu hal yang sempat
menunda rilisnya adalah dilakukannya security audit. Sebagaimana layaknya
sebuahperangkat lunak yang dilepas ke publik, keamanan adalah isu yang
mengingat.Tidak ada pengguna yang menginginkan lingkungan desktopnya mendadak
di-crack oleh pihak-pihak jahil, hanya gara-gara remote exploit yang belum dibenahi.

KDE 3.1, yang paling terbaru dari KDE.

Tentu, ada juga imbuhan segudang fitur baru di KDE 3.1 seperti
misalnyatampilanmodern dengan Keramik dan ikon Crystal, peningkatan kecepatan
Konqueror, kompatibilitas yang lebih baik di KHTML, dukungan KMail S/MIME untuk
attachment, fasilitas desktop sharing yang built-in, tambahan berbagai game, adanya

Created By Muhammad Syahrizal 129


download manager, dan banyak hal baru lainnya.

Perjalanan KDE yang telah melewati masa balitanya tidak membuat sekitar 800-an
kontributor KDE lantas menjadi berpuas diri dan berhenti berinovasi. Rencana dan
jadwal kegiatan sudah dibangun bersama-sama untuk generasi KDE berikutnya,
termasuk KDE 3.2 yang kemungkinan hadir sekitar musim semi tahun ini.
Beberapa tambahan aplikasi akan ikut menyemarakkan KDE 3.2, seperti misalnya
Kopete untuk instant messaging yang mendukung AIM, ICQ, Yahoo, dan banyak lagi
atau Umbrellountuk pemodelan dengan UML. Melongok kesuksesan Ximian dengan
Evolution-nya, tim KDE juga mencanangkan Kontact, aplikasi khusus PIM (Personal
Information Management) yang mirip-mirip dengan Outlook. Dengan menggabungkan
aplikasi mail, kalendar, dan dibubuhi dengan fitur groupware tentu diharapkan Kontact
dapat menjadi pertimbangan bagi mereka yang ingin bermigrasi dariOutlook.
Di tengah hiruk-pikut kampanye .NET oleh Microsoft, segelintir orang mulai
mengeksplorasibahasa C# (baca: C Sharp) yang diciptakan Microsoft khusus untuk
platform.NET-nya tersebut. Mono, sebuah program yang juga open-source, telah
merintis jalan panjang yang memungkinkan aplikasi .NET dijalankan di Linux, jelas
dengan menggunakan C#. Dalam kaitannya dengan KDE, binding dari C# ke Qt telah
berhasil diwujudkan denganproyek Qt#. Bukan mustahil bahwa dalam waktu dekat
KDE# juga akan lahir, yang berarti aplikasi KDE bisa dibangun dalam kerangka C#.
Generasi ketiga KDE dirumorkan akan berumur cukup panjang, bahkan mungkin hingga
versi3.6. Setelahnya, ketika Windows XP dan MacOS X mulai terasa usang, barulah
barangkali KDE 4 bakal lahir ke dunia. Kita nantikan bersama !

Membangun Aplikasi KDE dengan KDevelop

Linux adalah wahana pengembangan aplikasi yang memberikan banyak fasilitas. Selain
tersedianya GCC sebagai salah satu compiler yang modern, lengkap, dan andal, Linux
juga menawarkan ratusan pustaka (library) yang dapat dipergunakan untuk
mempermudah sekaligus mempercepat pengembangan sebuah aplikasi. Karena itu, sudah
selayaknya seorang programer dapat memanfaatkan pustaka-pustaka ini sembari
memperluas cakrawala pengetahuannya.
KDE yang merupakan akronim dari K Desktop Environment lebih dikenal sebagai
lingkungan kerja berbasis grafis. Selain menyediakan window manager, KDE juga
beragam aplikasi dalam aneka bidang, mulai dari file-manager, browser, hingga
program-program multimedia.
Yang tidak banyak disadari adalah bahwa KDE juga merupakan platform untuk
pengembangan aplikasi. Mengapa demikian ? Tidak lain adalah karena bersama KDE
terdapat juga pustaka-pustaka yang menjadi kerangka pembangun sebuah aplikasi
(application framework). Setiap sistem Linux yang menginstalasi KDE dipastikan
mempunyai pustaka-pustaka standar KDE, yang lumrahnya disebut sebagai kdelibs.
Bilamana Anda ingin membuat aplikasi dengan cepat dan tidak mau dipusingkan dengan
pengaturan antarmuka pemakai, akses berbagai fungsi sistem, pengolahan file, dan lain
sebagainya, Anda bisa memanfaatkan pustaka standar KDE ini.
KDE sendiri sebetulnya mengandalkan diri pada pustaka Qt (dari Trolltech) sebagai
fondasinya. Buat yang belum kenal, Qt dikenal sebagai toolkit untuk membangun
aplikasi yang lintas platform di Unix/X11, Windows, Mac, dan sistem embedded. Akan
tetapi, bagi sebagian besar developer KDE, bisa diklaim bahwa KDE bukanlah
semata-mata pustaka toolkit sebagaimana Qt. Hal ini berarti bahwa KDE tidak melulu

Created By Muhammad Syahrizal 130


menyediakan setumpuk fungsi-fungsi yang bisa digunakan dalam beragam library-nya,
tetapi juga menawarkan kerangka (framework) yang dapat dieksplorasi untuk
menghasilkan aplikasi-aplikasi GUI yang modern. Lepas dari faktor kecakapan
programmer yang menjadi salah satu penentu keberhasilan proses pengembangan sebuah
aplikasi, kekayaan library yang dipunyai oleh KDE plus kelengkapan dokumentasi
API-nya (yang bisa diakses dengan cuma-cuma) terbilang cukup menolong dan
menjadikan penyusunan suatu aplikasi menjadi perangkaian balok-balok dasar yang
memang sudah tersedia.
Tentu saja, kekayaan pustaka saja tidak akan cukup. Menyadari hal ini, tim KDE juga
merilis sebuah Integrated Development Environment (IDE) bernama KDevelop yang
bisa dipergunakan untuk membantu proses pengembangan aplikasi dengan lebih nyaman.
Bagi yang telah familiar dengan Microsoft Visual Studio, KDevelop ini tidak akan terasa
asing lagi. Fitur-fitur yang dimilikinya juga tidak kalah dengan Visual Studio, di
antaranya adalah project management, editor canggih dengan syntax highlight dan code
completion, debugger yang terintegrasi, class parser, akses ke dokumentasi Qt/KDE/C++
dengan cepat, penanganan configure/automake/autoconf, wizard, class generator, dan
masih banyak lagi.

Jika sudah terinstal dengan baik, KDevelop bisa dijalankan dari KDE dengan memilih
menu K, Development, KDevelop. Untuk pengguna Mandrake, menu ini bisa diakses dari
K, Applications, Development, Development environments, KDevelop. Bila baru pertama
kali ini Anda menjalankan KDevelop maka akan tampil aplikasi KDevelop Setup secara
otomatis (Gambar 1). Program kecil ini sendiri mirip dengan sebuah wizard, jadi tinggal
ikuti saja langkah demi langkahnya. Pada kebanyakan kasus, Anda hanya perlu mengklik
tombol Next hingga langkah terakhir.

Selanjutnya Anda akan dihadapkan dengan KDevelop dalam keadaan awal (Gambar 2).
Bisa Anda perhatikan bahwa penampilannya sangat serupa dengan Microsoft Visual
Studio. Tepat di bawah titlebar adalah sederetan tombol-tombol toolbar. Sebagaimana
umumnya toolbar, Anda cukup melewatkan pointer mouse di atas tombol-tombol ini
untuk mengaktifkan tooltip. Bagian kiri terdiri atas sejumlah tab yang masing-masing
ditandai dengan icon-icon tertentu, masing-masing untuk Classes, Groups, Files, dan
Books.

Supaya lebih jelas, Anda dapat mencoba membuat sebuah aplikasi KDE yang sangat
sederhana. Untuk ini, pilihlah menu Project, New yang digunakan untuk mengaktifkan
wizard pembuatan aplikasi baru (Gambar 3). Bisa dilihat bahwa wizard tersebut dapat
dipergunakan untuk membuat berbagai macam aplikasi, dari aplikasi KDE, Qt, GNOME,
dan juga aplikasi console biasa. Untuk contoh kali ini, pilihlah KDE2 Mini dan
selanjutnya klik tombol Next.

Selanjutnya Anda harus mengatur beberapa setting umum seperti nama aplikasi, direktori
kerja, nama pembuat, dan lain sebagainya (Gambar 4). Anda bisa mengikuti Gambar 4
dengan mengisikan Hello sebagai nama aplikasi. Sementara itu direktori kerjanya dapat
Anda tentukan sendiri, lantas klik tombol Next.
Dalam beberapa saat, wizard-nya KDevelop ini akan bekerja menyusun file-file yang
diperlukan, termasuk juga file-file automake dan autoconf, script konfigurasi, struktur
manual dan dokumentasi API, serta hal-hal kecil lainnya. Perbedaan KDevelop dengan

Created By Muhammad Syahrizal 131


Microsoft Visual Studio akan terlihat di sini, KDevelop menghasilkan dan mengolah
file-file yang diperlukan berdasarkan standar pengembangan aplikasi Unix (seperti
automake dan autoconf). Setelah pekerjaan kecil ini selesai, tinggal klik tombol Create
dan wizard pun selesai.

Sekarang KDevelop sudah mengaktifkan project baru yang bernama Hello tadi sehingga
tampilannya berubah menjadi seperti pada Gambar 6. Pada panel bagian kiri bisa Anda
cermati bahwa KDevelop sudah membuatkan dua file source-code yang diperlukan, yaitu
main.cpp dan hello.cpp. Sementara itu panel sebelah kiri menunjukkan editor yang
sedang memuat file hello.cpp.

Percaya atau tidak, dua file yang telah dengan baik hati dibuatkan oleh KDevelop ini
sudah memenuhi syarat sebagai aplikasi KDE. Untuk membuktikannya, Anda bisa
melakukan compile sekaligus menjalankannya dengan memilih menu Build, Execute
(shortcutnya adalah F9). Atau bisa juga dengan tombol Run di toolbar, yakni yang
iconnya bergambar roda gigi. Sementara proses compile dilakukan, perkembangan dan
statusnya bisa Anda lihat di panel kanan bawah pada tab Messages.
Bila tidak ada yang salah, artinya belum ada yang Anda utak-atik, mestinya program
Hello ini sudah tampak. Untuk menghasilkan sebuah aplikasi yang betul-betul punya fungsi,
tidak hanya sekedar menayangkan window kosong, Anda dapat memodifikasi file source
code main.cpp dan
hello.cpp. Karena KDE dan Qt dibangun dengan bahasa C++, maka mau tidak mau Anda
harus terlebih dahulu menguasai bahasa C++ ini. Di samping itu, untuk merancang
aplikasi yang menggunakan pustaka yang telah disediakan oleh Qt dan KDE, maka
prasyarat lainnya adalah sudah mengenali pustaka-pustaka tersebut. Sebagai langkah
awal, Anda bisa saja mempelajari Qt terlebih dahulu. Tutorial berseri tentang pengenalan
pemrograman Qt sempat dimuat di InfoLINUX, yaitu dari no 7/2001.
Guna bereksperimen sambil berkenalan dengan kelas-kelas C++ di Qt dan KDE, Anda
bisa memodifikasi program Hello sesuai panduan berikut ini. Mula-mula definisi kelas
Hello yang ada di file header hello.h mesti diubah. Asalnya kelas Hello ini diturunkan
dari kelas QWidget, yaitu kelas dasar untuk widget pada Qt. Sayangnya, kelas dasar
QWidget ini tidak banyak berguna. Karenanya lebih baik menggantinya dengan kelas
KMainWindow yang merupakan pembentuk window utama di sebuah aplikasi KDE.
Menyunting file hello.h bisa dilakukan dengan memilihnya dari daftar file (klik tab Files
di panel kiri). Editlah file tersebut sehingga menjadi seperti di bawah ini. Perhatikan
bahwa komentar pada bagian awal file (yang dihasilkan KDevelop) tidak dikutip di sini,
Anda bisa membiarkan sebagaimana adanya.
#ifndef HELLO_H
#define HELLO_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <kapp.h>
#include <qwidget.h>
#include <kmenubar.h>
#include <kmainwindow.h>
/** Hello is the base class of the project */
class Hello : public KMainWindow
{
Q_OBJECT
public:
/** construtor */
Hello(QWidget* parent=0, const char *name=0);

Created By Muhammad Syahrizal 132


/** destructor */
~Hello();
protected:
void initGUI();
void updateGUI();
void load( const char *fname );
void save( const char *fname );
private slots:
void fileOpen();
void fileSave();
private:
QString filename;
};
#endif

Dari kelas Hello yang baru ini dapat dicermati bahwa beberapa fungsi telah dibubuhkan,
yaitu initGUI() untuk inisialisasi antarmuka, updateGUI() untuk melakukan update
tampilan, serta dua fungsi load() dan save() yang mencontohkan cara memuat dan
menyimpan file. Sebagai tambahan, fungsi fileOpen() dan fileSave() merupakan slot
untuk menerima signal dari menu. Untuk lebih jelasnya mengenai signal dan slot, Anda
bisa merujuk ke tutorial pemrograman Qt di InfoLINUX no 7/2001 atau bisa juga di
dokumentasi Qt.
Selanjutnya, bagian utamanya yakni file hello.cpp juga diubah menjadi seperti di bawah
ini:
#include "hello.h"
#include <kfiledialog.h>
#include <ktoolbar.h>
#include <kstatusbar.h>
#include <kiconloader.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kmainwindow.h>
#include <kpopupmenu.h>
#include <kurl.h>
QString filter = "*.*|All";
Hello::Hello(QWidget *parent, const char *name) :
KMainWindow( 0, "Hello", WDestructiveClose )
{
initGUI();
updateGUI();
show();
}
Hello::~Hello()
{
}
// initializes user-interface
void Hello::initGUI()
{
KStdAction::open(this, SLOT( fileOpen() ),actionCollection(), "open" );
KStdAction::save(this, SLOT( fileSave() ),actionCollection(), "save" );
KStdAction::close(this, SLOT( close() ),actionCollection(), "close" );
actionCollection()->action("open")->plug( toolBar() );
actionCollection()->action("save")->plug( toolBar() );
KPopupMenu * file = new KPopupMenu( this );
menuBar()->insertItem( "&File", file );
actionCollection()->action("open")->plug( file );
actionCollection()->action("save")->plug( file );
actionCollection()->action("close")->plug( file );
menuBar()->insertItem( "&Help", helpMenu() );
}
// updates user-interface
void Hello::updateGUI()
{
setCaption( filename );

Created By Muhammad Syahrizal 133


}
// loads from file
void Hello::load( const char *fname )
{
// do file loading here
filename = fname;
// update caption and titlebar
statusBar()->message( filename + " loaded", 2000 );
updateGUI();
}
// saves to file
void Hello::save( const char *fname )
{
// do file saving here
filename = fname;
// update caption and titlebar
statusBar()->message( filename + " saved", 2000 );
updateGUI();
}
// opens and loads from file
void Hello::fileOpen()
{
KURL url;
url = KFileDialog::getOpenURL( QString::null, filter, this );
if( url.isEmpty() ) return;
if( !url.isLocalFile() ) return;
load( url.fileName() );
}
// saves to file
void Hello::fileSave()
{
KURL url;
url = KFileDialog::getSaveURL( QString::null, filter, this );
if( url.isEmpty() ) return;
if ( !url.isLocalFile() ) return;
save( url.fileName() );
}

Konstruktor kelas Hello cukup sederhana, yaitu hanya menginisialisasi tampilan dan
mengupdatenya untuk pertama kali. Sementara itu yang dikerjakan fungsi initGUI()
adalah membuat tiga action, masing-masing untuk fileOpen(), fileSave(), dan close().
Melalui kelas KStdAction, ketiga action dapat dipasangkan (plug) ke menu dan toolbar
dengan mudah. Di sisi lain, fungsi updateGUI() hanya akan memperbaharui caption dari
program jika filename berubah.

Baik fungsi load() dan save() pada program Hello di atas tidak melakukan operasi apapun
karena hanya berfungsi sebagai contoh. Kedua slot fileOpen() dan fileSave() akan
dipanggil dari action yang bersesuaian, lihat juga fungsi initGUI(). Pada badan fungsi
masing-masing hanya ada pemanggilan terhadap KFileDialog yang akan menghasilkan
kotak dialog untuk Load atau Save. Bisa dilihat, secara langkah demi langkah, memang
inilah yang akan terjadi pada aplikasi yang sungguhan.

Hingga saat ini, kalau Anda langsung melakukan compile kemungkinan Anda akan
menjumpai kesalahan karena pustaka yang bernama kfile belum di-link dengan program
Hello. Untuk mengatasinya, Anda harus mengubah pilihan linker yang digunakan. Pilih
menu Project, Options atau dengan shortcut F7 sehingga tampil kotak dialog Project
Options. Klik pada item Linker Options di daftar sebelah kiri dan selanjutnya tandai
checkbox yang bertuliskan kfile. Kalau tidak terjadi salah ketik ketika menyunting source-
code, mestinya program Hello

Created By Muhammad Syahrizal 134


sudah berubah menjadi seperti Gambar 9. Terlihat bahwa baik menu dan toolbar sudah
ada pada window program, bahkan kotak dialog Open atau Save sudah bisa muncul jika
tombol pada toolbar diklik. Mendistribusikan aplikasi yang Anda buat juga tidak kalah
gampang, tinggal pilih menu
Project, Make distribution. (yang sudah mengerti banyak tentang Makefile pastilah sudah
hafal cara lainnya: make dist). Selang beberapa saat file hello-0.1.tar.gz akan terbentuk
dan inilah tarbal dari source-code program Hello. Angka 0.1 di situ menunjukkan versi
0,1 (ingatlah langkah ke-2 dari Application Wizard). Anda sekarang bisa menyebarkan
tarbal ini, misalnya ke teman-teman yang juga menggunakan Linux. Bila ada yang
tertarik, mereka bisa mengambil tarbal tersebut, mengekstraknya dengan perintah tar zxvf
hello-0.1.tar.gz, menjalankan ./configure yang diikuti dengan make. Tentu saja, kalau
program Anda cuman sekedar menampilkan "Hello, world!" mungkin tidak banyak yang
akan terpikat mencobanya.

Kadang-kadang, meskipun telah mengenal sebagian pustaka Qt dan KDE yang paling
penting, keberadaan dokumentasi masih mutlak diperlukan. Tetapi jangan khawatir
karena KDevelop menyediakan fasilitas untuk mengakses dokumentasi ini dengan cepat,
bahkan tanpa berpindah dari KDevelop. Cukup aktifkan tab Dokumentasi (yang iconnya
bergambar buku terbuka) pada panel kiri sehingga akan didaftar berbagai macam
dokumentasi yang sudah diinstal di sistem Anda. Dari sini tinggal klik mana yang Anda
perlukan dan dalam sekejap panel sebelah kanan akan menghadirkan versi HTML dari
dokumentasi tersebut (Gambar 10), tinggal disimak dan dipahami baik-baik dan satu saat
Anda telah siap menjadi developer KDE. Selamat belajar !
Gambar 10. Mengakses dokumentasi Qt/KDE

Menggunakan Automake dan Autoconf

Tulisan ini berisi informasi tentang cara menggunakan automake dan autoconf. Kedua
utility ini dipergunakan guna menghasilkan suatu sistem pengkonfigurasi dan instalasi
aplikasi secara otomatis.
Untuk mempelajari automake dan autoconf, Anda tentunya harus sudah akrab dengan
metode pengembangan aplikasi menggunakan GNU C Compiler, yaitu yang berkaitan
dengan gcc, make, dan utility-utility lainnya. Hal ini diperlukan karena pada dasarnya
automake dan autoconf merupakan pelengkap bagi sistem pengembangan aplikasi ala
GNU.

Sekilas tentang automake dan autoconf

Rata-rata sebagian besar aplikasi Unix memiliki metoda compile dan instalasi yang sama.
Sebagai contoh, katakanlah terdapat sebuah utility yang dikemas dalam file distribusi
contoh-0.1.tar.gz. Cara melakukan compile dan instalasi adalah cukup dengan
perintah-perintah berikut ini:
tar zxvf contoh-0.1.tar.gz
cd contoh-0.1
./configure
make
make install
Perintah configure akan menjalankan sebuah script dan akan melakukan serangkaian
proses pendeteksian sistem Unix yang digunakan untuk mendapatkan informasi tertentu.
Dari hasil configure, maka akan terbentuk Makefile yang disusun berdasarkan

Created By Muhammad Syahrizal 135


template yang tersimpan di Makefile.in. Ketika Anda menjalankan make, maka proses
compile akan dimulai dan biasanya hal ini adalah untuk menghasilkan program utama.
Selanjutnya, untuk menginstal program contoh-0.1 ini, sekali lagi make harus
dijalankan dengan target bernama 'install'. Instalasi lumrahnya hanyalah proses
penyalinan file hasil compile ke direktori-direktori yang sesuai, program ke
/usr/local/bin, pustaka fungsi (library) ke /usr/local/lib, file-file header ke
/usr/local/include, serta panduan penggunaan ke ke /usr/local/man atau
/usr/local/info.
Terkadang, instalasi dapat saja tidak dilakukan ke /usr/local/. Sebuah program yang
ingin digunakan secara pribadi oleh user yang menginstal saja, dapat diinstal ke direktori
homenya, misalnya /home/ariya/. Dalam hal ini, satu-satunya yang dimodifikasi adalah
proses configure yang harus mengikutkan option untuk prefix, sebagaimana
ditunjukkan contoh berikut:
./configure --prefix=/home/ariya
Dapat dilihat bahwa proses compile dan instalasi sebuah program dari source codenya
relatif cukup mudah untuk dilakukan oleh user. Hal ini tidak lain karena proses
konfigurasi sudah dilakukan secara otomatis oleh si configure.
Misalkan Anda mempunya aplikasi yang Anda kembangkan sendiri, maka proses
compile dan instalasi aplikasi tersebut juga dapat memanfaatkan konfigurasi otomatis
dengan script configure. Hal ini dapat dilakukan dengan memanfaatkan automake dan
autoconf.
Automake adalah utility untuk mempermudah membuat Makefile. Bagi Anda yang
pernah menangani aplikasi yang cukup besar dan mencakup beberapa puluh (atau bahkan
ratusan) file, membuat dan mengelola Makefile merupakan pekerjaan yang menyita
waktu dan energi. Dengan automake, cukup didefinisikan beberapa hal yang perlu saja
maka akan dihasilkan sebuah Makefile yang lengkap untuk proses compile aplikasi
tersebut. Makefile yang dibuat juga bahkan telah dibekali kemampuan untuk
menghasilkan file .tar.gz, yang merupakan distribusi paket dari aplikasi yang
dikembangkan.
Autoconf adalah sekumpulan utility yang digunakan untuk memudahkan proses
konfigurasi program pada aneka varian sistem. Tanpa menggunakan konfigurasi yang
sesuai, maka program yang dirancang berjalan di berbagai platform harus melakukan
pendeteksian ragam sistem yang digunakan untuk menyesuaikan hal-hal khusus,
misalnya pendeteksian library yang dibutuhkan, panggilan fungsi ke pustaka tertentu,
inkompatibilitas antar fungsi, dan lain sebagainya. Autoconf dikemas dalam beberapa
program, mencakup autoconf, autoheader, autoscan, autoreconf, autoupdate, dan
ifnames.
Untuk programer sendiri, automake dan autoconf akan menguntungkan karena beberapa
hal, yaitu:
• Tidak perlu membuat Makefile secara manual. Bagi yang pernah terlibat pengembangan
aplikasi yang kompleks, dengan sekian belas sub-direktori, maka menghasilkan Makefile
yang tepat akan menyita banyak tenaga (belum lagi menentukan dependencies).
Automake akan membantu tahapan ini.
• Makefile yang dihasilkan automake sudah mempunyai target bernama install dan
uninstall. Keduanya akan digunakan oleh user untuk menginstal ataupun menghapus
instalasi program. Hal ini berarti programer tidak perlu lagi mengurusi soal instalasi ini.
• Makefile yang dihasilkan automake juga mempunyai target bernama dist. Target ini
digunakan untuk menghasilkan sebuah package dalam bentuk file tar.gz yang dapat
langsung didistribusikan.
• Untuk aplikasi yang dirancang portable di beberapa sistem Unix yang berbeda (misalnya

Created By Muhammad Syahrizal 136


AIX, Solaris, dan Linux), hasil konfigurasi dari configure akan berguna untuk
mereduksi sejumlah #ifdef yang lazimnya dimanfaatkan untuk mendeteksi dan
mengatasi perbedaan-perbedaaan di antara sistem Unix tersebut.

Instalasi

Sebelum dapat menggunakan automake dan autoconf, sistem Anda tentunya harus
dilengkapi dengan utility yang sesuai. Instalasi bisa dilakukan dari paket autotools. Jika
Anda menggunakan Red Hat Linux 6.1, maka cukup instal beberapa file RPM berikut ini:
autoconf-2.13-5.noarch.rpm
automake-1.4-5.noarch.rpm
libtool-1.3.3-1.noarch.rpm

Tentu saja, perangkat pengembangan program GNU C Compiler juga harus terpasang
terlebih dahulu. Hal ini mencakup compiler gcc (atau egcs atau pgcc) beserta
kelengkapannya. Jangan lupa untuk mengikutsertakan m4 di package
m4-1.4-12.i386.rpm. Ini adalah macro processor yang dibutuhkan oleh autoconf.
Bila Anda ingin melakukan sendiri proses compile, Anda harus mengambil source
codenya dari file tar.gz yang sesuai, kemudian melakukan configure, make, dan make
install. Sudah barang tentu paket autotools ini juga dibangun menggunakan autoconf
dan automake.
Source code beserta program lengkap plus dokumentasi autoconf dan automake dapat
diperoleh di situs web GNU (www.gnu.org).
Memodifikasi Aplikasi Lama
Aplikasi yang sudah ada dapat dengan mudah dimodifikasi agar memanfaatkan autoconf.
Syarat untuk ini adalah bahwa aplikasi Anda sudah memiliki Makefile yang digunakan
untuk melakukan make.

Berikut adalah langkah-langkah yang perlu dilakukan:


1) Paksa agar terdapat script untuk configure. Caranya adalah dengan perintah-perintah
berikut ini. Lakukan pada direktori yang menyimpan source-code dari aplikasi tersebut:
cp Makefile Makefile.orig
mv Makefile Makefile.in
autoscan
mv configure.scan configure.in
autoheader
autoconf
Catatan: Bila terdapat sub-direktori, maka yang harus dilakukan di masing-masing sub
direktori agak berbeda, yaitu cukup:
cp Makefile Makefile.orig
mv Makefile Makefile.in
autoheader
2) Modifikasi file configure.in. Hal ini dilakukan agar mudah melakukan rekonfigurasi
bila file *.in harus diubah lagi. Pada baris terakhir terdapat
AC_OUTPUT(Makefile)
Ini harus diubah menjadi:
AC_OUTPUT(Makefile, echo timestamp > stamp-h)
3) Nah, kini hasil autoconf siap untuk dicoba. Silakan jalankan:
./configure
Selamat ! Kini aplikasi Anda telah dapat dikonfigurasi otomatis. Namun demikian,
karena dalam kasus ini Makefile awalnya sudah tersedia, tidak dihasilkan dari automake,
maka belum tentu keseluruhan program dapat dipaketkan menjadi file distribusi dan
diinstal oleh user dengan mudah. Hal ini sangat tergantung bagaimana isi dari Makefile

Created By Muhammad Syahrizal 137


tersebut.

Membuat Aplikasi Baru

Membuat aplikasi baru agar menggunakan automake dan autoconf jauh lebih mudah
dibanding melakukan konversi aplikasi lama. Namun demikian, agar proses ini menjadi
mudah dipahami, berikut adalah hal-hal yang patut dijadikan pegangan:
• Script configure dihasilkan autoconf dari file configure.in
• Pada saat dieksekusi, script configure menghasilkan Makefile dari file
Makefile.in
• File Makefile.in dihasilkan menggunakan automake, untuk ini dibutuhkan
Makefile.am
Dapat dilihat bahwa yang perlu disediakan oleh sang programer hanyalah file
Makefile.am dan configure.in (serta source code program tentunya!).
Berikut adalah panduan langkah demi langkah untuk memulai aplikasi baru dengan
automake dan autoconf.
Mula-mula tentunya kita harus menulis source code untuk aplikasi baru tersebut. Karena
melibatkan sejumlah file, ada baiknya aplikasi ini diletakkan di direktori khusus. Berikut
adalah contohnya:
$ mkdir hello
$ cd hello
$ cat > hello.c
#include <stdio.h>
int main(int argc, char*argv[])
{
printf ("Hello, World ! (in autoconf)\n");
}
<Ctrl+D>
$
Contoh di atas hanya sekedar contoh. Tentunya Anda ingin membuat aplikasi yang lebih
bermanfaat dari sekedar "Hello, World!".
Secara manual, program di atas dapat dikompilasi dan dijalankan dengan cara:
$ gcc -o hello hello.c
$ ./hello
Dan akan muncul pesan (yang sangat terkenal) berikut ini:
Hello, World ! (in autoconf)
Sekarang, kita akan melakukan proses compile via automake dan autoconf. Untuk ini
diperlukan file Makefile.am dan configure.in.
File Makefile.am adalah sebagai berikut:
bin_PROGRAMS = hello
hello_SOURCES = hello.c
Sementara file configure.in adalah:
AC_INIT(hello.c)
AM_INIT_AUTOMAKE(hello,1.0)
AC_PROG_CC
AC_PROG_INSTALL
AC_OUTPUT(Makefile)

Penting untuk diingat bahwa file Makefile.am hanya akan berisi assignment, yaitu hanya
relasi-relasi saja dan bukan instruksi atau perintah untuk dijalankan (lazim juga dikenal
sebagai logic language). Sebaliknya, file configure.in berisi daftar instruksi yang
harus dieksekusi (procedural language).
Berikut adalah penjelasan ringkas dari hal-hal yang dikerjakan sebagai instruksi untuk
contoh file configure.in di atas:
• Instruksi AC_INIT dilakukan untuk menginisialisasi script konfigurasi. Untuk perintah

Created By Muhammad Syahrizal 138


ini, diperlukan nama file utama yang merupakan bagian dari source code.
• Instruksi AM_INIT_AUTOMAKE diperlukan karena di sini Makefile-nya dihasilkan dengan
automake. Bila Makefile.in dibuat manual, hal ini tidak perlu dilakukan. Yang perlu
diperhatikan di sini adalah bahwa argument pertama adalah nama paket programnya
(yaitu hello) sedangkan argument keduanya adalah nomor versi (dalam hal 1.0).
• Instruksi AC_PROG_CC memeriksa jenis compiler C yang digunakan.
• Instruksi AC_PROG_INSTALL mendeteksi kehadiran utility instal ala BSD. Jika hal ini
tidak tersedia, maka akan digunakan script install-sh sebagai gantinya.
• Instruksi AC_OUTPUT akan menghasilkan Makefile dan Makefile.in.
Karena standar GNU mensyaratkan beberapa file pelengkap, maka kita dapat membuat
file-file ini dengan cepat menggunakan perintah touch. Pada kenyataannya, mungkin
Anda sudah mempunyai file-file ini. Apabila tidak, maka gunakan perintah seperti
berikut:
$ touch NEWS README AUTHORS ChangeLog
Bila sebelumnya file-file ini tidak ada, maka kini file tersebut sudah muncul sendiri dan
mungkin kelak dapat Anda sunting agar berisi informasi yang (lebih) bermanfaat.
Yang tidak kalah pentingnya diperlukan adalah script install-sh. Tanpa script ini,
automake akan menolak untuk dijalankan. Script install-sh ini sendiri dapat didapat
dari berbagai program yang menggunakan automake dan autoconf (termasuk automake
dan autoconf sendiri!). Jika sistem Anda memiliki automake dan autoconf, maka script
ini biasanya bisa dijumpai di direktori /usr/share/automake. Silakan copy file ini ke
direktori yang sekarang aktif sehingga juga menjadi bagian dari program hello.
Nah, sekarang tiba bagian yang seru. Jalankan autoconf dengan perintah-perintah:
$ aclocal
$ autoconf
Apa yang sebenarnya terjadi ? Perintah aclocal menyiapkan file aclocal.m4. Secara
mudahnya, file ini diperlukan gara-gara adanya perintah AM_INIT_AUTOMAKE pada
configure.in. Selanjutnya perintah autoconf menggabungkan isi dari aclocal.m4 dan
configure.in serta menghasilkan script configure.
Tahap berikutnya adalah menjalankan automake:
[ariya@labkon hello]$ automake -a
automake: configure.in: installing `./mkinstalldirs'
automake: configure.in: installing `./missing'
automake: Makefile.am: installing `./INSTALL'
automake: Makefile.am: installing `./COPYING'

Pesan-pesan yang tampil adalah karena beberapa file-file tertentu tidak ada. Untungnya,
automake berbaik hati membuat file-file tersebut secara otomatis (karena digunakan
option -a).
Sekarang aplikasi hello ini sudah siap.
Untuk melakukan compile, tinggal dilakukan:
$ ./configure
creating cache ./config.cache
checking for a BSD compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... yes
checking for working aclocal... found
checking for working autoconf... found
checking for working automake... found
checking for working autoheader... found
checking for working makeinfo... found
checking for gcc... gcc
checking whether the C compiler (gcc ) works... yes
checking whether the C compiler (gcc ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes

Created By Muhammad Syahrizal 139


checking for a BSD compatible install... /usr/bin/install -c
updating cache ./config.cache
creating ./config.status
creating Makefile
$ ./make
gcc -DPACKAGE=\"hello\" -DVERSION=\"1.0\" -I. -I. -g -O2 -c hello.c
gcc -g -O2 -o hello hello.o
Yang dilakukan configure adalah mendeteksi platform sistem yang aktif, kemudian
menghasilkan Makefile yang tepat sebagaimana telah ditentukan dalam file
Makefile.in.
Lebih jauh, program hello ini bisa diinstal ke /usr/local/. Cukup dengan perintah:
# make install
make[1]: Entering directory `/home/ariya/hello'
/bin/sh ./mkinstalldirs /usr/local/bin
/usr/bin/install -c hello /usr/local/bin/hello
make[1]: Nothing to be done for `install-data-am'.
make[1]: Leaving directory `/home/ariya/hello'
(Dalam kebanyakan kasus, Anda harus login dahulu sebagai root agar bisa melakukan
install).
Hasil instalasi bisa diperiksa dengan:
$ /usr/local/bin/hello
Hello, World ! (in autoconf)
Membatalkan instalasi juga sama mudahnya. Cukup dengan:
# make uninstall
list='hello'; for p in $list; do \
rm -f /usr/local/bin/`echo $p|sed 's/$//'|sed 's,x,x,'|sed 's/$//'`; \
done
Maka file /usr/local/bin/hello akan hilang dalam sekejap.
Salah satu feature yang amat berguna adalah membuat file distribusi, yaitu source code
yang dikemas dalam file tar.gz (atau semacamnya). Hal ini bisa dilakukan dengan:
$ make dist
rm -rf hello-1.0
mkdir hello-1.0
chmod 777 hello-1.0
here=`cd . && pwd`; \
top_distdir=`cd hello-1.0 && pwd`; \
distdir=`cd hello-1.0 && pwd`; \
cd . \
&& automake --include-deps --build-dir=$here --srcdir-name=.
--output-dir=$top_distdir --gnu Makefile
chmod -R a+r hello-1.0
GZIP=--best gtar chozf hello-1.0.tar.gz hello-1.0
rm -rf hello-1.0
Proses ini akan menghasilkan file hello-1.0.tar.gz. Anda dapat memberikan file ini
kepada orang lain dan menyebutnya sebagai distribusi program hello. Yang tertarik dapat
memanfaatkan dan melakukan kompilasi program hello, cukup dengan perintah-perintah
tar zxvf, configure, dan make (sebagai sudah disebutkan di awal).

Menangani Aplikasi yang Kompleks

Langkah-langkah di atas sudah cukup memadai untuk pengembangan aplikasi yang


sederhana. Sekarang misalnya Anda mempunyai program yang source code tersebar di
beberapa direktori, menggunakan pustaka fungsi (library), campuran program C dan
C++, ataupun menggunakan lex (atau flex) dan yacc (atau bison), harus dilakukan
langkah-langkah tambahan.
Bila program Anda juga harus dicompile dengan C++ (atau berisi campuran file C dan

Created By Muhammad Syahrizal 140


CPP), maka yang harus ada pada configure.in adalah:
AC_PROG_CPP
Bila aplikasi yang akan dibangun membutuhkan library tertentu, hal ini dapat
dispesifikasi dengan relasi LDADD pada Makefile.am, contohnya adalah:
hello_LDADD = -lX11
Untuk menangani beberapa direktori, caranya cukup sederhana. Cukup ubah sedikit
instruksi AC_OUTPUT pada configure.in. Misalnya, kini terdapat sub direktori src/,
maka file configure.in harus menjadi:
AC_OUTPUT(Makefile src/Makefile)
Juga jangan lupa untuk membubuhkan relasi SUBDIRS pada Makefile.am, sebagaimana
contoh berikut:
SUBDIRS = src
Kemudian, pada sub direktori src/ ini juga harus terdapat Makefile.am yang tepat,
misalnya:
bin_PROGRAMS = hello
hello_SOURCES = main.c
Kelak pada saat automake dan autoconf dijalankan, sub direktori src/ akan ikut
ditelusuri sehingga dapat dihasilkan Makefile.in dan Makefile yang sesuai.
Bila aplikasi Anda menggunakan lexical analyzer dan semantic parser yang dikonstruksi
menggunakan flex dan bison (atau lex dan yacc), maka file configure.in perlu
disesuaikan dengan membubuhkan baris-baris berikut:
AM_PROG_LEX
AC_PROG_YACC
File input untuk flex dan bison tinggal dimasukkan sebagai bagian dari SOURCES
untuk aplikasi atau library (pada file Makefile.am), misalnya:
bin_PROGRAMS = hello
hello_SOURCES = main.c grammar.y parser.l

Catatan: automake mengasumsikan file .c yang dihasilkan dari .l dan .y adalah sama
dengan nama file sumbernya tetapi dengan mengganti suffiksnya (misalnya bslex.l
akan menghasilkan bslex.c).

Bila program Anda menghasilkan sebuah pustaka fungsi (library), maka configure
harus mampu menangani ranlib. Oleh karenanya, pertama-tama, jangan lupa tambahan
instruksi AC_PROG_RANLIB pada configure.in. Adapun relasi-relasi yang dibutuhkan di
Makefile.am untuk membuat sebuah library dicontohkan berikut ini:
lib_LIBRARIES = libfoo.a
libfoo_a_SOURCES = foo.c private.h
libfoo_a_LIBADD = objfile.o
libfoo_a_DEPENDENCIES = dep1 dep2
Berikut adalah penjelasan masing-masing relasi di atas:
• lib_LIBRARIES adalah mirip seperti bin_PROGRAMS tetapi kali ini berlaku untuk
pustaka fungsi(library). Di sini dapat didaftar library-library yang kelak akan diinstal ke
/usr/local/lib
• libfoo_a_SOURCES menentukan file-file source code untuk library bernama
libfoo.a. Dalam hal ini dapat juga dimasukkan file-file header yang merupakan bagian
dari source code, tapi tidak akan didistribusikan bersama libfoo.a.
• libfoo_a_DEPENDENCITES menentukan target lain yang harus tersedia terlebih dahulu
sebelum library ini dapat dihasilkan
• libfoo_a_LIBADD adalah untuk mendaftar file-file objek yang akan dianggap sebagai
bagian dari library ini.
Bila aplikasi Anda perlu menghasilkan library untuk program utama namun library
tersebut bukan bagian dari distribusi (tidak akan diinstal ke /usr/local/lib), maka
dapat digunakan relasi noinst_LIBRARIES pada Makefile.am seperti dicontohkan di

Created By Muhammad Syahrizal 141


bawah ini:
noinst_LIBRARIES = libdummy.a
libdummy_a_SOURCES = dummy.h dummy.c

Mengatasi Variansi Sistem

Telah disebut-sebut bahwa script configure akan mendeteksi jenis sistem dan platform
Unix. Hasilnya dapat digunakan agar program aplikasi untuk mengetahui dan menangani
variansi maupun ketidakkompatibelan antar sistem. Sebagai contoh, lazim dijumpai
bahwa program harus dapat bekerja pada sistem yang low-endian dan big-endian.
Autoconf dapat diinstruksikan untuk mendeteksi endianness dari sistem ini dengan
AC_C_BIGENDIAN. Bila ternyata sistem memang big endian, maka akan terdefinisi
WORDS_BIGENDIAN. Sebagai contoh, asumsikan terdapat program test.c sebagaimana
berikut ini:
#include <stdio.h>
int main(int argc, char*argv[])
{
printf ("Hello, World !\n");
#ifdef WORDS_BIGENDIAN
printf("Big Endian\n");
#endif
}
dengan instruksi AC_C_BIGENDIAN yang disisipkan pada configure.in (harus setelah
AC_INIT).

Setelah proses automake dan autoconf, akan dihasilkan script configure yang sudah
mampu mendeteksi endianness dari sistem. Ketika dijalankan, maka akan diperoleh:
creating cache ./config.cache
checking for a BSD compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... yes
checking for working aclocal... found
checking for working autoconf... found
checking for working automake... found
checking for working autoheader... found
checking for working makeinfo... found
checking for gcc... gcc
checking whether the C compiler (gcc ) works... yes
checking whether the C compiler (gcc ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
checking whether byte ordering is bigendian... yes
checking for a BSD compatible install... /usr/bin/install -c
updating cache ./config.cache
creating ./config.status
creating Makefile
Perhatikan bahwa sekarang terdapat baris yang menyatakan checking whether byte
ordering is bigendian....
Nah, sekarang apabila program test ini dicompile dan dijalankan, akan diperoleh hasil:
Hello, World !
Big Endian
bila memang proses konfigurasi, compile, dan instalasi dilakukan pada sistem yang big
endian (misalnya HP-UX dan SPARC). Akan tetapi, bila program yang sama
dikonfigurasi, dicompile, dan diinstal pada Linux untuk Intel Pentium, hasil yang
diperoleh adalah:
Hello, World !
Dari ilustrasi ini dapat disimpulkan bahwa penggunaan instruksi-instruksi tertentu
dengan autoconf akan memudahkan program yang dikembangkan untuk menyesuaikan

Created By Muhammad Syahrizal 142


diri dengan lingkungan (baik sistem operasi ataupun platform).
Disamping AC_C_BIGENDIAN, terdapat pula instruksi-instruksi lain yang cukup berguna.
Beberapa di antaranya disajikan di bawah ini (daftar lengkapnya sendiri dapat dilihat di
manual penggunaan autoconf).
AC_C_CHAR_UNSIGNED
Bila tipe char adalah unsigned, maka akan didefinisikan __CHAR_UNSIGNED__.
AC_CHECK_SIZEOF (type)
Ukuran dari tipe yang disebutkan (type) akan diletakkan pada definisi SIZEOF_xtype.
Ukuran ini dinyatakan dalam byte. xtype sendiri dibentuk dari type dengan mengubah
spasi menjadi garis bawah dan semuanya dalam huruf kecil. Untuk pointer, maka terdapat
prefix P. Sebagai contoh, pada HP-UX 10.x, AC_CHECK_SIZEOF(double) akan
menghasilkan SIZEOF_DOUBLE sebesar 8 dan AC_CHECK_SIZEOF(char*) akan
menghasilkan SIZEOF_CHAR_P sebesar 4.
AC_TYPE_SIZE_T
Bila size_t tidak didefinisikan, maka size_t akan dianggap sebagai unsigned.
AC_CHECK_HEADERS(headerfile)
Periksa headerfile, bila ada, maka akan didefinisikan HAVE_headerfile. Sebagai
contoh, AC_CHECK_HEADERS(unistd.h) akan menghasilkan HAVE_UNISTD_H jika
memang file unistd.h dijumpai pada sistem.
AC_CHECK_FUNCS(func)
Periksa apakah sistem mempunyai fungsi func. Bila ya, maka akan didefinisikan
HAVE_func. Sebagai contoh, AC_CHECK_FUNCS(memcpy) akan menghasilkan
HAVE_MEMCPY pada sistem yang mendukung ANSI C.
AC_CHECK_LIB(lib,func)
Periksa apakah terdapat fungsi bernama func pada library lib. Bila ada, maka akan
didefinisikan HAVE_lib. Contohnya adalah AC_CHECK_LIB(X11,XGetImage) akan
menghasilkan HAVE_X11 pada semua sistem yang mempunyai X Window.
Sebagai catatan akhir, dapat dilihat bahwa metoda di atas bekerja dengan memanfaatkan
option -D dari compiler (misalnya gcc). Hal ini akan jelas terlihat kalau Anda mengamati
output dari make.
Cara lain untuk mendapatkan definisi-definisi selain option -D adalah dengan meletakkan
semuanya pada file konfigurasi, biasanya adalah file config.h. Untuk dapat
menggunakan metoda alternatif ini, mula-mula sisipkan instruksi
AC_CONFIG_HEADER(config.h) pada configure.in. Selanjutnya, jalankan autoheader
sebagai berikut:
autoheader
Perintah di atas akan menghasilkan config.h.in yang merupakan template untuk
menghasilkan config.h
Sekarang modifikasi source code program untuk meng-include-kan file config.h.
Menyambung contoh sebelumnya, maka test.c sekarang menjadi:
#ifdef HAVE_CONFIG
#include <config.h>
#endif
#include <stdio.h>
int main(int argc, char*argv[])
{
printf ("Hello, World !\n");
#ifdef WORDS_BIGENDIAN
printf("Big Endian\n");
#endif
}

Setelah tahap ini selesai, jalankan kembali autoconf dan automake. Proses configure,
selain menghasilkan Makefile dari Makefile.in, juga memproses config.h.in untuk
menghasilkan config.h, yang akan berisi:

Created By Muhammad Syahrizal 143


/* config.h. Generated automatically by configure. */
/* config.h.in. Generated automatically from configure.in by autoheader.
*/
/* Define if your processor stores words with the most significant
byte first (like Motorola and SPARC, unlike Intel and VAX). */
#define WORDS_BIGENDIAN 1
Hasil akhirnya adalah sama. Namun tentu saja meletakkan semua definisi di file
config.h akan sangat menolong karena memudahkan debugging

Tanya Jawab (alias FAQ)


Mengapa harus menggunakan autoconf dan automake ?
Tidak harus, kok :-> Kedua utility ini hanya berfungsi sebagai alat bantu untuk
memudahkan dan tidak harus dipakai.
Utility aclocal tidak bisa dijalankan. Mengapa ?
Pastikan bahwa Perl terinstal pada sistem Anda.
Waktu menjalankan automake, tampil pesan kesalahan karena file install-sh tidak ada
? Bagaimana solusinya ?
File install-sh adalah sebuah script biasa. File ini dibutuhkan untuk proses konfigurasi.
Bila Anda tidak mempunyai file ini, silakan copy dari program lain. Lazimnya, program
yang dipaket menggunakan automake dan autoconf selalu menyertakan file ini.
Pada saat automake, muncul beberapa pesan "required file ... not found", tetapi
automake tidak mau membuat file tersebut secara otomatis. Mengapa demikian ?
Gunakan option -a saat menjalankan automake, jadi jangan jalankan 'automake' tetapi
'automake -a'.
Bagaimana mengatasi masalah yang muncul apabila program saya menggunakan bison.
Kemungkinan Anda lupa salah satu (atau kedua-duanya): menyisipkan relasi
AC_PROG_YACC di configure.in dan menambahkan source untuk bison (biasanya file
dengan ekstensi .y) ke bagian SOURCES di Makefile.am
Bisakah autoconf digunakan secara independen terhadap automake?
Bisa saja. Tentu Makefile yang dibuat sendiri harus mengenal substitusi variabel yang
akan dilakukan oleh configure. Silakan merujuk ke manual penggunaan autoconf untuk
lebih jelasnya.

Created By Muhammad Syahrizal 144


Daftar Pustaka :
1. Erlenkötter, Helmut. C++, Objektorientiertes Programmieren von Anfang an
2. http://infocom.cqu.edu.au/Staff/Mike_Turnbull/Home_Page/Lecturetts/Sect101.htm
3. http://www.aw-bc.com/catalog/academic/product/0,4096,0201895501-PRE,00.html
4. http://www.desy.de/gna/html/cc/Tutorial/node3.htm
5. http://www.uni-koeln.de/rrzk/kurse/unterlagen/CPPKURS/
6. http://www.uni-koeln.de/rrzk/kurse/unterlagen/CPPKURS/HTML/begriffe.htm
7. Hubbard, John R. Ph.D. Schaum’s Outlines. Programming with C++.
8. Bjarne Stroustrup, “The C++ Programming Language”, 3rd edition, Addison-
Wesley 1997
9. Scott Meyers,”Effective C++”, 2nd edition, Addison-Wesley
10. Scott Meyers,”More Effective C++”, Addison-Wesley
11. Q&A dalam C/C++ Users Journal.
12. GOF,”Design Pattern”, Addison-Wesley.
13. Chuck Allison, “Code Capsules: Visibility in C”, C Users Journal vol. 12 no. 4.
14. Chuck Allison, “Code Capsules: Visibility in C++”, C Users Journal vol. 12 no. 4.
15. Bobby Schmidt, “Completing the Foundation”, C/C++ Users Journal vol. 13 no. 12
16. Dan Saks, “Storage Classes and Linkage”, C/C++ Users Journal vol 15 no.11
17. Dan Saks, “Storage Classes and Language Linkage”, C/C++ Users Journal vol 15
no.12
18. MSDN, Q243241 INFO: C++ Standard Noncompliance Issues with Visual C++ 6.0
19. MSDN, Q167748 PRB: Variable Scope in for-statement Extends Beyond Loop
20. G. Bowden Wise, “Statics: Schizophrenia for C++ Programmers”, ACM
21. Andrei Alexandrescu and Petru Marginean, “Generic<Programming>: Simplify
Your Exception Safe Code”, C/C++ Users Journal C++ Experts Forum, December
1999.
22.Bjarne Stroustrup, “The C++ Programming Language”, 3rd Edition, Addison-
Wesley, 1997

Trolltech http://www.trolltech.com
K Desktop Environment http://www.kde.org
Dokumentasi Qt http://doc.trolltech.com
GIMP http://www.gimp.org
GNU Make http://www.gnu.org/software/make/make.html
Situs resmi GNOME - www.gnome.org
KDE untuk developer - http://developer.kde.org
KDevelop - www.kdevelop.org

Created By Muhammad Syahrizal 145


Qt dari Trolltech - http://www.trolltech.com/products/qt/
GNU autoconf Manual - http://www.gnu.org/manual/autoconf-2.13/autoconf.html
GNU automake Manual - http://www.gnu.org/manual/automake-1.3/automake.html
GNU Macro Processor Manual - http://www.gnu.org/manual/m4-1.4/m4.html
C-Scene: Multi-File Projects and the GNU Make Utility -
http://www.syclus.com/cscene/CS2/CS2-10.html
Learning autoconf and automake -
http://www.amath.washington.edu/~lf/tutorials/autoconf/
Learning the GNU Development tools -
http://www.st-andrews.ac.uk/~iam/docs/tutorial.html

Created By Muhammad Syahrizal 146


Profil Penulis :
Muhammad Syahrizal, kelahiran Medan 1981 ,meyakini bahwa buku adalah gerbang keberhasilan dan
meyakini perubahan hanya soal waktu,zaman tak bisa dilawan.

Masih Kuliah ditiga perguruan tinggi jurusan hukum, management dan Informatika sampai saat ini
sambil bekerja dan kuliah. Memiliki pengalaman Pendidikan Informal antara lain:Pelatihan Transaksi
Perdagangan Via E-commerce (Juni 2001),Pelatihan Dasar Jaringan dan Satelit (Agustus
2002),Pelatihan Dasar Unix Untuk Umum (September 2000),Pelatihan Kekuatan Hukum dalam Aspek
Regional /Internasional (Mei 2003)Pelatihan Product Knowledge dan Product
Management,Management Training Materials,Business Skills Training ,Telecommunication
Management System Training,IT Investment, IT Budgeting and IT Business Management
Training,DMTP - Disaster Management and Training Programme,Financial Management
Training,Managing Logistic IT Project / workshop training, Professional Certification Workshop - P3
Behavioral Analyst, Pelatihan Metals Project -Indonesia Australia Partnership For Skills Development
(Januari 2004),Pelatihan Robotic Hardware and Sofware Development (Oktober 2003),Formulas for
Quantifiying the Value of a Training - Technologies Invesment,Training & Organizational
Development, Network and Security Audit (workshop) (16-18 Juni 2004),Next Generation Network
(23-25 Juni 2004),Network Planning- High Speed (Broadband) networking infrastructure,Java and
Web Service (6-9 July 2004),Pelatihan Teknologi Interactive Voice Response Server (July,2005-
Lhokseumawe),Pelatihan Operasional dan Perbaikan Sentral IVR (Oktober,2005-
Lhokseumawe),Pelatihan Teknis Sentral IVR untuk Aceh, Padang, Bukit Tinggi, Solok, Padang
Sidempuan, Lhokseumawe (Desember,2005-Jakarta),Pelatihan Hacking dan Security oleh Hadi Sri
Atmono (January 2006, Medan),Leader Ship Day (Maret,2006 - Jakarta).

Sampai saat ini aktif dibeberapa Organisasi antara lain :Asisten Divisi Pengembangan dan
Pengendalian Robotic Population Club (Ohio, Jepang), Ketua Team Level C-4 Research and
Development Club (Jakarta),Ketua Network Identification and ID Consentration Club (Singapore),
Anggota Team Chemical And BioTechnologies Research Project (Severnaya Rusia), Anggota
HMI (Himpunan Mahasiswa Indonesia),Anggota Team Basket Junior Angsapura (1998-
2000),Anggota Bidang Olahraga SMU Negri 7 Medan,Anggota Organisasi Keislaman, Moral dan
Mental (BINTAL =Bina Mental) .

Memiliki pengalaman trainer antara lain: Microsoft Exchange 5-5 Series Concepts and Administration
PT. Iverson Konsultan Indonesia 2001 ,Designing Windows 2000 Active Directory PT. Metrodata
Edukasi Informatika 2001 ,Designing Windows 2000 Network Service PT. Metrodata Edukasi
Informatika 2001 ,Ms Windows 2000 Network & Operating System Essentials PT. Schematic
PrimaPersada, PT. Executrain 2001 ,Introduction to Deploying Microsoft Windows 2000 Professional
for IT Proffessionals and OEM System Builders PT. Schematic PrimaPersada, PT. Executrain 2001
,Secure Web Access Using Microsoft Proxy Server 2.0 Preliminary Course Syllabus PT. Schematic
PrimaPersada, PT. Executrain 2001 ,Creating and Managing Web Server Using Internet Information
Server 4.0 PT. Schematic PrimaPersada, PT. Executrain 2001 ,Install and Configure Windows 2000 as
File, Print and Web Server PT. Schematic PrimaPersada, PT. Executrain 2001 ,Introduction to Visual
Basic .NET Programming & System Design PT. Yamaha Music Indonesia 2002 ,Analyst and Design
Methodologi PT. Sakura Bengawan 2002 ,CIW:Design Methodology and Technology Book 1 & 2
BPK ,E-Commerce Strategies and Practices BPK 2003 , Microsoft Internet & Website Fundamentals
PT.Iverson 2003 ,MicrosoftAccess 2002 for Non-Programmers BRI 2003 ,Microsoft Access 2002
Delivery Guide BRI 2003 ,Mastering MFC Fundamental Using Microsoft Visual C++,Bank Indonesia
2003 Beginning Java Programming Using Java SDK 1.4 Limas, Satelindo 2003 Transact-SQL Using
SQL Server 2000 Bank Mandiri 2003 ,Java Script Unleashed PT.PLN 2003

Anda mungkin juga menyukai