Belajar Python 1
Belajar Python 1
Oleh:
Owo Sugiana <[email protected]>
JAKARTA
29 September 2002 - 7 Februari 2003
Daftar Isi
I Pendahuluan
15
1 Pemrograman Komputer
17
1.1
1.2
Bahasa Pemrograman
1.3
. . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . .
2 Bahasa Pemrograman
17
18
18
21
2.1
Mengapa Python . . . . . . . . . . . . . . . . . .
21
2.2
Nama Python . . . . . . . . . . . . . . . . . . . .
23
2.3
Pemrograman Terstruktur . . . . . . . . . . . . .
23
2.4
Dokumentasi
24
. . . . . . . . . . . . . . . . . . . .
3 Teknik Penulisan
27
3.1
Gaya . . . . . . . . . . . . . . . . . . . . . . . . .
27
3.2
27
. . . . . . . . . . . . . .
DAFTAR ISI
4 Persiapan
29
4.1
Paket Program
. . . . . . . . . . . . . . . . . . .
29
4.2
Text Editor . . . . . . . . . . . . . . . . . . . . .
29
II Python
31
5 Hello World
33
5.1
Aturan Penulisan . . . . . . . . . . . . . . . . . .
33
5.1.1
Indent . . . . . . . . . . . . . . . . . . . .
34
5.1.2
Baris Perintah
34
5.1.3
Keterangan Program . . . . . . . . . . . .
35
5.2
Variabel . . . . . . . . . . . . . . . . . . . . . . .
35
5.3
Modus Interaktif
35
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
6 Tipe Data
6.1
6.2
6.3
37
Bilangan . . . . . . . . . . . . . . . . . . . . . . .
37
6.1.1
Operator
38
6.1.2
Pengelompokan Operasi . . . . . . . . . .
38
6.1.3
Pembulatan . . . . . . . . . . . . . . . . .
40
6.1.4
Bentuk Tampilan . . . . . . . . . . . . . .
40
. . . . . . . . . . . . . . . . . . . . . . . .
41
String
. . . . . . . . . . . . . . . . . .
6.2.1
42
6.2.2
String Format . . . . . . . . . . . . . . . .
42
int()
float()
6.2.3
. . . . . .
43
6.2.4
. . . . . .
43
6.2.5
Panjang String -
List
6.3.1
len()
. . . . . . . . . .
43
. . . . . . . . . . . . . . . . . . . . . . . . .
43
Penambahan -
append()
&
insert()
. .
44
DAFTAR ISI
6.4
del
6.3.2
Penghapusan -
. . . . . . . . . . . . .
44
6.3.3
45
6.3.4
Pemenggalan
45
6.3.5
Panjang List -
. . . . . . . . . . . .
45
6.3.6
45
47
. . . . . . . . . . . . . . . .
len()
6.3.7
Membalikkan Urutan -
reverse()
6.3.8
Mengurutkan -
. . . . . . . . . . .
47
6.3.9
Menyalin -
. . . . . . . . . . .
48
. . . . . . . . . . . . .
48
sort()
list() . .
keys() .
values()
. . . .
6.4.1
Daftar Kunci -
. . . . . . . . . .
49
6.4.2
Daftar Nilai -
. . . . . . . . . .
49
6.4.3
6.4.4
Menghapus -
del
update()
49
. . . . . . . . . . . . . .
49
. . . . . . . .
50
. . . . . . . .
50
type() .
dir()
6.5
6.6
7 Kondisi
51
7.1
Bentuk Logika
. . . . . . . . . . . . . . . . . . .
7.2
52
Selain Itu -
. . . . . . . . . . . . . . .
53
7.3
Selain Itu
. . . . . . . . . . . . . . .
53
7.4
Operator Perbandingan
. . . . . . . . . . . . . .
54
. . . . . . . . . . . . . . . . . .
55
7.5
else . . .
Jika - elif
Operator Logika
not
7.5.1
Bukan -
. . . . . . . . . . . . . . . . .
7.5.2
7.5.3
8 Perulangan - Loop
8.1
8.2
Selama -
while
and
for
55
. . . . . .
55
. . . .
56
or
59
. . . . . . .
59
. . . . . . . . . . . . . . . . . . .
60
DAFTAR ISI
8.3
break
. . . . . . . . .
9 Fungsi
62
63
9.1
Nilai Masukan . . . . . . . . . . . . . . . . . . . .
9.2
Nilai Keluaran -
. . . . . . . . . . . . . .
64
9.3
Memanggil Dirinya . . . . . . . . . . . . . . . . .
65
9.4
Kepemilikan Variabel
. . . . . . . . . . . . . . .
65
9.5
66
return
10 File
64
69
69
10.2 Printer . . . . . . . . . . . . . . . . . . . . . . . .
70
70
70
71
. . . . . . . . . . . . . . . . . . .
72
73
12 Proyek String
75
. . . . . . . . . . . . . .
zfill()
File - seek()
75
. . . . . . .
76
. . . . . . .
76
. . . . . . . . . . . . . . . . .
splitfields() . . . .
Hapus Karakter Tak Tampak - strip() .
Rata Kiri dan Kanan - ljust() & rjust()
Kunci Pada Dictionary - has_key() . . .
76
78
12.2.2
78
12.2.3
12.2.4
78
78
DAFTAR ISI
III Qt
79
13 Pendahuluan
81
14 Aplikasi Pertama
83
84
84
14.3
self
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
85
85
15 Visual Class
87
87
89
. . . . . . . . . . . . .
qt
self
. . . . . . . . .
89
90
. . . . . . . . . . . . . . . . . .
90
90
15.2 Sinyal
. . . . . . . . . . . . . . . . . . . . . . . .
91
93
94
. . . . . . . . . . . . .
. . . . . . . . . . . . . .
95
15.3 Hiasan . . . . . . . . . . . . . . . . . . . . . . . .
96
15.3.1 Font -
QFont . .
QColor
15.3.2 Warna -
. . . . . . . . . . . . . .
96
. . . . . . . . . . . . . .
98
. . . . . . . . . . . .
QCheckBox . . .
Pilih Salah Satu - QRadioButton
Daftar Fluktuatif - QComboBox
.
99
. . . . . . . . .
99
15.5
. . . . . . . . .
101
15.6
15.7 Listbox
. . . . . . . . .
105
. . . . . . . . . . . . . . . . . . . . . . .
106
DAFTAR ISI
. . . . . . . . . . . . . . . . . . . . . . . .
15.10Hanya Keyboard
. . . . . . . . . . . . . . . . . .
110
111
113
113
. . . . . . . . . . . . .
114
. . . . . . . . . . . . . . . . . .
117
15.10.3 NumLock
16 Kasir I
119
17 Wadah - Container
123
17.1 Widget . . . . . . . . . . . . . . . . . . . . . . . .
17.2 Panel
123
. . . . . . . . . . . . . . . . . . . . . . . .
123
17.3 Groupbox . . . . . . . . . . . . . . . . . . . . . .
123
17.4 Multigroup
127
. . . . . . . . . . . . . . . . . . . . .
18 Penataan
131
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . .
19 Waktu
19.1 Jam
133
136
139
. . . . . . . . . . . . . . . . . . . . . . . . .
19.2 Tanggal -
QDate
. . . . . . . . . . . . . . . . . .
131
139
140
. . . . . . . . . . . . . . . . .
142
. . . . . . . . . . . . . . . . . . . . . . . .
143
20 Form Dialog
20.1 File Dialog
145
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
146
149
DAFTAR ISI
20.3 Input
. . . . . . . . . . . . . . . . . . . . . . . .
21 Tabel
152
155
157
161
168
22 Kasir II
175
23 Database
179
180
23.1.1 PostgreSQL . . . . . . . . . . . . . . . . .
180
23.1.2 MySQL
. . . . . . . . . . . . . . . . . . .
181
. . . . . . . . . . . . . . . . . . . . .
181
185
. . . . . . . . . . . . . . . . . . . . . . . .
185
189
23.4.2 Variant
. . . . . . . . . . . . . . . . . . .
190
. . . . . . . . . . .
191
. . . . . . . . . . . . . . . . . .
192
193
196
23.5.4
197
NULL
. . . . . . . . . . . . . . . . . . . . .
. . .
198
. . . . . . . . . . . . . . .
210
213
24 Kasir III
24.1 Struktur Tabel
217
. . . . . . . . . . . . . . . . . . .
217
DAFTAR ISI
10
. . . . . . . . . . . . . . . . . . .
218
219
24.4 Pencetakan
219
. . . . . . . . . . . . . . . . . . . . .
24.5 Program . . . . . . . . . . . . . . . . . . . . . . .
219
24.6 Laporan . . . . . . . . . . . . . . . . . . . . . . .
225
225
226
. . . . . . . . . .
226
226
Daftar Tabel
6.1
Operator Bilangan
. . . . . . . . . . . . . . . . .
39
6.2
46
7.1
Operator Perbandingan
7.2
Operator Logika
. . . . . . . . . . . . . .
54
. . . . . . . . . . . . . . . . . .
57
11
12
DAFTAR TABEL
Daftar Gambar
1.1
6.1
45
. . . . . . . . . . . . . . . . . . . .
84
. . . . . . . . . . . . . . . . . . . .
89
. . . . . . . . . . . . . . . . . . . . . .
100
15.2 Checkbox
15.3 Radiobutton . . . . . . . . . . . . . . . . . . . . .
103
15.4 Combobox . . . . . . . . . . . . . . . . . . . . . .
105
15.5 Listbox
. . . . . . . . . . . . . . . . . . . . . . .
107
110
15.7 LCD . . . . . . . . . . . . . . . . . . . . . . . . .
112
. . . . . . . . . . .
114
. . . . . . . . . . . . . . . . . . . . .
147
149
13
DAFTAR GAMBAR
14
21.1 QTable . . . . . . . . . . . . . . . . . . . . . . . .
155
21.2 ValueGrid . . . . . . . . . . . . . . . . . . . . . .
161
. . . . . . . . . . . . . . . . . . . . .
181
23.3 QDataTable . . . . . . . . . . . . . . . . . . . . .
194
23.4 CursorTable
. . . . . . . . . . . . . . . . . . . .
195
. . . . . . . . . . . . . . . . . . . . . . .
199
24.1 Kasir . . . . . . . . . . . . . . . . . . . . . . . . .
218
23.5 DBGrid
Kata Pengantar
Pengembangan aplikasi bisnis di Indonesia sudah sangat berkembang dan memiliki potensi pasar yang masih sangat luas. Berbagai paket pemrograman - baik dari dalam maupun luar negeri
- juga semakin memudahkan para programmer dalam membuatnya. Praktis kini pertumbuhan pengembang perangkat lunak
(
software developer )
local support )
semakin
DAFTAR GAMBAR
16
modus teks (
console ).
tidak disertakan dalam paket standar Python. Buku ini menggunakan Qt sebagai pustakanya.
Karena merupakan tutorial, maka ulasan bab demi bab dirangkai dengan tingkat keterkaitan yang tinggi. Bagi para pemula sebaiknya membaca secara runut guna memudahkan pemahaman dalam setiap penjelasan.
Sebagai pelengkap, buku ini juga menyertakan beberapa pertanyaan dan latihan soal guna menggali potensi yang sudah dimiliki pembaca.
Ucapan terima kasih perlu ditujukan kepada pihak terkait
yang sudah membantu kelancaran penyelesaian buku ini. Kepada keluarga penulis, Henry (NCS), Mahendra Putra, dan Henry
(Bina Nusantara).
Seluruh kebutuhan
DAFTAR GAMBAR
17
information tech-
nology )
perpustakaan kampus, kantor, rumah, dan perpustakaan lainnya agar dibaca siapa saja yang bersungguh-sungguh menumbuhkan IT di Indonesia.
Penulis
18
DAFTAR GAMBAR
Bagian I
Pendahuluan
19
Bab 1
Pemrograman
Komputer
Bagi mereka yang belum memahami dunia komputer, khususnya dunia pemrograman, terkadang masih dihadapkan pada
pertanyaan tentang alasan-alasan kita membuat program, apa
manfaat yang bisa diambil, bagaimana kelanjutannya, dan bagaimana arah teknologi komputer ke depan sehingga investasi
waktu dan lainnya dalam mempelajari pemrograman tidak siasia.
Berikut ini sedikit ulasan seputar dunia pemrograman komputer agar memantapkan motivasi dan memudahkan pemahaman
mengapa suatu keputusan telah diambil.
21
22
program yang ada terlalu berat dimana speskasi komputer yang ada miliki tidak mampu untuk menjalankannya
23
pakan hal penting pemilihan suatu bahasa pemrograman. Pemrograman tradisional membutuhkan siklus pengembangan yang
lebih lama karena harus melalui proses kompilasi dan
linking
ke
24
../../python-pengenalan/siklus.ps
Bab 2
Bahasa Pemrograman
Ada banyak bahasa pemrograman yang sudah dibuat sejak diciptakannya komputer pertama kali. Bahasa-bahasa tersebut ada
yang tergolong untuk pembuatan aplikasi umum, namun ada
juga yang memang dirancang untuk suatu aplikasi tertentu.
Pengurangan
source
program
http://www.python.org/doc/Comparisons.html
25
26
http://www.python.org/doc/essays/comparisons.html
http://www.sunworld.com/swol-10-1997/swol-10-scripting.html
Atau untuk yang bergaya humor ada di:
http://www.python.org/doc/Humor.html#vowels
Mungkin bahasa pemrograman ini belum terdengar secara meluas di kalangan programmer Indonesia.
ic language ).
jenis baru.
Berorientasi objek
1 Di
27
Tcl
Seperti Tcl, Python dapat digunakan sebagai bahasa yang digabungkan dengan bahasa lainnya. Tidak seperti Tcl, Python
memiliki ciri bahasa pemrograman yang sesungguhnya.
Se-
cara umum, struktur datanya dan dukungan untuk pemrograman berskala besar membuatnya dapat diterapkan untuk ruang
lingkup yang lebih besar.
string processor.
Perl
tools.
shell
ca. Bagi sebagian orang hal ini membuat Python lebih mudah
digunakan dan pilihan yang lebih tepat untuk membuat pro-
melakukan lebih dari sekedar pengolahan teks dan le, kemampuan Python sangat menggoda.
Java
28
array3
disebut
pada
integer dan
oat secara lebih esien, namun membutuhkan deklarasi untuk
2 Karena
lukan.
29
sebagaimana
Esiensi juga
semakin
30
lebih kecil dari BMP. JPEG sangat baik untuk faktor esiensi tempat (
BMP sangat
simple
dan pros-
Reuseable code 5
merupakan ka-
ta yang akan dicapai. Anda mungkin sudah membuat algoritma yang ditulis dalam bahasa pemrograman tertentu.
2.4 Dokumentasi
Biasakan membuat dokumentasi dalam aktivitas pemrograman
Anda.
suatu program
2.4. DOKUMENTASI
31
audience
script 7 yang
bug 8
tertentu, dan juga sertakan alamat Anda (kalau berkenan) sebagai referensi bagi komunitas pengguna untuk
bertanya.
32
Bab 3
Teknik Penulisan
Sebelum lebih jauh membaca buku ini, ada baiknya Anda memahami beberapa hal teknis tentang bentuk tulisannya.
3.1 Gaya
Gaya penulisan yang diterapkan pada pembuatan buku ini mengutamakan hal-hal berikut:
1. Bahasan merupakan yang paling sering diterapkan dalam
pembuatan aplikasi, terutama aplikasi database.
2. Memperbanyak contoh program dan sebisa mungkin mungkin
menghindari gaya buku referensi untuk mempermudah
33
34
Italic
Courier
Underline
penegasan seperti moto atau kata kunci yang biasanya berkaitan dengan pembicaraan seputar konsep atau loso.
35
Karakter dolar ($) yang mengawali suatu baris perintah menandakan perintah tersebut dijalankan di
but sebagai
1 Karena
command line .1
console
36
Bab 4
Persiapan
Juga ada beberapa hal yang perlu dipersiapkan untuk menjalankan contoh program yang ada.
lu dipasang (
yaitu:
python
qt
interpreter Python
qt-PostgreSQL
melalui Qt
37
BAB 4. PERSIAPAN
38
qt-MySQL
Qt
PyQt
ment .
atau
pat mengenail perintah Python dimana keduanya akan membedakan dengan warna objek dalam script Python seperti
1 kata
reserved
Bagian II
Python
39
Bab 5
Hello World
Hello world
Makna dibelakangnya
adalah bagaimana menampilkan pesan tersebut dengan menggunakan bahasa yang tengah kita pelajari. Buatlah sebuah le
halo.py
$ kwrite halo.py
Lalu ketikkan baris berikut:
$ python halo.py
41
42
Hello world !
dimana perintah
5.1.1 Indent
Sebagaimana bahasa pemrograman pada umumnya, Python mengenal apa yang disebut blok program. Baris-baris berikut dianggap sebuah blok program:
43
44
Untuk sebuah baris yang terlalu panjang, Anda dapat menggunakan karakter
# Tanya kabar
print "Apa kabar ?"
atau bisa juga dituliskan disampingnya:
""" Oleh
:
Email :
Tanggal:
Manfaat:
"""
print "Salam"
Owo Sugiana
[email protected]
17-1-2003
Mencetak salam
cross (#)
5.2. VARIABEL
45
5.2 Variabel
Python tidak membutuhkan deklarasi variabel secara khusus sebagaimana beberapa bahasa pemrograman lainnya.
Deklarasi
n = 1
yang menunjukkan variabel
n = 1
n = "Saya belajar Python."
Baris pertama mendeklarasikan n bertipe integer, dan pada
baris berikutnya n berubah tipe menjadi string.
interactive mode ).
aktif (
$ python
Python 1.5.2 (#1, Aug 7 2000, 21:22:50)
[GCC 2.95.2 19991024 (release)] on linux2
46
>>>
Penjumlahan berikut
untuk menampilkannya.
print 5+7
Bab 6
Tipe Data
Meski tidak memerlukan deklarasi secara khusus, Python sangat
memperhatikan tipe data. Anda tidak diperkenankan melakukan
hal ini:
48
6.1 Bilangan
Bilangan atau angka merupakan hal yang biasa kita temui dalam
matematika. Python mengenal dua tipe data bilangan: bilangan bulat (integer) dan bilangan pecahan (oat).
n bertipe oat karena mengandung titik desn merupakan variabel dan 7 meru-
6.1.1 Operator
Operator merupakan pengolah variabel atau nilai. Tabel 6.1
berisi beberapa operator bilangan yang sering dijumpai pada
operai matematika.
6.1. BILANGAN
Catatan
49
float():
math.
>>> 8 + 5 * 2
18
50
Operator
Simbol
Contoh
tambah
+
a + b
kurang
a - b
kali
*
a * b
bagi
/
a / b
sisa bagi
%
a % b
pangkat
**
a ** b
6.1. BILANGAN
51
perkalian, baru selanjutnya penjumlahan. Jika Anda ingin sebaliknya gunakan tanda kurung untuk pengelompokan operasi:
6.1.3 Pembulatan
Pembulatan bilangan pecahan bisa menggunakan fungsi
dan
round().
Perbedaannya adalah
bawah, sedangkan
round()
int()
int()
membulatkan ke-
52
pada
"%.2f"
tampil. Kalau Anda lihat hasilnya maka dapat diambil kesimpulan bahwa
1234.567
format()
format()
me-
6.2. STRING
53
Modul locale
locale
6.2 String
String merupakan kalimat yang diawali dan diakhir dengan kutip, baik kutip ganda maupun tunggal.
juga dapat menangani string dengan berbagai cara. String dapat diapit baik oleh kutip tunggal maupun kutip ganda.
backslash (\)
54
String juga dapat ditulis dengan awalan tiga buah kutip (baik
kutip tunggal maupun ganda) dimana akhir string juga dinyatakan dengan tiga kutip juga.
(penjumlahan) berikut:
6.2. STRING
55
(perkalian):
Python
>>> a = 1
>>> b = 2
>>> c = a + b
> > > s = str(a) + " + " + str(b) + " = " + str(c)
> > > print s
1 + 2 = 3
Meski cara di atas sudah benar, namun pengisian variabel
56
mirip dengan
int()
cast .
len()
6.3. LIST
57
6.3 List
List sering disebut sebagai array atau larik (dalam bahasa Indonesia) adalah kumpulan data dimana setiap data memiliki
nomor index yang dimulai dari 0.
b[0]
b[1]
bertipe integer.
58
c merupakan list hampa dimana tidak ada elemen data di dalamnya. Untuk menambahkannya gunakan fungsi append().
> > > c.append(100)
> > > c.append('persen')
>>> c
[100, 'persen']
Perintah
insert()
append().
del
6.3. LIST
59
list of character
satu karakter).
6.3.4 Pemenggalan
slice )
Pemenggalan (
sebagai contoh.
Cara terbaik untuk mengingat bagaimana pemenggalan bekerja adalah dengan berasumsi bahwa angka index berada diantara dua karakter.
len()
gambar 6.1.
untuk mendapatkan
60
Variabel
Hasil
Keterangan
d
'Python'
nilai awal
d[0]
'P'
d[2:]
'thon'
d[:2]
'Py'
d[-1]
'n'
d[-2:]
'on'
d[:-2]
'Pyth'
d[2:5]
'tho'
mulai
karakter
ketiga
hingga
dari kiri
kelima
6.3. LIST
61
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0
1
-6
-5 -4 -3
5
-2
6
-1
(total
62
[0]
[1]
ascending ):
yang terbesar (
6.3. LIST
63
>>> a
[3, 4, 8, 9]
Sedangkan untuk mengurutkan dari yang terbesar ke yang terkecil (
maka
saja. Ini
juga berubah
64
associative arrays
dimana -
dan
1003
disebut sebagai
keys
(kunci), sedangkan
Un-
key -nya:
Tipe data
dengan
tipe
65
dari dictionary.
data.
66
del.
type()
dir():
67
68
Bab 7
Kondisi
if
apa yang akan dilakukan, sehingga tema ini sering disebut sebagai jika-maka.
Karena penulisan
editor
seperti
vi
atau
kwrite
text
interactive interpreter .
if
bekerja.
BAB 7. KONDISI
70
if n == "y":
print "Baiklah"
raw_input() digunakan untuk menerima masukan dari pemakai.
Fungsi ini mengembalikan nilai string.
Operator == menyatakan persamaan, sehingga n == "y" diban sama dengan "y". Jangan lupa untuk menyertakan titik
dua (:) pada akhir baris if.
ca
Sub-Blok Program
Perhatikan baris
if n == "y":
print "Baiklah"
print "Siapkan perlengkapannya"
Baris lain yang sejajar dengan
if
if n == "y":
print "Baiklah"
print "Siapkan perlengkapannya"
print "..."
Sehingga
print "..."
terpenuhi.
n == "y"
tidak
71
false
0,
string
if 0:
print "Benar"
else:
print "Salah"
yang akan menampilkan pesan "Salah", dan baris berikut
if 1:
print "Benar"
else:
print "Salah"
akan menampilkan pesan "Benar".
BAB 7. KONDISI
72
"y"
maka baris
elif
73
==
tuk menyatakan
sama dengan.
BAB 7. KONDISI
74
Contoh
Keterangan
a == b
a sama dengan b
a < b
a lebih kecil dari b
a > b
a lebih besar dari b
a != b
a tidak sama dengan b
a >= b
a lebih besar atau sama dengan b
a <= b
a lebih kecil atau sama dengan b
a in c
a termasuk dalam list c
75
Catatan
sukkan huruf
mengantisipasi
capslock
not, and,
dan
or.
1 Lihat
BAB 7. KONDISI
76
true .
langan ganjil.
Catatan
Penggunaan
int(n)
han yang tidak dapat ditangani script di atas, yaitu apabila proses konversi dari string ke integer gagal, misalnya
dengan memasukkan huruf. Untuk menangkap kesalahan
konversi tersebut Anda bisa menggunakan
or
menyatakan bahwa
true
kondisi terpenuhi.
77
BAB 7. KONDISI
78
b
not a
a and b
a or b
1
1
0
1
1
1
0
0
0
1
0
1
1
0
1
0
0
1
0
0
Bab 8
Perulangan - Loop
Perulangan (
disi terpenuhi. Kondisi yang dimaksud - tentunya - akan mempengaruhi seberapa banyak proses tersebut dijalankan. Banyaknya
perulangan ini bisa ditentukan di awal
berlangsung.
80
1
2
3
for
tabel = [
[ 2769, "Jeruk", 5500 ],
[ 8205, "Mangga", 3750 ]
for
for un-
81
]
for record in tabel:
for nilai in record:
print nilai,
print
range()
range()
range(5)
berarti
[0,1,2,3,4],
begitu seterusnya.
for
untuk mendapatkan
0
1
2
Bila kisaran yang diinginkan adalah 1-3 maka gunakan
Latihan
pada saat
runtime.
dimana
range(1,4).
dimasukkan
1 Bilangan
82
while:
for
i = 0
while i < 3:
i = i + 1
print i
Script di atas memang lebih pas bila dengan
for.
Contoh
berikut akan menampilkan bilangan acak yang dibuat terusmenerus sampai ditemukan bilangan yang lebih besar dari
import random
i = 0
while i <= 0.5:
i = random.random();
print i
dengan contoh hasil sebagai berikut:
0.135330567072
0.321183281272
0.42870775016
0.335857508686
0.447331794014
0.5:
83
0.287945799635
0.854292081945
Hasil di atas sangat mungkin berbeda dengan yang Anda peroleh - karena sifat bilangan acak itu sendiri.
Perhatikan nilai
Modul random
random
dir().
Contoh:
import random
print dir(random)
Kalau Anda beruntung, dalam suatu modul terdapat konstanta
__doc__
import time
print time.__doc__
84
break.
import random
while 1:
i = random.random();
print i
if i > 0.5:
break
print "selesai"
Perhatikan angka
De-
break. break
print "selesai".
Latihan
1. Tampilkan satu bilangan acak yang lebih kecil dari 0,5.
2. Melanjutkan sebelumnya, tampilkan
lebih kecil dari 0,5.
2 Lihat
for
dan
while.
Bab 9
Fungsi
Pada contoh-contoh program sebelumnya, Anda sudah menggunakan fungsi seperti
len(), range(),
dan
random()
dimana
tujuan pembuatan fungsi adalah mempersingkat penulisan suatu blok program yang dipakai berulang-ulang. Misalnya pada
program berikut:
print
print
print
print
print
"-" * 10
"Setiap pesan diawali garis."
"-" * 10
"Juga diakhiri garis."
"-" * 10
print "-" * 10
85
BAB 9. FUNGSI
86
# Deklarasi fungsi
def garis():
print "-" * 10
# Program utama
garis()
print "Setiap pesan diawali garis."
garis()
print "Juga diakhiri garis."
garis()
def
Mis-
def garis(n):
print "-" * n
garis(10)
print "Setiap pesan diawali garis."
87
garis(3)
print "Juga diakhiri garis."
garis(10)
Fungsi juga dapat menerima masukan lebih dari satu. Misalkan
karakternya bisa diganti-ganti, tidak hanya "-".
def garis(k,n):
print k * n
garis("-",10)
print "Setiap pesan diawali garis."
garis(".",3)
print "Juga diakhiri garis."
garis("*",10)
return
def garis(k,n):
return k * n
print
print
print
print
garis("-",10)
"Setiap pesan diawali garis."
garis(".",3)
"Juga diakhiri garis."
BAB 9. FUNGSI
88
print garis("*",10)
Sebagai tambahan, perintah lain di bawah baris
return
(masih
def garis(k,n):
return k * n
print "Selesai"
Baris
didahului oleh
fungsi.
return sebenarnya
None. None meru-
faktorial()
def faktorial(n):
if n <= 1: return 1
else: return n * faktorial(n-1)
print faktorial(5)
berikut ini:
89
def hurufDalamNama():
huruf = {}
for h in nama:
if huruf.has_key(h):
jml = huruf[h] + 1
else:
jml = 1
huruf.update( {h:jml} )
return huruf
nama = raw_input("Nama Anda: ")
print hurufDalamNama()
Variabel
nama
Sehingga
BAB 9. FUNGSI
90
print huruf
akan tampil pesan kesalahan:
Latihan
hurufDalamNama()
Petunjuk
Gunakan
keys()
dan
sort().
91
x = 8*3
24
x = 7+3
10
x = sin(45)
BAB 9. FUNGSI
92
0.850903524534
x = pi*(10**2)
314.159265359
x =
Bab 10
File
Bab ini membahas beberapa hal mengenai operasi le dan direktori.
biasanya untuk mencetak laporan dimana le tersebut berfungsi ganda: sebagai
ke printer.
open().
f = open("test.txt","w")
1 Preview
93
94
f.write("coba")
f.close()
Option
w (write )
r (read ).
/etc/hosts.
Contoh berikut
f = open("/etc/hosts","r")
for baris in f.readlines():
print baris,
f.close()
readlines() mengembalikan list dimana elemennya merupakan
string yang mewakili setiap baris le. String ini diakhiri karakter
Enter, namun belum tentu untuk string pada baris terakhir.
Oleh karena itu
10.2 Printer
Sebuah device printer dapat dianggap sebuah le, biasanya ada
di
/dev/lp0.2
f = open("/dev/lp0","w")
f.write("test\n")
f.close()
2 DOS
open()
ini.
10.2. PRINTER
95
/dev/lp0 ini.
system administrator
(user
close()
chr(15)
Selama
f = open("/dev/lp0","w")
f.write( chr(15) )
f.close()
Setelah program di atas selesai dijalankan, perintah pengecilan
masih tersimpan dalam memori printer. Jadi bila
96
Untuk kertas
continues
"\f"
f = open("/dev/lp0","w")
f.write( "\f" )
f.close()
Karakter ASCII
chr ()
ord()
sebaliknya. Contoh:
ASCII-nya berapa:
cat
10.2. PRINTER
97
import sys
import os
namafile = sys.argv[1]
printer = "/dev/lp0"
f = open(printer,"w")
f.write( chr(15) )
f.close()
perintah = "cat %s > %s &" % (namafile, printer)
os.system( perintah )
Simpan program di atas dengan nama
cetak.py,
lalu cobalah
cat.
Cara di
3 yang
&
etakan tetap dilakukan meski program Python yang memanggilnya sudah selesai.
3 Misalnya:
98
Modul sys
Ruang lingkup modul
dengan interpreter.
sys
Sedangkan list
argv
['cetak.py', '/etc/hosts'].
argv
Modul os
Modul ini memiliki banyak fungsi yang berkaitan dengan sistem operasi.
Fungsi
system()
program lain.
test.txt
f = open("test.txt","w")
akan ditulis pada direktori aktif.
apa yang sedang aktif atau bagaimana pindah ke direktori tertentu, cobalah program berikut:
import os
os.chdir("/tmp")
print os.getcwd()
Bab 11
error.
syntax
exception.
while 1
99
100
dimana akan muncul pesan kesalahan karena titik dua (:) belum
disertakan dalam
while:
exception terjadi pada saat program dijalankan karekesalahan logika. Misalnya perintah berikut ini:
Sedangkan
na
1 / 0
yang akan menimbulkan pesan kesalahan:
Bab 12
Proyek String
Paket Python menyertakan modul string yang memiliki berbagai fungsi untuk penanganan string. Meski pokok bahasannya
pengolahan string, namun banyak hal baru yang juga dibahas
seputar tipe data lainnya.
102
nomorbaris.py
------------01| import sys
02| import string
03|
04| namafile = sys.argv[1]
05| print namafile
06| print "-" * len(namafile)
07|
08| file
= open(namafile,"r")
09| jumlahbaris = len(file.readlines())
10| lebar
= len(str(jumlahbaris))
11| file.seek(0)
12| n = 0
13| for baris in file.readlines():
14|
n = n + 1
15|
nomor = string.zfill(n, lebar)
16|
print "%s| %s" % (nomor, baris),
17| file.close()
Tentu saja Anda sudah tahu bagaimana isi programnya.
103
dotmatrix
Nomor;Nama Barang;Harga
1;Duren;15000
2;Jeruk;7000
3;Rambutan;5000
4;Mangga;5500
5;Pisang;4750
6;Jambu;6500
7;Pepaya;2000
1 Sehingga
104
8;Nanas;1500
9;Bengkuang;2000
10;Belimbing;4000
Selanjutnya le ini dibaca, diolah, lalu dicetak, dengan algoritmanya adalah sebagai berikut:
1. File dibuka dan diasumsikan sebagai sebuah tabel dimana
setiap baris (record) dipisahkan dengan karakter enter,
dan setiap kolom dipisahkan oleh karakter pemisah.
2. Setiap kolom dianalisa:
mumnya.
3. Kemudian setiap nilai dicetak ke layar yang akan dipaskan
jumlah karakternya dengan karakter spasi hingga mencapai jumlah maksimum, tergantung posisi kolom elemen
data tersebut.
Contoh hasilnya adalah sebagai berikut:
Nama Barang
Duren
Jeruk
Rambutan
Mangga
Pisang
Jambu
Harga
15000
7000
5000
5500
4750
6500
Pepaya
Nanas
Bengkuang
Belimbing
105
2000
1500
2000
4000
csv.py
-----01| import string
02| import sys
03|
04| namafile = sys.argv[1]
05| pemisah = ";"
06| file = open(namafile,"r")
07| maks = {}
08| for baris in file.readlines():
09|
record = string.splitfields(baris, pemisah)
10|
kolom = -1
11|
for nilai in record:
12|
kolom = kolom + 1
13|
panjang = len(nilai)
14|
if not maks.has_key(kolom) or \
15|
panjang > maks[kolom]:
16|
maks.update( {kolom:panjang} )
17| file.seek(0)
18| for baris in file.readlines():
19|
record = string.splitfields(baris, pemisah)
106
20|
kolom = -1
21|
for nilai in record:
22|
kolom = kolom + 1
23|
s = string.strip(nilai)
24|
print string.ljust( s, maks[kolom] ),
25|
print
26| file.close()
Pemisah antar eld bisa saja menggunakan karakter lain, titik
koma (;) misalnya. Asalkan bisa dipastikan nilai di dalam eld
tidak mengandung karakter tersebut.
rstrip().
lstrip(),
Untuk
107
rjust().
has_key()
di-
pakai untuk mengetahui apakah suatu kunci terdapat pada dictionary tersebut.
Latihan
108
Bagian III
Qt
109
Bab 13
Pendahuluan
1 dan merupakan library 2 untuk aplikasi
3
yang menggunakan form dimana di dalamnya terdapat button,
4
radiobox, grid , dsb. Objek-objek tersebut tersedia dalam ben-
tuk
class 5 .
database server
untuk menyimpan data. Oleh karena itu library ini sangat cocok dalam pembuatan aplikasi bisnis.
Sebagai referensi tambahan, Qt juga digunakan dalam KDE
- sebuah
window manager
1 www.trolltech.com
2 Library: pustaka kumpulan class,
3 Meski dengan Qt memungkinkan
asa, namun tujuan dibuatnya library ini memang untuk aplikasi berbasis
form (window).
112
6 dan merupakan
library
Bab 14
Aplikasi Pertama
Program pendek berikut akan menampilkan sebuah form seperti
pada gambar 14.1. Kesederhanaannya ingin menunjukkan bagaimana membuat aplikasi Qt semudah mungkin.
hello.py
-------01| from qt import *
02|
03| class FormHello(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Hello World !")
07|
self.show()
08|
113
114
09|
10|
11|
12|
app = QApplication([])
fm = FormHello()
app.setMainWidget(fm)
app.exec_loop()
visual class ).
Sedangkan
yang ada
dalam suatu aplikasi yang akan menunjuk salah satu form sebagai form utama dengan fungsi
setMainWidget().
berorientasi objek (
merupakan
115
inheritence )
dari class
pakan pembentuk (
constructor )
pertama kali suatu objek diciptakan, dan ini merupakan standar Python. Pemanggilan fungsi
QWidget.__init__() berguna
form .
Namun class
Secara umum manfaat dari teknik pemrograman berorientasi objek adalah menyederhanakan pembuatan program pada
aplikasi yang komplek (rumit) melalui proses penurunan sifat
ini.
3 Pada
116
looping )
tikan perulangan (
up.
Jadi di dalam
14.3 self
self sebagai parameter masukan __init__() mewakili FormHello.
Setiap fungsi yang didenisikan di dalam class setidaknya memiliki sebuah parameter yang mewakili class tersebut. Kata
self
self.show()
caption4
di suatu form.
Tanpa ini, form tidak ditampilkan namun program tetap berjalan karena
self.show()
exec_loop()
4 Caption:
judul form
hang )
Kalau
lakukan saja
117
$ killall python
show() dan setCaption() dipanggil pada saat penciptaan yang
juga dapat dipanggil sesudahnya:
hello1.py
--------01| from qt import *
02|
03| class FormHello(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Hello World !")
07|
08| app = QApplication([])
09| fm = FormHello()
10| fm.show()
11| app.setMainWidget(fm)
12| app.exec_loop()
118
Bab 15
Visual Class
QWidget
hana.
tampak (
visual object ).
leluhur
semua objek-
widget.
Buku
ini juga menggunakan istilah yang sama untuk menyebut objektampak, yaitu
QWidget
dan keturunannya.
1 Lihat
119
120
sukkan data (
relasi1.py
---------01| from qt import *
02|
03| class FormRelasi(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.resize(268,194)
07|
self.setCaption("Relasi")
08|
labelNama = QLabel(self)
09|
labelNama.setGeometry(10,10,65,20)
10|
labelNama.setText("Nama")
11|
labelAlamat = QLabel(self)
12|
labelAlamat.setGeometry(10,40,65,20)
13|
labelAlamat.setText("Alamat")
14|
self.editNama = QLineEdit(self)
15|
self.editNama.setGeometry(90,10,160,20)
16|
self.editAlamat = QTextEdit(self)
17|
self.editAlamat.setGeometry(90,40,160,102)
18|
buttonSimpan = QPushButton(self)
19|
buttonSimpan.setGeometry(90,150,80,24)
20|
buttonSimpan.setText("Simpan")
21|
self.show()
22|
23| app = QApplication([])
24| fm = FormRelasi()
121
app.setMainWidget(fm)
app.exec_loop()
print "Nama", fm.editNama.text()
print "Alamat", fm.editAlamat.text()
QLabel
QLineEdit
input )
dari penggu-
QTextEdit
mirip
QLineEdit,
QPushButton
resize()
pixel.
122
setGeometry()
Dua
pu menampung masukan sebanyak satu baris saja, karena memang kebutuhannya seperti itu. Berbeda dengan Alamat yang
menggunakan
QTextEdit
towarp ).
au-
QLineEdit
dan
QTextEdit.
setText(), text()
dimiliki oleh
QPushButton.
QLabel
123
Parent merupakan
sebagai child . Pada
2 objek.
wadah
contoh di atas
dikatakan bahwa
Perhatikan
baris:
labelNama = QLabel(self)
self
dimana
labelNama.
QLabel
Pembuatan
self.editNama = ...
berarti variabel
editNama
dimiliki
self,
sedangkan,
... = QLineEdit(self)
berarti
QLineEdit
self.
2 Lihat
3 Lihat
124
self).
self
self
segmentation fault.4
15.1.4 Modul qt
Modul
qt
import qt
dan sebagai gantinya gunakan
from qt import *
agar tidak perlu menyebutkan nama modul didepan class yang
digunakan.
4 Segmentation
fault:
kesalahan
program
yang
sering
disebabkan
masalah manajemen memori. Kesalahan ini cukup fatal karena tidak terdeteksi oleh programnya itu sendiri.
125
non-visual class5 .
self.editNama.setText( QString("Nuryadi") )
sama hasilnya dengan:
self.editNama.setText( "Nuryadi" )
dimana editor bertipe
QLineEdit,
misalnya.
Namun jangan
text()
de-
ngan perintah standar Python lainnya mengenai string, misalnya penggunaan operator tambah (+) seperti:
QString.
string:
QWidget.
126
QString.
QString
untuk mencetak
str()
maupun
string formatting %.
print sudah
15.2 Sinyal
FormRelasi
event.6
Saat
signal ).
relasi.txt
NAMA: <nama>
ALAMAT:
<alamat>
--File
plaintext
editor biasa.
6 Karena
ap
disebut
berdasarkan kejadian).
tur
event
driven
programming
(pengendalian
15.2. SINYAL
127
relasi2.py
---------01| from qt import *
02| import os
03|
04| class FormRelasi(QWidget):
05|
def __init__(self):
06|
QWidget.__init__(self)
07|
self.resize(268,194)
08|
self.setCaption("Relasi")
09|
labelNama = QLabel(self)
10|
labelNama.setGeometry(10,10,65,20)
11|
labelNama.setText("Nama")
12|
labelAlamat = QLabel(self)
13|
labelAlamat.setGeometry(10,40,65,20)
14|
labelAlamat.setText("Alamat")
15|
self.editNama = QLineEdit(self)
16|
self.editNama.setGeometry(90,10,160,20)
17|
self.editAlamat = QTextEdit(self)
18|
self.editAlamat.setGeometry(90,40,160,102)
19|
buttonSimpan = QPushButton(self)
20|
buttonSimpan.setGeometry(90,150,80,24)
21|
buttonSimpan.setText("Simpan")
22|
self.show()
23|
self.connect( buttonSimpan,
24|
SIGNAL("clicked()"), self.tombolKlik )
25|
26|
def tombolKlik(self):
27|
rec = "NAMA: %s\nALAMAT:\n%s\n---\n" % \
128
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
41|
42|
43|
44|
Fungsi
(self.editNama.text(),
self.editAlamat.text())
file = "relasi.txt"
fileSementara = "~" + file
os.system("touch " + file)
os.system("touch " + fileSementara)
f = open(file,"r")
fSementara = open(fileSementara, "w")
fSementara.write(f.read() + rec)
fSementara.close()
f.close()
os.rename(fileSementara, file)
app = QApplication([])
fm = FormRelasi()
app.setMainWidget(fm)
app.exec_loop()
connect()
Jalankan
jalankan
penyisipan fungsi
diberikan para pengembang Qt, maka Anda tidak dapat menyisipkan suatu fungsi ke dalam fungsi lain yang dimiliki suatu
objek.
15.2. SINYAL
129
Latihan
Pada saat
buttonSimpan
Petunjuk
Gunakan fungsi
setFocus()
dan
Modul os
rename()
le. Sedangkan
touch
system()
antara Python dengan library Qt yang dibangun dengan bahasa C++. Python memang dikatakan sebagai antarmuka bahasa C
7C
7 (C
interface ).
seluruh perintah C.
130
Praktis Python
PytQt).
objek dimana sinyal yang muncul kemudian dihubungkan dengan suatu fungsi.
Istilah event dalam Qt sebenarnya juga berupa kejadian yang
diwakili oleh suatu fungsi. Perbedaannya dengan sinyal adalah
override8 )
sifatnya
__init__()
yang
QLineEdit
linecase.py
----------01| from qt import *
02|
03| class LineCase(QLineEdit):
04|
Normal = 0
8 Override:ditulis
reimplementation .
15.2. SINYAL
131
05|
Upper = 1
06|
Lower = 2
07|
08|
def __init__(self, parent, case=0):
09|
QLineEdit.__init__(self, parent)
10|
self.case = case
11|
self._OnSet = 0
12|
self._panjang = 0
13|
self.teksBerubah = None
14|
self.connect( self,
15|
SIGNAL( "textChanged( const QString& )" ),
16|
self.berubah)
17|
18|
def berubah(self, t):
19|
if self._OnSet: return
20|
if self.case != self.Normal and \
21|
self._panjang < t.length():
22|
self._OnSet = 1
23|
if self.case == self.Upper:
24|
self.setText( self.text().upper() )
25|
else:
26|
self.setText( self.text().lower() )
27|
self._OnSet = 0
28|
self._panjang = t.length()
29|
if self.teksBerubah: self.teksBerubah( self )
30|
31| if __name__ == "__main__":
32|
app = QApplication([])
33|
fm = LineCase(None, LineCase.Upper)
132
34|
35|
36|
fm.show()
app.setMainWidget(fm)
app.exec_loop()
__name__)
textChanged()
pada
LineCase
hal Anda ingin menyisipkan fungsi lain pada saat teks berubah.
reimplementation ) LineCase menjadi class baru dan mengubah source fungsi berubah().
Cara ini sudah dicontohkan oleh __init__(). Sedangkan cara
Cara pertama bisa dengan menulisulang (
teksBerubah
berubah()
dimana baris
apakah nilainya sudah diganti dengan yang lain. Jika ya, maka penggantinya harus berupa event dengan sebuah parameter
masukan, dikarenakan ia dipanggil dengan sebuah parameter di
dalamnya. Perhatikan bagian
15.2. SINYAL
133
self.teksBerubah( self )
Lebih jelasnya jalankan contoh berikut ini:
linecase1.py
-----------01| from qt import *
02| from linecase import LineCase
03|
04| class FormCase(QWidget):
05|
def __init__(self):
06|
QWidget.__init__(self)
07|
self.line = LineCase(self, LineCase.Lower)
08|
self.line.teksBerubah = self.ubahCaption
09|
self.show()
10|
11|
def ubahCaption(self, w):
12|
self.setCaption( w.text() )
13|
14| app = QApplication([])
15| fm = FormCase()
16| app.setMainWidget(fm)
17| app.exec_loop()
self9 yang
jumlahnya sebanyak yang ditetapkan variabel event teksBerubah
pada LineCase. Contoh di atas menunjukkan parameter tersebut bertipe LineCase, sehingga fungsi text() bisa digunakan.
ubahCaption()
9 Ingat,
Bila
fungsi didenisikan di luar class, maka - tentu - self tidak perlu disertakan.
134
15.3 Hiasan
Terlepas dari alur suatu sistem, ada baiknya kita mengetahui
beberapa hal untuk memperbagus tampilan dengan tujuan aplikasi yang digunakan bisa lebih informatif.
Italic
Miring
Underline
Garis bawah
Bold
Tebal
font.py
QLabel
QLineEdit.
font.py
------01| from qt import *
02|
03| class FormFont(QWidget):
yang isinya
15.3. HIASAN
04|
05|
06|
07|
08|
09|
10|
11|
12|
13|
14|
15|
16|
17|
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
135
def __init__(self):
QWidget.__init__(self)
self.setCaption("Font")
self.label = QLabel(self)
self.label.setAutoResize(1)
self.label.setText( "Tulis saja" )
font = QFont(self.label.font())
font.setFamily("Courier [Adobe]")
font.setPointSize(48)
font.setBold(1)
font.setItalic(1)
font.setUnderline(1)
self.label.setFont(font)
self.teks = QLineEdit(self)
self.teks.setGeometry( 10, 80, 106, 20 )
self.show()
self.connect( self.teks, SIGNAL( "textChanged( \
const QString&)"), self.ubahLabel)
def ubahLabel(self, teks):
self.label.setText( teks )
app = QApplication([])
fm = FormFont()
app.setMainWidget(fm)
app.exec_loop()
Pada dasarnya
136
atas.
Penjelasan mengenai fungsi pada
font()
QFont
di atas adalah:
setFamily()
setPointSize()
kwrite.
Pilih
setBold()
boolean
(logika) 1 (ditebalkan)
setItalic()
setUnderline()
ga boolean.
Di luar masalah font, program di atas cukup menarik karena
setAutoResize() yang menentukan apakah ukuQLabel akan mengikuti panjang tulisan. Serta penggunaan
sinyal textChanged() yang terpicu saat teks pada QLineEdit
melibatkan
ran
berubah.
15.3. HIASAN
137
warna.py
-------01| from qt import *
02|
03| class FormWarna(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Warna")
07|
self.label = QLabel(self)
08|
self.label.setAutoResize(1)
09|
self.label.setPaletteForegroundColor(
10|
QColor("yellow"))
11|
self.label.setPaletteBackgroundColor(
12|
QColor("blue"))
13|
self.label.setText( "Tulis saja" )
14|
self.teks = QLineEdit(self)
15|
self.teks.setGeometry( 10, 20, 106, 20 )
16|
self.show()
17|
self.connect( self.teks, SIGNAL( "textChanged( \
18|
const QString&)"), self.ubahLabel)
138
19|
20|
21|
22|
23|
24|
25|
26|
red ),
merah (
hijau (
green ),
dan biru (
blue )
atau
setPaletteForegroundColor(QColor("white"))
bisa juga ditulis demikian:
setPaletteForegroundColor(QColor(255,255,255))
FormWarna:
de-
139
self.label.setPaletteBackgroundColor(QColor("blue"))
menjadi
self.setPaletteBackgroundColor(QColor("blue"))
QLineEdit
2. Memiliki sebuah kotak isian yang apabila di-klik bermakna ya, dan bila di-klik sekali lagi berarti tidak. Keduanya
dibedakan dengan sebuah tanda
checked (benar).
checkbox.py menunjukkan bagaimana QCheckBox dapat digunakan untuk mengubah warna form.
140
checkbox.py
----------01| from qt import *
02|
03| class FormCheckBox(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Check Box")
07|
self.checkBox = QCheckBox( self )
08|
self.checkBox.setText( "Putihkan" )
09|
self.connect( self.checkBox, SIGNAL( "clicked()"),
10|
self.putihkan )
11|
self.warnaAsli = self.paletteBackgroundColor()
12|
self.show()
13|
14|
def putihkan(self):
15|
if self.checkBox.isChecked():
16|
self.setPaletteBackgroundColor(QColor(
17|
255,255,255))
18|
else:
19|
self.setPaletteBackgroundColor(self.warnaAsli)
20|
21| app = QApplication([])
22| fm = FormCheckBox()
23| app.setMainWidget(fm)
24| app.exec_loop()
isChecked()
141
QCheckBox
setting ),
suatu proses
QButtonGroup
QButtonGroup.
reset ).
142
143
self.show()
self.connect( self.golDarah,
SIGNAL("clicked(int)"), self.golDarahKlik )
self.connect( self.btReset, SIGNAL("clicked()"),
self.btResetKlik )
def golDarahKlik(self, index):
self.setCaption( "Golongan %s (%d) dipilih" %
( self.golDarah.find(index).text(), index) )
def btResetKlik(self):
if self.golDarah.selected():
self.golDarah.selected().setChecked( 0 )
self.setCaption( "Tidak ada yang dipilih" )
app = QApplication([])
fm = FormRadioButton()
app.setMainWidget(fm)
app.exec_loop()
QButtonGroup
di
atas:
selected()
count()
10 None:
None10 .
objek hampa
Bila
QButtonGroup.
144
find()
clicked()
QRadioButton
menentukan apakah radiobutton terpilih atau tidak, dimana nilai masukan 0 berarti tidak dipilih, sedangkan 1 berarti terpilih.
reset QButtonGroup.
Anda juga bisa mengganti tombol Reset dengan sebuah pilihan baru pada radiobutton yang berisi Tidak
tahu dimana pada saat pertama ditampilkan men-
11
Meningkatkan Fleksibilitas
Mayoritas kita mungkin hanya tahu bahwa golongan darah itu
A, B, AB, dan O saja.
ada golongan darah lainnya di dunia ini. Bila itu terjadi, maka
radiobutton1.py
11 Default:
self.golX.
145
yang dimaksud.
dan merupakan nilai default pada saat pertama kali program dijalankan.
radiobutton2.py
--------------01| from qt import *
02|
12 Anggap
146
147
( self.golDarah.find(index).text(), index) )
app = QApplication([])
fm = FormRadioButton()
app.setMainWidget(fm)
app.exec_loop()
Jadi jumlah objek-pilihan tergantung dari jumlah datanya dimana penataannya menggunakan suatu rumus yang diletakkan
dalam perualangan
for.
setButton()
selected ).
layouter.13
14
berjalan
148
atau dihapus tanpa perlu mengatur kembali tata letak dari setiap pilihan, karena ia merupakan kombinasi antara tombol dan
popup-list .
descending .
ascending maupun
but.
combobox.py
----------01| from qt import *
02|
03| class FormComboBox(QWidget):
149
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("ComboBox")
07|
daftarBuah = ["Pisang", "Jeruk", "Apel",
08|
"Mangga", "Pepaya", "Nanas", "Jambu"]
09|
self.buah = QComboBox(self)
10|
self.buah.insertStrList( daftarBuah )
11|
self.buah.setEditable(1)
12|
self.buah.setAutoCompletion(1)
13|
self.buah.listBox().sort()
14|
self.setCaption( "Ada %d pilihan buah" %
15|
self.buah.count() )
16|
self.show()
17|
self.connect( self.buah, SIGNAL("activated(int)"),
18|
self.buahKlik )
19|
self.connect( self.buah, SIGNAL("highlighted(int)"),
20|
self.buahHighlighted )
21|
22|
def buahKlik(self, index):
23|
self.setCaption( "Buah %s (%d) dipilih" %
24|
( self.buah.currentText(), index) )
25|
26|
def buahHighlighted(self, index):
27|
self.setCaption( "Buah %s (%d) tersorot" %
28|
( self.buah.text( index ), index) )
29|
30| app = QApplication([])
31| fm = FormComboBox()
32| app.setMainWidget(fm)
150
33| app.exec_loop()
Adapun penjelasan mengenai fungsi
QComboBox
yang dipakai
adalah:
insertStrList()
berupa list.
setEditable()
mengaktifkan editor.
setAutoCompletion()
currentText()
text()
listBox()
currentItem().
count()
15.7 Listbox
Listbox mirip dengan combobox yang dapat memuat banyak
pilihan dengan kemampuan
15 Scrolling:
pungnya.
scrolling15 .
Perbedaannya ia tidak
15.7. LISTBOX
151
listbox1.py
kan dua listbox kiri dan kanan yang apabila dilakukan klik ganda (
double-click16 )
listbox1.py
----------01| from qt import *
02|
03| class FormListBox(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("ListBox")
07|
daftarBuah = ["Pisang", "Jeruk", "Apel",
08|
"Mangga", "Pepaya", "Nanas", "Jambu"]
09|
label = QLabel(self)
10|
label.move( 10, 10 )
11|
label.setText( "Buah-buahan" )
12|
self.buah = QListBox(self)
13|
self.buah.setGeometry( 10, 40, 140, 120 )
14|
self.buah.insertStrList( daftarBuah )
15|
self.buah.sort()
16 Double-click:
152
16|
17|
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
41|
42|
43|
label = QLabel(self)
label.move( 170, 10 )
label.setText( "Terpilih" )
self.terpilih = QListBox(self)
self.terpilih.setGeometry( 170, 40, 140, 120 )
label = QLabel(self)
label.setGeometry( 10, 160, 200, 20 )
label.setText("Lakukan klik ganda (double click)")
self.show()
self.connect(self.buah, SIGNAL("selected(int)"),
self.buahSelected)
self.connect(self.terpilih, SIGNAL("selected(int)"),
self.terpilihSelected)
def buahSelected(self, index):
self.terpilih.insertItem( self.buah.text(index))
self.terpilih.sort()
self.buah.removeItem( index )
def terpilihSelected(self, index):
self.buah.insertItem( self.terpilih.text(index))
self.buah.sort()
self.terpilih.removeItem( index )
app = QApplication([])
fm = FormListBox()
app.setMainWidget(fm)
app.exec_loop()
15.7. LISTBOX
Berikut ini beberapa fungsi
153
QListBox
has:
sort()
insertItem()
menambah data.
removeItem()
menghapus data.
selected()
double-click ).
listbox2.py
listbox2.py
----------01| from qt import *
02|
03| class FormListBox(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("ListBox")
07|
daftarBuah = ["Pisang", "Jeruk", "Apel",
08|
"Mangga", "Pepaya", "Nanas", "Jambu"]
09|
self.buah = QListBox(self)
154
10|
11|
12|
13|
14|
15|
16|
17|
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
15.7. LISTBOX
39|
40|
41|
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
155
i = i + 1
def btKiriKlik(self):
for i in range( self.terpilih.count() ):
if self.terpilih.isSelected( i ):
self.buah.insertItem(self.terpilih.text(i))
self.buah.sort()
i = 0
while i < self.terpilih.count():
if self.terpilih.isSelected( i ):
self.terpilih.removeItem( i )
else:
i = i + 1
app = QApplication([])
fm = FormListBox()
app.setMainWidget(fm)
app.exec_loop()
Ia membu-
QListBox.Single
QListBox.Multi
fat
Pilihan bersi-
QListBox.Extended
156
range )
QListBox.NoSelection
only ).
read-
disable ), se-
enable ). enable.py
17 Dalam
sebuah form hanya ada satu objek yang fokus (focused ), artinya
157
enable.py
--------01| from qt import *
02|
03| class FormNama(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Masukkan nama")
07|
self.resize(200,80)
08|
self.nama = QLineEdit( self )
09|
self.nama.setGeometry(5,5, 100,20)
10|
self.tombol = QPushButton( self )
11|
self.tombol.setText("&OK")
12|
self.tombol.setGeometry(5,30, 60,30)
13|
self.tombol.setEnabled(0)
14|
self.show()
15|
self.connect(self.nama,
16|
SIGNAL("textChanged( const QString& )"),
17|
self.berubah)
18|
self.connect(self.tombol, SIGNAL("clicked()"),
19|
self.selesai)
20|
21|
def berubah(self, teks):
22|
if teks.isEmpty():
23|
self.tombol.setEnabled(0)
24|
else:
158
25|
26|
27|
28|
29|
30|
31|
32|
33|
self.tombol.setEnabled(1)
def selesai(self):
self.close()
app = QApplication([])
fm = FormNama()
app.setMainWidget(fm)
app.exec_loop()
setEnabled()
QWidget.
textChanged() muncul pada saat teks pada QLineEdit
berubah. Sinyal ini menyertakan isi teksnya yang bertipe QString
dimana isEmpty() menghasilkan nilai logika 1 apabila teks kosong,
dan 0 bila sebaliknya. Dengan demikian fungsi berubah() sebeini berasal dari
Sinyal
15.9 LCD
QLCDNumber merupakan label dengan tampilan seperti layar kalkulator sederhana. Contoh berikut ini menampilkan jam digital.
jamdigital.py
-------------
15.9. LCD
159
160
display()
setNumDigits()
setSegmentStyle()
mungkin adalah
Flat, Filled,
dan
Nilai yang
Outline.
Sedangkan pembahasan yang berkaitan dengan waktu dapat dilihat pada halaman 139.
161
18
shortcut-key )
alamat.py
--------01| from qt import *
02|
03| class FormAlamat(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Alamat")
07|
self.resize( 270,130 )
08|
09|
labelNama = QLabel
(
10|
self.nama = QLineEdit (
11|
labelAlamat = QLabel
(
12|
self.alamat = QLineEdit (
18 Down:
panah bawah
self
self
self
self
)
)
)
)
QLabel
162
13|
14|
15|
16|
17|
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
btOk
= QPushButton( self )
labelNama.setBuddy ( self.nama )
labelAlamat.setBuddy( self.alamat )
labelNama.setGeometry
self.nama.setGeometry
labelAlamat.setGeometry
self.alamat.setGeometry
btOk.setGeometry
(
(
(
(
(
20,20, 40,20
70,20,180,20
20,50, 50,20
70,50,180,20
90,90, 80,24
)
)
)
)
)
labelNama.setText ( "&Nama" )
labelAlamat.setText( "&Alamat" )
btOk.setText
( "&OK" )
self.show()
self.connect(btOk, SIGNAL("clicked()"),
self.selesai)
def selesai(self):
self.close()
app = QApplication([])
fm = FormAlamat()
app.setMainWidget(fm)
app.exec_loop()
print fm.nama.text(), fm.alamat.text()
labelNama dan labelAlamat yang telah
&, dan dengan menggunakan fungsi setBuddy(),
163
nama
dan
alamat.
btOk
&
ini memberikan
keypad19 )
berarti
samadengan
(=),
19 Keypad:
+, -, *, dan /.
Pastikan
164
4. Tombol Return
reset,
mengembalikan kondisi
kalkulator.py
------------01| from qt import *
02|
03| class FormKalkulator(QDialog):
04|
def __init__(self):
05|
QDialog.__init__(self)
06|
self.setCaption("Kalkulator")
07|
self.resize(640,120)
08|
self.lcd = QLCDNumber(self)
09|
self.lcd.resize( self.size() )
10|
self.lcd.setSegmentStyle(QLCDNumber.Flat)
11|
self.lcd.setNumDigits(10)
12|
self.reset()
NumLock). Pada laptop, keypad biasanya diaktifkan dengan menggunakan
tombol Fn dan tombol lainnya. Bacalah petunjuk penggunaannya.
20 Posisi
165
self.show()
def reset(self, teks=0):
self.nilai = 0
self.operator = ""
self.teks = ""
self.lcd.display(teks)
def angka(self):
if self.lcd.intValue() == self.lcd.value():
return self.lcd.intValue()
else:
return self.lcd.value()
def setAngka(self, a):
if not self.teks and a == ".":
self.teks = "0"
x = "%s%s" % (self.teks, a)
try: n = float(x)
except ValueError: return
self.teks = x
self.lcd.display(x)
def negatif(self):
self.lcd.display( - self.angka() )
def setOperator(self, op):
self.hitung()
self.operator = op
166
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
60|
61|
62|
63|
64|
65|
66|
67|
68|
69|
70|
def hitung(self):
if self.operator:
s = "self.nilai = self.nilai %s %s" % \
(self.operator, self.lcd.value() )
try:
exec(s)
except ZeroDivisionError:
self.reset("salah")
return
else:
self.nilai = self.angka()
self.lcd.display( self.nilai )
self.teks = ""
self.operator = ""
def selesai(self):
self.hitung()
self.close()
def keyPressEvent(self, e):
ch = "%s" % e.text()
if ch in ["+","-","*","/"]: self.setOperator(ch)
elif e.key() == Qt.Key_N: self.negatif()
elif e.key() == Qt.Key_Escape: self.reset()
elif e.key() == Qt.Key_Enter: self.hitung()
elif e.key() == Qt.Key_Return: self.selesai()
else: self.setAngka( ch )
167
21
key()
adalah contoh konstanta yang sudah disiapkan untuk nilai fungsi ini.
text()
state()
mengembalikan nilai
Qt.ShiftButton, Qt.ControlButton,
atau
Qt.AltButton.
value()
sedangkan
21 Event:
intValue()
menjadi integer.
168
15.10.3 NumLock
Secara default, lampu indikator NumLock tidak menyala ketika
seseorang login.
Untuk memas-
keycode 79 = 7
keycode 80 = 8
keycode 81 = 9
keycode 83 = 4
keycode 84 = 5
keycode 85 = 6
keycode 87 = 1
keycode 88 = 2
keycode 89 = 3
keycode 90 = 0
keycode 91 = period
keycode 77 =
Bila Anda
22 Home directory:
Bab 16
Kasir I
Kasir I adalah program kasir sederhana namun sudah layak dipakai untuk mencatat transaksi penjualan. Ide pembuatannya
adalah:
1. Pemakai sudah mengetahui harga jual produknya.
2. Tidak memerlukan pencatatan nama barang, yang penting nilainya tercetak.
3. Kebebasan mencatat transaksi seperti pemberian discount,
perubahan harga jual, seketika, dsb. Operasi perhitungan
dengan operator tambah, kurang, kali, dan bagi dimungkinkan.
4. Struk cukup informatif dimana tercetak rincian nilai, total
penjualan, uang yang dibayarkan serta nilai kembaliannya.
Juga tercetak tanggal dan jam transaksi.
169
170
nanti akan mengubah sifat leluhurnya agar sesuai dengan kriteria di atas. Adapun tur dari forn ini adalah:
1. Tombol Enter berarti mencetak harga barang namun yang
tampil di layar LCD adalah totalnya (akumulasi).
2. Tombol Return berarti mengasumsikan nilai yang tampil
di layar LCD adalah pembayaran. Selanjutnya nilai tersebut dikurangi total penjualan dan ditampilkan kembaliannya. Informasi yang tercetak adalah total penjualan, nilai pembayaran serta kembaliannya, dan terakhir waktu
transaksi.
Berikut ini contoh tampilan pada struk:
2.500
3.000
7.500
1 Lihat
halaman 115.
171
13.000 T
20.000 B
7.000 K
290103 16:46
Makna T, B, dan K berturut-turut adalah Total, Bayar, dan
Kembali. Baris terakhir merupakan tanggal, bulan, tahun dan
jam pencetakan.
kasir1.py
--------01| from qt import *
02| from string import rjust
03| from locale import setlocale, LC_ALL, format
04| from os import system
05| import sys
06| from kalkulator import FormKalkulator
07|
08| setlocale(LC_ALL, "")
09|
10| class FormKasir(FormKalkulator):
11|
def __init__(self):
12|
FormKalkulator.__init__(self)
13|
self.setCaption("Kasir I")
14|
if sys.argv[1:]: filename = sys.argv[1]
15|
else: filename = "/dev/lp0"
16|
self.file = open(filename, "w")
17|
self.total = 0
18|
172
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
41|
42|
43|
44|
45|
46|
47|
173
48|
49|
50|
51|
52|
53|
54|
Fungsi
self.lcd.display( kembali )
else: FormKalkulator.keyPressEvent(self, e)
app = QApplication([])
fm = FormKasir()
app.setMainWidget(fm)
app.exec_loop()
flush()
dah di-write().
/dev/null
174
Bab 17
Wadah - Container
Wadah atau
QTabWidget.
grouping ).
176
17.1 Widget
Meski selama ini
17.2 Panel
Frame (QFrame)
panel
- merupakan wadah
yang bisa diatur model bingkainya. Contoh penggunaannya dapat dilihat dalam
suhu.py
di halaman 124.
17.3 Groupbox
Groupbox (QButtonGroup) pada bahasan sebelumnya juga dikategorikan sebagai wadah. Ia dilengkapi label di atasnya sebagai
keterangan perihal daftar objek yang ada di dalamnya.
Class
box
2 (QSpinBox).
spin-
17.3. GROUPBOX
177
2. Melalui pilihan yang mewakili suhu tertentu, yaitu: dingin, hangat, dan panas.
radiobutton (QButtonGroup).
range )
berikut
ini:
suhu.py
------01| from qt import *
178
17.3. GROUPBOX
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
41|
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
179
labelSuhu.setText("Suhu (Celcius)")
labelSuhu.setAlignment( QLabel.WordBreak |
QLabel.AlignVCenter)
self.suhu = QSpinBox( panelSuhu )
self.suhu.setGeometry(65,10,40,20)
grupSuhu = QButtonGroup(self)
grupSuhu.setGeometry(140,80,110,90)
grupSuhu.setTitle("Bagi Manusia")
self.rbDingin = QRadioButton(grupSuhu)
self.rbDingin.setGeometry(10,20,96,20)
self.rbDingin.setText("Dingin")
self.rbHangat = QRadioButton(grupSuhu)
self.rbHangat.setGeometry(10,40,96,20)
self.rbHangat.setText("Hangat")
self.rbPanas = QRadioButton(grupSuhu)
self.rbPanas.setGeometry(10,60,96,20)
self.rbPanas.setText("Panas")
self.connect(self.suhu, SIGNAL(
"valueChanged(int)" ), self.suhuBerubah)
self.connect( grupSuhu, SIGNAL(
"clicked(int)"), self.grupSuhuBerubah )
self.ubah = 1
180
17.3. GROUPBOX
181
89| fm = FormSuhu()
90| app.setMainWidget(fm)
91| app.exec_loop()
QSpinBox
setValue().
valueChanged()
yang
suhu.py
adalah
Variabel
self.ubah
merupakan
variabel logika untuk mengatasi permasalahan tersebut, dan dengan demikian rekursif tak berkesudahan dapat dihindari.
Rekursif:
182
17.4 Multigroup
Objek lain yang mirip groupbox namun dapat memiliki wadah
lebih dari satu adalah
QTabWidget. tab.py
berikut menun-
QTabWidget.
tab.py
-----01| from qt import *
02|
03| class FormIdentitas(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption( "Identitas" )
07|
08|
self.TabWidget = QTabWidget(self)
09|
self.TabWidget.setGeometry(20,20,290,210)
10|
self.tabAlamat = QWidget(self.TabWidget)
11|
self.tabInternet = QWidget(self.TabWidget)
12|
self.TabWidget.insertTab(self.tabAlamat, "Alamat")
13|
self.TabWidget.insertTab(self.tabInternet,"Internet"
14|
15|
# Isi tabAlamat
16|
labelJalan = QLabel(self.tabAlamat)
17|
labelJalan.setGeometry(11,11,66,20)
18|
labelJalan.setText("Jalan")
19|
self.jalan = QLineEdit(self.tabAlamat)
17.4. MULTIGROUP
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
41|
42|
43|
44|
45|
46|
47|
48|
183
self.jalan.setGeometry(83,11,196,20)
labelKel = QLabel(self.tabAlamat)
labelKel.setGeometry(11,37,66,20)
labelKel.setText("Kelurahan")
self.kelurahan = QLineEdit(self.tabAlamat)
self.kelurahan.setGeometry(83,37,196,20)
labelKec = QLabel(self.tabAlamat)
labelKec.setGeometry(11,63,66,20)
labelKec.setText("Kecamatan")
self.kecamatan = QLineEdit(self.tabAlamat)
self.kecamatan.setGeometry(83,63,196,20)
labelPropinsi = QLabel(self.tabAlamat)
labelPropinsi.setGeometry(11,89,66,20)
labelPropinsi.setText("Propinsi")
self.propinsi = QLineEdit(self.tabAlamat)
self.propinsi.setGeometry(83,89,196,20)
labelKodePos = QLabel(self.tabAlamat)
labelKodePos.setGeometry(11,115,66,20)
labelKodePos.setText("Kode Pos")
self.kodePos = QLineEdit(self.tabAlamat, "kodePos")
self.kodePos.setGeometry(83,115,70,20)
labelTelp = QLabel(self.tabAlamat)
labelTelp.setGeometry(11,141,66,20)
labelTelp.setText("Telp")
184
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
60|
61|
62|
63|
64|
65|
66|
67|
68|
69|
70|
71|
72|
73|
74|
75|
76|
77|
self.telp = QLineEdit(self.tabAlamat)
self.telp.setGeometry(83,141,196,20)
# Isi tabInternet
labelEmail = QLabel(self.tabInternet)
labelEmail.setGeometry(11,11,41,20)
labelEmail.setText("Email")
self.email = QLineEdit(self.tabInternet)
self.email.setGeometry(58,11,211,20)
labelWeb = QLabel(self.tabInternet)
labelWeb.setGeometry(11,37,41,20)
labelWeb.setText("Web")
self.web = QLineEdit(self.tabInternet)
self.web.setGeometry(58,37,211,20)
labelYahoo = QLabel(self.tabInternet)
labelYahoo.setGeometry(11,63,41,20)
labelYahoo.setText("Yahoo")
self.yahoo = QLineEdit(self.tabInternet)
self.yahoo.setGeometry(58,63,211,20)
labelIcq = QLabel(self.tabInternet)
labelIcq.setGeometry(11,89,41,20)
labelIcq.setText("ICQ")
self.icq = QLineEdit(self.tabInternet)
self.icq.setGeometry(58,89,211,20)
self.show()
17.4. MULTIGROUP
78|
79|
80|
81|
82|
Fungsi
185
app = QApplication([])
fm = FormIdentitas()
app.setMainWidget(fm)
app.exec_loop()
Masukan pertamanya adalah wadah, sedangkan yang kedua berupa string sebagai nama kelompok.
186
Bab 18
Penataan
Menentukan posisi dan ukuran widget memang merupakan pekerjaan tersendiri. Untunglah Qt menyediakan
layouter (QLayout
kwrite
kwrite
? Bi-
ukuran
Lalu bagai-
188
yang bertugas mengatur ukuran dan posisi widget secara vertikal dan horizontal.
texteditor1.py
-------------01| from qt import *
02|
03| class FormEditor(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Text Editor")
07|
self.editor = QTextEdit(self)
08|
layout = QVBoxLayout(self)
09|
layout.addWidget( self.editor )
10|
self.show()
11|
12| app = QApplication([])
13| fm = FormEditor()
14| app.setMainWidget(fm)
15| app.exec_loop()
addWidget()
Sebagaimana
kwrite,
ukuran
QTextEdit
akan
189
texteditor2.py
-------------01| from qt import *
02|
03| class FormEditor(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Text Editor")
07|
self.editor = QTextEdit(self)
08|
panel
= QFrame (self)
09|
panel.setMinimumHeight(40)
10|
layout = QVBoxLayout(self)
11|
layout.addWidget( panel )
12|
layout.addWidget( self.editor )
13|
self.show()
14|
15| app = QApplication([])
16| fm = FormEditor()
17| app.setMainWidget(fm)
18| app.exec_loop()
setMinimumHeight()
Latihan
Gantilah
setMinimumHeight()
menjadi
setMinimumWidth().
190
addWidget()
setAutoAdd()
yang
texteditor2a.py
--------------01| from qt import *
02|
03| class FormEditor(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Text Editor")
07|
layout = QVBoxLayout(self)
08|
layout.setAutoAdd(1)
09|
panel = QFrame(self)
10|
panel.setMinimumHeight(40)
11|
self.editor = QTextEdit(self)
12|
self.show()
13|
14| app = QApplication([])
15| fm = FormEditor()
16| app.setMainWidget(fm)
17| app.exec_loop()
Simpan
Menyimpan le
191
texteditor3.py
-------------01| from qt import *
02|
03| class FormEditor(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Text Editor")
07|
layout
= QVBoxLayout( self )
08|
layout.setAutoAdd(1)
09|
panel
= QFrame
( self )
10|
self.editor = QTextEdit ( self )
11|
12|
layout
= QHBoxLayout( panel )
13|
layout.setAutoAdd(1)
14|
btBaru
= QPushButton( panel )
15|
btBuka
= QPushButton( panel )
16|
btSimpan
= QPushButton( panel )
17|
btSimpanSbg = QPushButton( panel )
18|
19|
btBaru.setText
( "Baru" )
20|
btBuka.setText
( "Buka" )
21|
btSimpan.setText ( "Simpan" )
22|
btSimpanSbg.setText( "Simpan Sebagai" )
192
23|
24|
25|
26|
27|
28|
29|
self.showMaximized()
app = QApplication([])
fm = FormEditor()
app.setMainWidget(fm)
app.exec_loop()
Perhatikan, kini
lagi.
Kelihatannya
showMaximized()
maximized ),
form diperbesar (
besar.
addStretch(). Fungsi
QHBoxLayout dan QVBoxLayout.
QBoxLayout,
leluhur
texteditor3a.py
--------------01| from qt import *
02|
03| class FormEditor(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Text Editor")
ini
193
layout
= QVBoxLayout( self )
layout.setAutoAdd(1)
panel
= QFrame
( self )
self.editor = QTextEdit ( self )
layout
= QHBoxLayout(
layout.setAutoAdd(1)
layout.addStretch()
btBaru
= QPushButton(
btBuka
= QPushButton(
btSimpan
= QPushButton(
btSimpanSbg = QPushButton(
btBaru.setText
(
btBuka.setText
(
btSimpan.setText (
btSimpanSbg.setText(
panel )
panel
panel
panel
panel
)
)
)
)
"Baru" )
"Buka" )
"Simpan" )
"Simpan Sebagai" )
self.showMaximized()
app = QApplication([])
fm = FormEditor()
app.setMainWidget(fm)
app.exec_loop()
194
195
app = QApplication([])
fm = FormEditor()
app.setMainWidget(fm)
app.exec_loop()
setDirection()
LeftToRight
RightToLeft
Down
Up
Dari beberapa contoh di atas tentang penggunaan layouter, dapat diambil beberapa kesimpulan:
1. Layouter hanya berfungsi sebagai penata widget - baik
ukuran maupun posisi - bukan suatu wadah.
2. Layouter akan memenuhi wadah (parent) dengan widget
(child) yang diaturnya.
196
tab.py
QGridLayout
grid ),
alamat1.py
---------01| from qt import *
02|
03| class FormAlamat(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Alamat")
07|
layout = QGridLayout( self )
08|
layout.setMargin(5)
09|
labelNama = QLabel
( self )
10|
labelAlamat = QLabel ( self )
11|
self.nama = QLineEdit( self )
12|
self.alamat = QLineEdit( self )
13|
labelNama.setText
("Nama")
14|
labelAlamat.setText
("Alamat")
15|
layout.addWidget(labelNama,
0,0)
16|
layout.addWidget(labelAlamat, 1,0)
17|
layout.addWidget(self.nama,
0,1)
18|
layout.addWidget(self.alamat, 1,1)
19|
self.show()
20|
21| app = QApplication([])
22| fm = FormAlamat()
197
23| app.setMainWidget(fm)
24| app.exec_loop()
setMargin()
QLayout,
Fungsi ini
leluhur
QGridLayout.
alamat2.py
---------01| from qt import *
02|
03| class FormAlamat(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Alamat")
07|
layout = QGridLayout( self, 2,2 )
08|
layout.setAutoAdd(1)
09|
layout.setMargin(5)
10|
labelNama = QLabel
( self )
11|
self.nama = QLineEdit( self )
198
12|
13|
14|
15|
16|
17|
18|
19|
20|
21|
Bab 19
Waktu
Qt memiliki class khusus berkaitan dengan waktu, yaitu
(jam),
QDate
(tanggal), dan
QDateTime
QTime
19.1 Jam
QTime
200
hour()
jam
minute()
menit
second()
detik
msec()
milidetik
addSecs(n ) tambah n
QTime.
secsTo(t )
detik dimana
integer, mengembalikan
toString()
t (QTime).
jam tanpa nol di depan (0..23 atau 1..12 jika ditampilkan dengan AM/PM)
hh
jam dengan nol di depan (00..23 atau 01..12 jika ditampilkan dengan AM/PM)
mm
ss
zzz
menampilkan AM/PM.
ap
menampilkan am/pm.
201
Berikut ini
currentDate()
year()
tahun.
month()
bulan.
day()
tanggal.
dayOfWeek()
Minggu = 7.
dayOfYear()
QDate.
daysInMonth()
daysInYear()
month()
year()
202
addDays(n )
menambah
addMonths(n )
addYears()
daysTo(d )
menambah
menambah
hari, mengembalikan
QDate.
bulan, mengembalikan
tahun, mengembalikan
d (QDate),
QDate.
QDate.
mengembalikan in-
teger.
toString()
dd
ddd
dddd
MM
MMM
MMMM
yy
yyyy
203
Class ini bisa kita denisi ulang (reimplementation) agar berbahasa Indonesia. Format yang ditambahkan adalah:
hari
bulan
pasaran
Class-nya dinamakan
tanggal.py
---------01| from qt import *
02| import string
03|
04| class Tanggal(QDate):
05|
Hari = ["Senin","Selasa","Rabu","Kamis",
06|
"Jumat","Sabtu","Minggu"]
07|
Bulan = ["Januari","Februari","Maret","April","Mei",
08|
"Juni","Juli","Agustus","September","Oktober",
09|
"November","Desember"]
10|
Pasaran = ["Pon","Wage","Kliwon","Legi","Pahing"]
11|
12|
# Konstanta: 1-2-2003 Pon
13|
TGL = QDate(2003,2,1)
14|
15|
def __init__(self, y, m, d):
16|
QDate.__init__(self, y, m, d)
204
17|
18|
def toString(self,
19|
format="hari pasaran, dd bulan yyyy"):
20|
s = str(QDate.toString(self, format))
21|
if string.find(s, "hari") > -1:
22|
hari = self.Hari[self.dayOfWeek()-1]
23|
s = string.replace(s, "hari", hari)
24|
if string.find(s, "bulan") > -1:
25|
bln = self.Bulan[self.month()-1]
26|
s = string.replace(s, "bulan", bln)
27|
if string.find(s, "pasaran"):
28|
jml = self.TGL.daysTo(self)
29|
sisa = jml % 5
30|
psr = self.Pasaran[sisa]
31|
s = string.replace(s, "pasaran", psr)
32|
return QString(s)
33|
34|
35| if __name__ == "__main__":
36|
n = QDate.currentDate()
37|
t = Tanggal(n.year(), n.month(), n.day())
38|
print t.toString()
adalah gabungan
QDate
t = QDate.currentDate()
dan
QTime.
Inisialisasinya
19.4. TIMER
205
j = QTime.currentTime()
w = QDateTime( t, j )
Adapun fungsi yang sering digunakan adalah:
currentDateTime()
date()
time()
toString()
QDateTime.
QTime.
QDate dan
19.4 Timer
Pewaktu atau
atu
QObject
Fitur
pada Qt.
startTimer()
timerEvent()
WaktuDigital
206
Bab 20
Form Dialog
Form dialog (QDialog) dibangun dengan konsep untuk melaksanakan suatu fungsi form yang singkat, misalnya menampilkan pesan, pengisian username dan password untuk login, dsb.
QDialog biasanya dipanggil dari form lain yang menjadi parentnya. Beberapa turnya antar lain:
1. Fungsi
menghasilkan
iya-kan" input.
2. Fungsi
bernilai
put.
3. Bila Enter ditekan sama artinya dengan meng-klik tombol
207
208
default.
ngan fungsi
QPushButton.setDefault().
reject().
dialog.py
--------01| from qt import *
02|
03| class FormNama(QDialog):
04|
def __init__(self, parent):
05|
QDialog.__init__(self, parent)
06|
self.setCaption("Nama")
07|
layout = QVBoxLayout( self )
08|
layout.setAutoAdd(1)
09|
10|
self.nama = QLineEdit( self )
11|
wadah
= QWidget ( self )
12|
13|
layout
= QHBoxLayout( wadah )
14|
layout.setAutoAdd(1)
15|
self.tombolOK
= QPushButton( wadah )
16|
self.tombolBatal = QPushButton( wadah )
17|
18|
self.tombolOK.setText
("&OK")
19|
self.tombolBatal.setText ("&Batalkan")
20|
self.tombolOK.setDefault(1)
21|
self.connect(self.tombolOK, SIGNAL("clicked()"),
22|
self.ok)
209
self.connect(self.tombolBatal, SIGNAL("clicked()"),
self.batal)
def ok(self):
self.accept()
def batal(self):
self.reject()
app = QApplication([])
fm = FormNama(None)
fm.show()
fm.exec_loop()
if fm.result() == QDialog.Accepted:
print "Inputnya:", fm.nama.text()
else:
print "Input dibatalkan"
Pemanggilan
exec_loop()
showmodal
QDialog.
QMessageBox,
atau
QInputDialog.
QFileDialog,
210
texteditor4.py
berikut ini
texteditor4.py
-------------01| from qt import *
02|
03| class FormEditor(QWidget):
04|
def __init__(self):
05|
QWidget.__init__(self)
06|
self.setCaption("Text Editor")
07|
layout = QVBoxLayout( self )
08|
layout.setAutoAdd(1)
09|
panel
= QFrame ( self )
10|
self.editor = QTextEdit( self )
11|
font
= self.editor.font()
12|
font.setFamily("Courier")
13|
self.editor.setFont( font )
14|
15|
layout = QHBoxLayout( panel )
16|
layout.setAutoAdd(1)
17|
layout.addStretch()
211
layout.setDirection( QBoxLayout.RightToLeft )
btSimpanSbg
btSimpan
btBuka
btBaru
=
=
=
=
QPushButton(
QPushButton(
QPushButton(
QPushButton(
btBaru.setText
(
btBuka.setText
(
btSimpan.setText (
btSimpanSbg.setText(
panel
panel
panel
panel
)
)
)
)
"Baru" )
"Buka" )
"Simpan" )
"Simpan Sebagai" )
self.setFilename( None )
self.showMaximized()
self.connect(btBaru, SIGNAL("clicked()"), self.baru)
self.connect(btBuka, SIGNAL("clicked()"), self.buka)
self.connect(btSimpan, SIGNAL("clicked()"),
self.simpan)
self.connect(btSimpanSbg, SIGNAL("clicked()"),
self.simpanSbg)
def _simpan(self, filename):
f = open( filename, "w" )
f.write( "%s" % self.editor.text() )
f.close()
def setFilename(self, filename):
self.filename = filename
212
213
76| fm = FormEditor()
77| app.setMainWidget(fm)
78| app.exec_loop()
getOpenFileName() dan getSaveFileName() merupakan fungsi
siap pakai untuk menampilkan le dialog. Keduanya mengembalikan nama le (QString) apabila tombol OK diklik.
Jika
yaitu
huruf
M sama besar, hal yang biasa kita perlukan untuk mengedit
suatu le teks.
Latihan
texteditor4.py sudah memenuhi syarat untuk sebuah aplikasi
text editor, namun perlu ditingkatkan lagi faktor kenyamanan
penggunaannya, terutama berkaitan dengan tombol:
1. Saat pertama kali program dijalankan, tombol yang aktif
hanyalah Buka.
apakah ada perubahan pada editor sejak ia terakhir disimpan. Bila ya maka ke empat tombol aktif. Sebaliknya bila
tidak terjadi perubahan - misalnya setelah tombol Simpan di-klik - maka tombol yang aktif adalah Baru dan
Simpan Sebagai.
Petunjuk
Gunakan
setEnabled().
214
Konrmasi ini
QMessageBox
icon ) sehubun-
texteditor5.py
-------------001| from qt import *
002|
215
216
032|
033|
034|
035|
036|
037|
038|
039|
040|
041|
042|
043|
044|
045|
046|
047|
048|
049|
050|
051|
052|
053|
054|
055|
056|
057|
058|
059|
060|
217
218
090|
091|
092|
093|
094|
095|
096|
097|
098|
099|
100|
101|
102|
103|
104|
105|
106|
107|
108|
109|
110|
111|
112|
113|
114|
115|
116|
def simpanSbg(self):
if not self.berubah: return
tanya = 1
while tanya:
filename = QFileDialog(self).getSaveFileName()
if filename.isEmpty(): return
if QFile.exists( filename ):
pesan="File %s sudah ada. Timpa ?" % filename
id = QMessageBox.warning( self, "Perhatian",
pesan, "Ya", "Jangan", "Kembali")
if id == 2: return
if id == 0: tanya = 0
else:
tanya = 0
_filename = "%s" % filename
self._simpan( _filename )
self.setFilename( _filename )
return 1
def closeEvent(self, e):
if self.lanjutkan(): e.accept()
else
: e.ignore()
app = QApplication([])
fm = FormEditor()
app.setMainWidget(fm)
app.exec_loop()
20.3. INPUT
QMessageBox
219
menyediakan fungsi
warning()
yang mengemba-
closeEvent()
Latihan
(milik
Anda dapat
20.3 Input
Bila dalam program Anda ada sebuah proses yang membutuhkan sebuah masukan saja, maka
ban yang tepat. Berikut ini program kasir layak pakai dimana
nama barang, jumlah, serta harga satuannya dimasukkan menggunakan
QInputDialog.
input.py
-------01| from qt import *
02| from string import
03| from locale import
04| import sys
05|
06| def cetak(s):
07|
if sys.argv[1:]:
08|
else:
output = sys.argv[1]
output = "/dev/lp0"
220
09|
10|
11|
12|
13|
14|
15|
16|
17|
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
file = open(output,"w")
c = chr(15) + s + "\n"
file.write(c)
file.close()
def cetakBrg(nama, jml, hrg):
j = format("%.2f", jml, 1)
h = format("%d", hrg, 1)
a = ljust(nama[:20], 20)
b = rjust(j, 7)
c = rjust(h, 8)
s = "%s%s%s" % (a,b,c)
cetak(s)
def cetakAkhir(nama, nilai):
n = format("%d", nilai, 1)
a = ljust(nama, 27)
b = rjust(n, 8)
s = "%s%s" % (a,b)
cetak(s)
setlocale(LC_ALL, "")
total = 0
app = QApplication([])
while 1:
nama, ok = QInputDialog.getText("Kasir",
"Nama barang (Enter: Total, Esc: Selesai)",
QLineEdit.Normal, "")
20.3. INPUT
38|
39|
40|
41|
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
60|
61|
221
$ python input.py
namun bila printer tidak ada, masukkan nama le pengganti:
222
QInputDialog
Bab 21
Tabel
Tabel merupakan daftar yang terdiri dari baris dan kolom. Qt
telah menyediakan class
Sifat
QTable
pada aplikasi
spreadsheet 1 .
sheet
1 Spreadsheet
223
224
cell.2
cell.
qtable1.py
---------01| from qt import *
02| from qttable import QTable
03|
04| class FormTable(QWidget):
05|
def __init__(self):
06|
QWidget.__init__(self)
07|
self.setCaption("Table")
08|
kolom = [ "Nama", "Alamat" ]
09|
isi = [
10|
[ "Pribadi Endro", "Kemayoran" ],
11|
[ "Ahmad", "Purwokerto" ],
12|
[ "Putera Sinaga", "Bogor" ]
13|
]
14|
self.t = QTable(self)
15|
self.t.setNumCols( len(kolom) )
16|
self.t.setNumRows( len(isi) )
17|
i = -1
2 Cell:
elemen pada
QTable
225
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
QTable
setNumCols()
setNumRows()
226
horizontalHeader()
yang bertipe
QHeader.
Fungsi
setLabel()-nya
di-
cell ) tertentu.
setText()
text()
currentChanged()
current cell 3
berubah.
Secara default
QTable
ubah isi, lebar baris, dan lebar kolom pada saat runtime.
Beberapa tombol keyboard berikut ini juga dapat Anda gunakan:
F2
isi cell siap diubah. Pada kasus isi cell terlalu panjang namun Anda hanya ingin mengubah sedikit saja maka tombol ini sangat berguna.
Escape
membatalkan perubahan
QTable
227
Grid.
menyisipkan baris
Down
da di baris terakhir.
Delete
4 pada baris
4 Kolom
setHide().
Kolom seperti
Sehingga dikatakan
228
QTable
tidak menunjukkan
focus widget.5
memiliki widget lebih dari satu tentu saja bisa membingungkan pemakai. Pada
agar tampak
2.
QTable
focus -nya.
Grid
grid.py
------01| from qt import *
02| from qttable import QTable
03|
04| class Grid(QTable):
05|
def __init__(self, parent):
06|
QTable.__init__(self, parent)
07|
self.setNumRows(1)
08|
09|
def activateNextCell(self):
10|
if self.currentColumn() < self.numCols()-1:
5 focus
widget: objek aktif yang siap menerima input atau aksi lainnya.
229
self.setCurrentCell(self.currentRow(),
self.currentColumn()+1)
def setNumRows(self, count):
if count > 1: c = count
else:
c = 1
QTable.setNumRows(self, c)
def insertRows(self, row, count=1):
QTable.insertRows(self, row, count)
self.setCurrentCell( row, self.kolomKiri() )
def removeRow(self, row):
r = self.currentRow()
if self.numRows() > 1: QTable.removeRow(self, row)
else:
for col in range( self.numCols() ):
self.clearCell( row, col )
if r == self.numRows(): r = self.numRows() - 1
self.setCurrentCell( r, self.currentColumn() )
def sisip(self):
self.insertRows( self.currentRow() )
def turun(self):
if self.currentRow() == self.numRows()-1:
self.insertRows( self.numRows() )
else:
self.setCurrentCell( self.currentRow()+1,
230
40|
41|
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
60|
61|
62|
63|
64|
65|
66|
67|
68|
self.currentColumn() )
def hapusCell(self):
self.clearCell( self.currentRow(),
self.currentColumn() )
def hapusBaris(self):
self.removeRow( self.currentRow() )
def kolomKiri(self):
col = 0
while self.columnWidth(col) == 0:
if col == self.numCols()-1: return col
col = col + 1
return col
def kolomKanan(self):
col = self.numCols()-1
while self.columnWidth(col) == 0:
if col == 0: return col
col = col - 1
return col
def kiriAtas(self):
self.setCurrentCell(0, self.kolomKiri() )
def palingKiri(self):
self.setCurrentCell( self.currentRow(),
self.kolomKiri() )
231
69|
70|
def kananBawah(self):
71|
self.setCurrentCell( self.numRows()-1,
72|
self.kolomKanan() )
73|
74|
def palingKanan(self):
75|
self.setCurrentCell( self.currentRow(),
76|
self.kolomKanan() )
77|
78|
def keyPressEvent(self, e):
79|
if self.numCols() == 0: return
80|
elif e.key() == Qt.Key_Insert: self.sisip()
81|
elif e.key() == Qt.Key_Down: self.turun()
82|
elif e.key() == Qt.Key_Delete:
83|
if e.state() == Qt.ControlButton: self.hapusBaris()
84|
else: self.hapusCell()
85|
elif e.key() == Qt.Key_Home:
86|
if e.state() == Qt.ControlButton: self.kiriAtas()
87|
else: self.palingKiri()
88|
elif e.key() == Qt.Key_End:
89|
if e.state() == Qt.ControlButton: self.kananBawah()
90|
else: self.palingKanan()
91|
else: QTable.keyPressEvent(self, e)
92|
93| if __name__ == "__main__":
94|
app = QApplication([])
95|
fm = Grid(None)
96|
fm.setNumCols(5)
97|
fm.show()
232
98|
99|
app.setMainWidget(fm)
app.exec_loop()
__init__()
memastikan
activateNextCell()
Grid
setNumRows()
Grid
6 berakhir)
- setidaknya - memi-
insertRows()
removeRow()
clearCell()
setCurrentCell()
keyPressEvent()
6 Edit-mode:
233
ValueGrid
234
exec()
Fungsi
9. Baris aktif (
ribu()
fungsi.py
--------01| import string
02| import locale
03| from math import *
04|
05| locale.setlocale(locale.LC_ALL, "")
06|
07|
235
236
37|
return
valuegrid.py
valuegrid.py
-----------001| from qt import *
002| from qttable import QTable
003| from grid import Grid
004| from fungsi import angka, ribu
005|
006| class ValueGrid(Grid):
007|
def __init__(self, parent):
008|
Grid.__init__(self, parent)
009|
self.penBox = QPen()
010|
self.penBox.setColor( QColor("lightgray") )
011|
self.penText = QPen()
012|
self.penText.setColor( QColor("black") )
013|
self.brushCurrent = QBrush()
014|
self.brushCurrent.setColor( QColor("yellow") )
015|
self.brushCurrent.setStyle( QBrush.SolidPattern )
016|
self.data = []
017|
self._row = 0 # baris terakhir sebelum currentRow(
018|
self.beforeDelete = None # sebelum data dihapus
019|
self.connect(self, SIGNAL("currentChanged(int,int)"
020|
self.saatPindah)
021|
237
238
051|
052|
053|
054|
055|
056|
057|
058|
059|
060|
061|
062|
063|
064|
065|
066|
067|
068|
069|
070|
071|
072|
073|
074|
075|
076|
077|
078|
079|
239
s = ribu(a)
align = QPainter.LTR
else:
s = d
else:
s = ""
if row == self.currentRow() and self.data:
painter.fillRect( 0,0, cr.width(), cr.height(),
self.brushCurrent )
else:
painter.eraseRect( 0,0, cr.width(), cr.height() )
painter.setPen( self.penBox )
painter.drawLine( 0, cr.height()-1, cr.width(),
cr.height()-1 )
painter.drawLine( cr.width()-1, cr.height()-1,
cr.width()-1, 0 )
painter.setPen( self.penText )
painter.drawText(2,2, cr.width()-4, cr.height()-4,
align, s)
def saatPindah(self, row, col):
if row != self._row:
r = self.cellGeometry( self._row, 0 )
r.setRight( self.width() )
self.repaintContents(r)
r = self.cellGeometry( row, 0 )
r.setRight( self.width() )
self.repaintContents(r)
self._row = row
240
109|
110|
111| if __name__ == "__main__":
112|
app = QApplication([])
113|
fm = ValueGrid(None)
114|
data = [ [1001,"Belimbing",3000.0,"Kg"],
115|
[1287,"Jeruk","=7000+500.0","Kg" ] ]
116|
fm.setNumCols(4)
117|
fm.setData(data)
118|
fm.show()
119|
app.setMainWidget(fm)
120|
app.exec_loop()
Adapun fungsi yang ditulisulang adalah:
___init__()
QPen
menggambar kotak.
resizeData()
na
ValueGrid
QTable.
Kare-
pass
ri.
setNumCols()
insertRows()
removeRow()
insertRows().
241
QLineEdit,
lah
Standarnya ada-
initFromCell
bernilai logika
setCellContentFromEditor()
createEditor() belum
Fungsi
cellWidget()
clearCell()
updateCell()
memanggil
paintCell()
form di-
tion
ValueGrid
memi-
paintCell()
7 Lihat
242
es penggambaran.
painter
bertipe
QPainter
yang
8 ).
selected
col
cr
row
(sedang fokus).
paintCell()
baris
QPen
Merupakan pena gambar yang dipakai
QPainter.
Fungsi
setColor()
QBrush
Merupakan cat yang dipakai
pada latar belakang (
8 Lihat
QPainter
background ).
QRect.
Fungsi
setColor()-nya
un-
243
NoBrush
SolidPattern
kepadatan 100%.
Dense1Pattern
kepadatan 94%.
Dense2Pattern
kepadatan 88%.
Dense3Pattern
kepadatan 63%.
Dense4Pattern
kepadatan 50%.
Dense5Pattern
kepadatan 37%.
Dense6Pattern
kepadatan 12%.
Dense7Pattern
kepadatan 6%.
HorPattern
garis horizontal.
VerPattern
garis vertikal.
CrossPattern
kotak-kotak.
BDiagPattern
FDiagPattern
DiagCrossPattern
belah ketupat.
244
QPainter
Merupakan alat gambar pada widget.
fillRect()
eraseRect()
setPen()
drawLine()
membuat garis.
drawText()
membuat tulisan.
align yang menentukan apakah tulisan ditampilkan rata kiri (RTL) atau rata kanan (LTR).
masukan
QRect
shape ).
x()
y()
height()
width()
setX().
setY().
setHeight().
setWidth().
right()
top()
setLeft().
x().
Untuk mengubah-
left() + width().
setRight().
y().
bahnya gunakan
bottom()
245
setTop().
Untuk mengu-
top() + height().
setBottom().
2. Pencarian berdasarkan nama dan tidak membedakan huruf kecil maupun besar.
246
Nama;Harga
mangga harum manis;9000
mangga indramayu;7000
jeruk medan;6500
semangka tanpa biji;3000
semangka kuning;5000
duku;5500
rambutan binjai;3000
rambutan rapiah;6000
durian monthong;10000
alpukat;4000
anggur merah;20000
247
anggur hijau;15000
jeruk lokam;8000
jeruk pakistan;10000
mangga golek;5000
mangga gedong;15000
lengkeng impor;10000
lengkeng lokal;7000
pir australia;12000
pir shandong;9000
Seperti terlihat pada contoh di atas, pemisah antar eld menggunakan karakter titik koma (;).
Un-
TableFile.
linecase9
cari.py
------001| from
002| from
003| from
004| from
005|
9 Lihat
qt import *
valuegrid import ValueGrid
string import splitfields, strip, upper
linecase import LineCase
halaman 94.
248
249
035|
036|
def teksBerubah(self, w):
037|
if self.cari() < 0 and self.cari(0) < 0:
038|
QMessageBox.warning(self, "Perhatian",
039|
"%s tidak ditemukan" % w.text())
040|
041|
def cari(self, awalan=1, mulaiBaris=-1):
042|
s = "%s" % self.teks.text().upper()
043|
brs = mulaiBaris
044|
ketemu = 0
045|
while brs < self.tabel.numRows()-1:
046|
brs = brs + 1
047|
data = self.tabel.data[brs][self.kolomCari]
048|
t = QString(data).upper()
049|
if awalan: ketemu = t.find(QRegExp("^"+s)) > -1
050|
else: ketemu = t.find(s) > -1
051|
if ketemu:
052|
if self.tabel.currentRow() != brs:
053|
self.tabel.setCurrentCell(brs, self.kolomCari)
054|
return brs
055|
return -1
056|
057|
def lanjut(self):
058|
if self.teks.text().isEmpty(): return
059|
if self.cari(0, self.tabel.currentRow() ) < 0:
060|
self.cari(0)
061|
062|
063| """ TableFile
250
251
093|
for field in fields:
094|
n = strip(field)
095|
if uppercase: n = upper(n)
096|
try:
097|
n = float(n)
098|
if n == int(n): n = int(n)
099|
except ValueError:
100|
pass
101|
rec.append(n)
102|
self.records.append( rec )
103|
104|
105| if __name__ == "__main__":
106|
import sys
107|
filename = sys.argv[1]
108|
t = TableFile( filename )
109|
110|
app = QApplication([])
111|
fm = FormCari(None, t.records, t.labels)
112|
fm.tabel.setColumnWidth(0,200)
113|
fm.showMaximized()
114|
fm.exec_loop()
115|
if fm.result() == QDialog.Accepted:
116|
row = fm.tabel.currentRow()
117|
col = fm.tabel.currentColumn()
118|
print fm.tabel.data[row][col]
Misalkan sumber data disimpan dalam le
barang.csv
maka
252
FormCari
sebenarnya membe-
tertentu pada
keyPressEvent()
pixel.
Perhatikan
mat waktu karena tidak harus menekan tombol Tab untuk memindahkan fokus ke
10 Regular
tabel.
Bab 22
Kasir II
Kasir II merupakan aplikasi kasir yang memiliki tur lebih ke-
cari.py.
1 Lihat
2 Lihat
halaman 119.
halaman 168.
253
254
RAMBUTAN BINJAI
ANGGUR MERAH
TOTAL
BAYAR
KEMBALI
30-01-03 00:42
50,25 150.750
5,65 113.000
263.750
300.000
36.250
Jadi secara umum Kasir II masih menyimpan sifat kesederhanaan Kasir I yaitu kemudahan instalasi dan perawatan.
kasir2.py
--------01| from qt import *
02| from cari import FormCari
03| from fungsi import ribu
04| from string import rjust, ljust
05|
06| class FormKasir(FormCari):
07|
def __init__(self, parent, t, output="/dev/lp0"):
255
08|
09|
10|
11|
12|
13|
14|
15|
16|
17|
18|
19|
20|
21|
22|
23|
24|
25|
26|
27|
28|
29|
30|
31|
32|
33|
34|
35|
36|
256
37|
38|
39|
40|
41|
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
60|
61|
62|
63|
64|
65|
nama = self.tabel.data[row][0]
harga = self.tabel.data[row][1]
jml, ok = QInputDialog.getDouble(nama,
"Sebanyak", 1, 0, 99999, 2)
if ok:
subtotal = int(jml * harga)
self.total = self.total + subtotal
self.lcd.display( ribu(self.total) )
self.cetakBarang(nama, jml, subtotal)
self.teks.selectAll()
def bayar(self):
s = "%s" % self.teks.text()
try: bayar = int(s)
except ValueError: return
kembali = bayar - self.total
self.lcd.display( ribu(kembali) )
self.cetakAkhir("TOTAL", self.total)
self.cetakAkhir("BAYAR", bayar)
self.cetakAkhir("KEMBALI", kembali)
w = QDateTime.currentDateTime().toString(
"dd-MM-yy hh:mm")
s = "\n" * 5
self.cetak( "%s%s" % (w,s) )
self.teks.clear()
self.total = 0
return 1
def cetak(self, s):
257
66|
self.file.write(chr(15)+s)
67|
self.file.flush()
68|
69|
def cetakBarang(self, nama, jml, subtotal):
70|
_nama = ljust(nama[:20], 20)
71|
_jml = rjust(ribu(jml), 7)
72|
_subtotal = rjust(ribu(subtotal),8)
73|
s = "%s%s%s\n" % (_nama, _jml, _subtotal)
74|
self.cetak(s)
75|
76|
def cetakAkhir(self, nama, total):
77|
_nama = ljust(nama,10)
78|
_total = rjust(ribu(total),25)
79|
s = "%s%s\n" % (_nama, _total)
80|
self.cetak(s)
81|
82|
83| if __name__ == "__main__":
84|
import sys
85|
from cari import TableFile
86|
87|
filename = sys.argv[1]
88|
t = TableFile( filename )
89|
if sys.argv[2:]: output = sys.argv[2]
90|
else:
output = "/dev/lp0"
91|
app = QApplication([])
92|
fm = FormKasir(None, t, output)
93|
fm.showMaximized()
94|
fm.exec_loop()
258
cari.py:
Jangan
ready ).
Apabila Anda ingin menyimpan transaksi ke sebuah le maka tambahkan nama lenya:
/dev/null
Bab 23
Database
Database merupakan penyimpan data yang terpisah dari program. File
database le.
database server , yaitu suatu program yang dirancang khusus untuk menyimini database yang dimaksud adalah menggunakan
driver
sebagai penghubungnya.
Qt
qtsql.
1 Beberapa
259
260
connection ID
2 dengan menggunakan
connection ID
tersebut
username, password, dan hostname (bisa juga nomor IP ). Pada Qt informasi lain yang dibutuhkan adalah nama driver yang
akan digunakan. Driver ini merupakan penghubung aplikasi dengan database bersangkutan. Qt memiliki beberapa driver untuk login ke beberapa produk database.
Sebelum Anda mencoba contoh program berikutnya, pastikan
database PostgreSQL atau MySQL terpasang dengan baik.
superuser
ke database server.
261
root-nya.4
ma database yang akan dibuat adalah latihan.
postgres-nya,
Sedangkan na-
23.1.1 PostgreSQL
Pertama kali sistem PostgreSQL terpasang, user yang sudah
dibuat adalah postgres dengan database template1.
Berbekal
psql
query.
262
latihan=#
Sampai di sini Anda siap untuk membuat tabel.
23.1.2 MySQL
MySQL juga memiliki program serupa, yaitu
nya pun hampir sama:
mysql.
Langkah-
$ mysql -u root
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 3.23.49
Type 'help;' or '\h' for help. Type '\c' to clear the buffer
mysql> CREATE DATABASE latihan;
Query OK, 1 row affected (0.14 sec)
5 Perhatikan,
option
-u
263
mysql> \q
Bye
$
Kemudian lanjutkan dengan login ke database latihan:
multiuser ).
pengguna (
264
login.py
gram utama untuk proses login. Fitur yang ada dalam form ini
adalah:
1. Pengguna cukup mengisikan username dan password, karena data mengenai driver dan hostname sudah dideniskan
(hardcode).
2. Untuk login cukup klik tombol OK atau tekan Enter.
Meski ada pertanyaan password, Anda bisa mengosongkannya
apabila memang instalasi server database masih default.
login.py
-------01| from qt import *
02| from qtsql import QSqlDatabase
03|
04| """ Driver
05|
QPSQL7 : PostgreSQL
06|
QMYSQL3 : MySQL
07|
QODBC3 : ODBC
08|
QOCI8 : Oracle
09|
QTDS7 : Sybase / MS SQL Server
10| """
11|
12| DB_DRIVER = "QPSQL7"
13| DB_USER
= "postgres"
14|
15| #DB_DRIVER = "QMYSQL3"
#DB_USER
265
= "root"
#DB_DRIVER = "QOCI8"
#DB_USER
= "scott"
DB_NAME = "latihan"
DB_HOST = "localhost"
class FormLogin(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.resize(150,100)
self.setCaption("Login")
layout = QVBoxLayout(self)
layout.setAutoAdd(1)
layout.setMargin(5)
wadahInput = QWidget(self)
layout = QGridLayout(wadahInput, 2,2)
layout.setAutoAdd(1)
layout.setSpacing(5)
labelUsername = QLabel ( wadahInput )
self.username = QLineEdit( wadahInput )
labelPassword = QLabel ( wadahInput )
self.password = QLineEdit( wadahInput )
labelUsername.setText( "Username" )
labelPassword.setText( "Password" )
self.username.setText( DB_USER )
self.password.setEchoMode( QLineEdit.Password )
266
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
57|
58|
59|
60|
61|
62|
63|
64|
65|
66|
67|
68|
69|
70|
71|
72|
73|
wadahTombol = QWidget(self)
layout = QHBoxLayout( wadahTombol )
layout.setAutoAdd(1)
layout.setSpacing(5)
tombolOk
= QPushButton( wadahTombol )
tombolBatal = QPushButton( wadahTombol )
tombolOk.setAutoDefault(1)
tombolOk.setText ( "OK" )
tombolBatal.setText( "Batalkan" )
self.db = QSqlDatabase.addDatabase( DB_DRIVER )
self.db.setHostName
( DB_HOST )
self.db.setDatabaseName
( DB_NAME )
267
74|
self.reject()
75|
else:
76|
self.username.clear()
77|
self.password.clear()
78|
self.username.setFocus()
79|
80|
def batal(self):
81|
self.reject()
82|
83|
84| if __name__ == "__main__":
85|
app = QApplication([])
86|
if FormLogin(None).db.isOpen():
87|
print "Login berhasil"
88|
else:
89|
print "Login dibatalkan"
Bagi pengguna MySQL hapuslah remark (#) pada baris berikut:
#DB_DRIVER = "QMYSQL3"
#DB_USER
= "root"
Form ini dapat digunakan sebagai otorisasi penggunaan program dimana aplikasi tidak perlu dilanjutkan manakala proses login gagal. Perhatikan baris yang berisi pesan keberhasilan
proses login. Pada blok itulah Anda dapat meletakkan pemanggilan form utama.
QSqlDatabase
268
addDatabase()
mengembalikan
QSqlDatabase juga.
Fungsi ini
membutuhkan nama driver yang akan digunakan untuk menghubungi server database.
setHostName()
setDatabaseName()
setUsername()
setPassword()
menentukan password.
open()
isOpen()
lastError()
databaseText()-nya
salahan.
CREATE TABLE
23.4. QUERY
269
TEXT
dibatasi. Ketiadaan
NOT NULL
boleh tidak.
23.4 Query
7
dan
DELETE.8
6 Kehampaan dalam eld adalah NULL. Perlu diketahui juga bahwa string
hampa ("") yang selama ini kita kenal sebagai kehampaan bagi string bukan
kehampaan bagi eld.
query
270
Kini akan kita buat form yang memiliki keempat fungsi tersebut sesuai dengan struktur tabel di atas.. Fitur lainnya adalah:
1. Nama ditampilkan dalam sebuah combobox yang dapat
di-edit. Sedangkan alamat tetap ditampilkan dalam textedit.
2. Alamat yang tampil akan disesuaikan dengan nama yang
tampak pada combobox.
3. Ada dua tombol untuk menyimpan dan menghapus.
Tombol simpan dihadapkan pada dua kemungkinan dalam menyimpan data:
1. Apabila data baru maka ia menggunakan
INSERT.
UPDATE.
relasi3.py
---------001| from qt import *
002| from qtsql import QSqlQuery
003| from string import replace
004| from login import FormLogin
23.4. QUERY
271
005|
006| def strSql(s):
007|
return replace("%s" % s, "'", "")
008|
009| def salahQuery( parent, query ):
010|
s = "%s\n%s" % ( query.lastError().databaseText(),
011|
query.lastQuery() )
012|
QMessageBox.warning(parent, "Perhatian", s )
013|
014|
015| class FormRelasi(QWidget):
016|
def __init__(self):
017|
QWidget.__init__(self)
018|
self.setCaption("Relasi")
019|
layout = QGridLayout( self, 3,2)
020|
layout.setAutoAdd(1)
021|
layout.setSpacing(5)
022|
layout.setMargin(5)
023|
024|
labelNama
= QLabel
(self)
025|
self.nama
= QComboBox (self)
026|
labelAlamat = QLabel
(self)
027|
self.alamat = QTextEdit (self)
028|
tombolSimpan = QPushButton(self)
029|
tombolHapus = QPushButton(self)
030|
labelNama.setText ("Nama")
031|
labelAlamat.setText("Alamat")
032|
self.nama.setEditable(1)
033|
self.nama.insertItem("<baru>")
272
034|
035|
036|
037|
038|
039|
040|
041|
042|
043|
044|
045|
046|
047|
048|
049|
050|
051|
052|
053|
054|
055|
056|
057|
058|
059|
060|
061|
062|
self.nama.clearEdit()
tombolSimpan.setText("&Simpan")
tombolHapus.setText ("&Hapus")
23.4. QUERY
063|
064|
065|
066|
067|
068|
069|
070|
071|
072|
073|
074|
075|
076|
077|
078|
079|
080|
081|
082|
083|
084|
085|
086|
087|
088|
089|
090|
091|
273
self.query.value(0).toString() )
def simpan(self):
index
= self.nama.currentItem()
insert
= index == 0
nama
= strSql( self.nama.currentText() )
alamat
= strSql( self.alamat.text() )
if insert:
sql = "INSERT INTO relasi ( nama, alamat ) " + \
"VALUES( '%s', '%s' )" % ( nama, alamat )
else:
_nama = strSql( self.nama.text(index) )
sql = "UPDATE relasi SET " + \
"nama='%s', alamat='%s' WHERE nama='%s'" % (
nama, alamat, _nama )
if self.query.execQuery( sql ):
if insert:
index = index + 1
self.nama.insertItem( self.nama.currentText(),
index )
self.nama.setCurrentItem( index )
else:
self.nama.changeItem( self.nama.currentText(),
index )
else:
salahQuery(self, self.query)
def hapus(self):
274
092|
if self.nama.currentItem() <= 0: return
093|
index = self.nama.currentItem()
094|
nama = strSql( self.nama.text(index) )
095|
sql = "DELETE FROM relasi WHERE nama='%s'" % nama
096|
if self.query.execQuery( sql ):
097|
self.nama.removeItem( index )
098|
if index + 1 > self.nama.count():
099|
index = index - 1
100|
self.nama.setCurrentItem( index )
101|
self.pilihNama( index )
102|
else:
103|
salahQuery(self, self.query)
104|
105| app = QApplication([])
106| if FormLogin(None).db.isOpen():
107|
fm = FormRelasi()
108|
app.setMainWidget(fm)
109|
app.exec_loop()
QSqlQuery
self.query = QSqlQuery()
self.query.execQuery( "SELECT nama FROM relasi" )
23.4. QUERY
275
Bi-
Pada contoh
WHERE
salahQuery().
ini merupakan
primary key
tabel
next().
record
current record di bawah. Sedangkan untuk mendanilai dari setiap eld pada record tersebut digunakan-
mengenai
patkan
lah fungsi
value().
value()
Lebih lanjut
Fungsi
ter kutip
kutip tunggal dua kali berarti memberitahu server database bahwa itu kutip tunggal.
QComboBox
insertItem()
9 Optional:
276
clearEdit()
setCurrentItem()
removeItem()
currentItem().
Sehingga untuk
next()
ke record berikutnya.
prev()
ke record sebelumnya.
first()
ke record pertama.
last()
ke record terakhir.
seek(n )
record ke
at()
n.
at()
= 0.
23.4. QUERY
next(), prev(), first(),
277
dan
last()
mengembalikan logika
QSqlQuery
query1.py
--------01| from qt import *
02| from qtsql import QSqlQuery
03| from login import FormLogin
04|
05| app = QApplication([])
06| if FormLogin(None).db.isOpen():
07|
q = QSqlQuery("SELECT nama, alamat FROM relasi")
08|
while q.next():
09|
print q.value(0).toString(), q.value(1).toString()
10|
print
11|
while q.prev():
12|
print q.value(0).toString(), q.value(1).toString()
23.4.2 Variant
QSqlQuery.value() mengemQVariant. Variant atau QVariant merupakan tipe data
apa saja. QVariant memiliki banyak fungsi konversi ke berba-
toString()QString
278
toDateTime()QDateTime
toDouble()oat
toInt()integer
Untuk mengetahui tipe data suatu variant dapat menggunakan
fungsi
QVariant.type()
Beberapa di-
antaranya adalah:
QVariant.String QString
QVariant.Double
QVariant.Int
oat
integer
QVariant.Date QDate
QVariant.Time QTime
QVariant.DateTime QDateTime
QSqlQuery
juga dan
10 Sebagaimana
279
cursor1.py
---------01| from qt import *
02| from qtsql import QSqlCursor
03| from login import FormLogin
04|
05| app = QApplication([])
06| if FormLogin(None).db.isOpen():
07|
c = QSqlCursor( "relasi" )
08|
if c.select():
09|
while c.next():
10|
print c.value("nama").toString(), \
11|
c.value("alamat").toString()
12|
else:
13|
print c.lastError().databaseText()
select() digunakan untuk menjalankan query SELECT. Ia mengembalikan logika true apabila query berhasil.
11 Baris
c.select()
sama artinya dengan query
select()
11 Contoh
relasi.
280
c.select("nama='Budi'")
Nilai masukan bagi
memprogram database dan - dengan alasan tersebut - diharapkan lebih memudahkan programmer
karena tidak perlu menuliskan query. Namun dalam
beberapa hal dengan
QSqlQuery
23.5.1 Browsing
QDataTable merupakan QTable yang dapat
record QSqlCursor secara otomatis. Cobalah
menampilkan isi
program berikut
ini:
datatable1.py
------------01| from qt import *
02| from qtsql import QSqlCursor, QDataTable
03| from login import FormLogin
04|
05| class FormRelasi(QWidget):
06|
def __init__(self):
07|
QWidget.__init__(self)
08|
self.setCaption("Tabel relasi")
281
09|
layout = QHBoxLayout(self)
10|
layout.setAutoAdd(1)
11|
self.cursor = QSqlCursor( "relasi" )
12|
self.table = QDataTable(self)
13|
self.table.setSqlCursor(self.cursor, 1)
14|
self.table.refresh()
15|
self.show()
16|
17| app = QApplication([])
18| if FormLogin(None).db.isOpen():
19|
fm = FormRelasi()
20|
app.setMainWidget(fm)
21|
app.exec_loop()
QSqlCursor dipakai oleh QDataTable sebagai sumber data melalui
setSqlCursor(). Angka 1 (true) pada masukan kedu-
fungsi
addColumn().
self.table.setSqlCursor(self.cursor)
self.table.addColumn("nama", "Nama Relasi")
QDataTable
memiliki menu
popup
12 pada
QDataTable.
12 Klik-kanan:
282
psql
atau
mysql:
283
'2003-01-17 13:09:34');
INSERT INTO pegawai
(id,nama,tgl_lahir,gaji,jadual_masuk,waktu_input)
VALUES
(3,'Budi Respati','1973-12-20',1750000,'07:30',
'2003-01-17 13:14:56');
kemudian ubahlah
dengan
pegawai.
QDataTable
1. Field
NULL
ini:
284
QDataTable unCursorTable.
cursortable.py
-------------01| from qt import *
02| from qtsql import QDataTable
03| import locale
04|
05| locale.setlocale(locale.LC_ALL, "")
06|
07| class CursorTable(QDataTable):
08|
Tanggal = "dd-MM-yyyy"
09|
Jam
= "hh:mm:ss"
10|
Waktu = "%s %s" % (Tanggal, Jam)
11|
12|
def __init__(self, parent):
13|
QDataTable.__init__(self, parent)
14|
15|
def paintField(self, painter, field, cr, selected):
16|
if field.type() in [QVariant.Int, QVariant.Double]:
17|
align = QPainter.LTR
18|
else:
19|
align = QPainter.RTL
20|
if field.isNull():
21|
teks = ""
22|
elif field.type() == QVariant.Double:
23|
teks = locale.format( "%.2f",
24|
field.value().toDouble(), 1 )
285
25|
elif field.type() == QVariant.Date:
26|
teks = field.value().toDate().toString(
27|
self.Tanggal)
28|
elif field.type() == QVariant.DateTime:
29|
teks = field.value().toDateTime().toString(
30|
self.Waktu)
31|
elif field.type() == QVariant.Time:
32|
teks = field.value().toTime().toString(self.Jam)
33|
else:
34|
teks = field.value().toString()
35|
painter.drawText(2,2, cr.width()-4, cr.height()-4,
36|
align, teks )
37|
38|
39| if __name__ == "__main__":
40|
from login import FormLogin
41|
from qtsql import QSqlCursor
42|
43|
app = QApplication([])
44|
if FormLogin(None).db.isOpen():
45|
cursor = QSqlCursor( "pegawai" )
46|
fm = CursorTable(None)
47|
fm.setSqlCursor( cursor, 1 )
48|
fm.refresh()
49|
fm.show()
50|
app.setMainWidget(fm)
51|
app.exec_loop()
286
cursor2.py
---------01| from qt import *
02| from qtsql import QSqlCursor
03| from login import FormLogin
04|
05| app = QApplication([])
06| if FormLogin(None).db.isOpen():
07|
c = QSqlCursor( "relasi" )
08|
c.select()
287
while c.next():
c.primeDelete()
c.delRecords()
c.select()
b = c.primeInsert()
b.setValue("nama", QVariant("Udin") )
b.setValue("alamat", QVariant("Jakarta") )
c.insert()
c.select()
while c.next():
print c.value("nama").toString(), \
c.value("alamat").toString()
b = c.primeUpdate()
b.setValue("alamat", QVariant("Bogor") )
c.update()
c.select()
while c.next():
print c.value("nama").toString(), \
c.value("alamat").toString()
13 Buer:
QSqlRecord.
penyimpanan sementara.
288
Jadi baris
b = c.primeUpdate()
b.setValue("alamat", QVariant("Bogor") )
c.update()
bisa ditulis
c.primeUpdate()
c.editBuffer().setValue("alamat", QVariant("Bogor") )
c.update()
Primary Key
Telah dibahas pada contoh sebelumnya bahwa
Tan-
23.5.4
NULL
QSqlCursor.
289
clear().
alamat pada nama
cursor3.py
---------01| from qt import *
02| from qtsql import QSqlCursor
03| from login import FormLogin
04|
05| app = QApplication([])
06| if FormLogin(None).db.isOpen():
07|
c = QSqlCursor( "relasi" )
08|
c.select("nama='Udin'")
09|
if c.next():
10|
b = c.primeUpdate()
11|
b.field("alamat").clear()
12|
c.update()
13|
c.select()
14|
while c.next():
15|
print c.value("nama").toString(), \
16|
c.value("alamat").toString()
17|
else:
18|
print "Udin belum terdaftar"
Objek eld ini sebenarnya milik leluhur
290
QDataTable
- sedikit banyak - menambah waktu proses input karena melibatkan dua alat yaitu keyboard dan mouse.
Untuk memperbaikinya, kita akan membuat class baru keturunan
Grid
1. Sama seperti
QDataTable,
sumberdatanya
QSqlCursor.
angka() 15
now
6. Masukan tanggal yang tidak lengkap akan dilengkapi dengan waktu saat ini. Misalkan sekarang tanggal 17-2-2003,
291
10
31-1
DATETIME
DBGrid,
produk tersebut.
Modul
QDate, QTime,
serta
QDateTime.
fungsi.py
--------001| from qt import *
002| import string
003| import locale
292
004|
005|
006|
007|
008|
009|
010|
011|
012|
013|
014|
015|
016|
017|
018|
019|
020|
021|
022|
023|
024|
025|
026|
027|
028|
029|
030|
031|
032|
locale.setlocale(locale.LC_ALL, "")
293
033|
try:
034|
exec("a"+a)
035|
return a
036|
except:
037|
return
038|
039|
040| """ Mengubah string tanggal format dd-MM-yyyy menjadi
041|
QDate. Bila hanya dd maka MM dan yyyy diisi bulan
042|
dan tahun sekarang. Bila hanya dd-MM maka yyyy diisi
043|
tahun ini. Bila 'NOW' berarti tanggal sekarang.
044| """
045| def tanggal(s):
046|
w = string.strip("%s" % s)
047|
if string.upper(w) == "NOW":
048|
return QDate.currentDate()
049|
050|
if string.find(w, "-") > -1: p = "-"
051|
else: p = "/"
052|
t = string.splitfields(w,p)
053|
054|
try: d = int(t[0])
055|
except ValueError: return
056|
057|
# Untuk bulan dan tahun default
058|
now = QDate.currentDate()
059|
060|
if t[1:]:
061|
try: m = int(t[1])
294
295
091|
if t[2:]:
092|
x = t[2]
093|
x = string.replace(x,",",".")
094|
x = string.splitfields(x,".")
095|
try: s = int(x[0])
096|
except ValueError: return
097|
if x[1:]:
098|
y = "0." + x[1]
099|
try: ms = float(y) * 1000
100|
except ValueError: return
101|
else:
102|
ms = 0
103|
else:
104|
s, ms = 0, 0
105|
else:
106|
m, s, ms = 0, 0, 0
107|
j = QTime(h,m,s,ms)
108|
if j.isValid() and not j.isNull(): return j
109|
110|
111| """ Mengubah string waktu bentuk dd-MM-yyyy hh:mm:ss.zzz
112|
menjadi QDateTime
113| """
114| def waktu(s):
115|
w = string.strip("%s" % s)
116|
if string.upper(w) == "NOW":
117|
return QDateTime.currentDateTime()
118|
119|
w = string.splitfields("%s" % w)
296
120|
121|
122|
123|
124|
125|
126|
fungsi.py
if w: d = tanggal(w[0])
else: return
if w[1:]: t = jam(w[1])
else: t = QTime(0,0,0,0)
return QDateTime( d, t )
di atas akan digunakan dalam
dbgrid.py
ini.
dbgrid.py
--------001| from qt import *
002| from qttable import QTable
003| from qtsql import QSqlIndex
004| import string
005| from grid import Grid
006| from fungsi import *
007| from linecase import LineCase
008|
009| class DBGrid(Grid):
010|
Tgl = "dd-MM-yyyy"
011|
Jam = "hh:mm:ss"
012|
Wkt = "%s %s" % (Tgl, Jam)
013|
014|
# status current record
015|
Browse = 0
016|
Insert = 1
berikut
297
Update = 2
def __init__(self, parent):
Grid.__init__(self, parent)
self.penBox = QPen()
self.penBox.setColor( QColor("lightGray") )
self.penText = QPen()
self.penText.setColor( QColor("black") )
self.brushBrowse = QBrush()
self.brushBrowse.setColor( QColor("yellow") )
self.brushBrowse.setStyle( QBrush.SolidPattern )
self.brushInsert = QBrush()
self.brushInsert.setColor( QColor("cyan") )
self.brushInsert.setStyle( QBrush.SolidPattern )
self.brushUpdate = QBrush()
self.brushUpdate.setColor( QColor("green") )
self.brushUpdate.setStyle( QBrush.SolidPattern )
self._cursor = None
self.status = self.Browse
self._row = -1 # sebelum currentRow()
self._col = -1 # sebelum currentColumn()
self.editRow = -1 # baris yang sedang diedit
self._maxLength = {} # fieldname:length
self._case = {} # fieldname:Normal|Upper|Lower
self.intValidator = QIntValidator(self)
self.doubleValidator = QDoubleValidator(self)
self.afterInsert = None # event setelah tambah()
self.beforePost = None # event sebelum UPDATE/INSERT
self.afterPost = None # event sesudah UPDATE/INSERT
298
046|
047|
048|
049|
050|
051|
052|
053|
054|
055|
056|
057|
058|
059|
060|
061|
062|
063|
064|
065|
066|
067|
068|
069|
070|
071|
072|
073|
074|
self.connect(self,
SIGNAL("currentChanged(int,int)"),
self.saatPindah)
def resizeData(self, i):
pass # hemat memory
def beginEdit(self, row, col, replace):
if self.ubah():
return QTable.beginEdit(self, row, col, replace)
def createEditor(self, row, col, initFromCell):
field = self._cursor.editBuffer().field(col)
fieldname = str(field.name())
if self._case.has_key(fieldname):
case = self._case[fieldname]
else: case = LineCase.Normal
e = LineCase(self, case)
if field.type() == QVariant.String:
if self._maxLength.has_key(fieldname):
e.setMaxLength(self._maxLength[fieldname])
elif field.type() == QVariant.Int:
e.setValidator( self.intValidator )
elif field.type() == QVariant.Double:
e.setValidator( self.doubleValidator )
if initFromCell:
if field.isNull(): s = ""
elif field.type() == QVariant.Date:
299
s = field.value().toDate().toString(self.Tgl)
elif field.type() == QVariant.DateTime:
s = field.value().toDateTime().toString(self.Wkt)
elif field.type() == QVariant.Time:
s = field.value().toTime().toString(self.Jam)
elif field.type() == QVariant.Double:
s = str(field.value().toDouble())
elif field.type() == QVariant.Int:
s = str(field.value().toInt())
else:
s = field.value().toString()
e.setText( s )
return e
def setCellContentFromEditor(self, row, col):
self.isiDariEditor()
def clearCell(self, row, col):
if self._cursor.seek(row):
self.ubah().field(col).clear()
self.updateCell(row, col)
def insertRows(self, row, count=1):
if not self.simpan() or self._cursor.size() < 1:
return
Grid.insertRows(self, row)
self.tambah()
r = self.cellGeometry(row-1,0)
r.setRight( self.width() )
300
104|
105|
106|
107|
108|
109|
110|
111|
112|
113|
114|
115|
116|
117|
118|
119|
120|
121|
122|
123|
124|
125|
126|
127|
128|
129|
130|
131|
132|
r.setBottom( self.height() )
self.repaintContents(r)
def removeRow(self, row):
if not self.adaPrimaryKey(): return
if self._cursor.seek( row ):
self._cursor.primeDelete()
if self._cursor.delRecords():
self._refresh()
self.setStatus( self.Browse )
Grid.removeRow( self, row )
r = self.cellGeometry( self.currentRow(), 0 )
r.setRight( self.width() )
self.repaintContents(r)
else: self.salah()
else: Grid.removeRow( self, row )
def keyPressEvent(self, e):
if e.key() == Qt.Key_Up: self.naik()
elif e.key() == Qt.Key_Escape: self.batal()
elif e.key() == Qt.Key_F4: self.simpan()
elif e.key() == Qt.Key_F5: self.perbaharui()
else: Grid.keyPressEvent(self, e)
301
302
162|
163|
164|
165|
166|
167|
168|
169|
170|
171|
172|
173|
174|
175|
176|
177|
178|
179|
180|
181|
182|
183|
184|
185|
186|
187|
188|
189|
190|
303
191|
not cursor.primaryIndex().isEmpty():
192|
index = QSqlIndex()
193|
for i in range( cursor.primaryIndex().count() ):
194|
index.append( cursor.field(i) )
195|
cursor.setSort( index )
196|
cursor.select()
197|
self.setNumCols( cursor.count() )
198|
self.setNumRows( cursor.size() )
199|
self._row = self.currentRow()
200|
self._col = self.currentColumn()
201|
for col in range( cursor.count() ):
202|
self.horizontalHeader().setLabel(col,
203|
cursor.field(col).name() )
204|
else:
205|
self.setNumCols(0)
206|
self.setNumRows(0)
207|
self._cursor = cursor
208|
209|
def adaPrimaryKey(self):
210|
if self._cursor.primaryIndex().isEmpty():
211|
self.pesan("Tabel tanpa Primary Key tidak dapat \
212| diubah atau dihapus.")
213|
else: return 1
214|
215|
def setStatus(self, status):
216|
if self.status == status: return
217|
self.status = status
218|
if status == self.Browse: self.editRow = -1
219|
else: self.editRow = self.currentRow()
304
220|
221|
222|
223|
224|
225|
226|
227|
228|
229|
230|
231|
232|
233|
234|
235|
236|
237|
238|
239|
240|
241|
242|
243|
244|
245|
246|
247|
248|
r = self.cellGeometry(self.currentRow(),0)
r.setRight( self.width() )
self.repaintContents(r)
def tambah(self):
b = self._cursor.primeInsert()
for col in range(b.count()): b.field(col).clear()
self.setStatus( self.Insert )
if self.afterInsert: self.afterInsert(self._cursor)
return b
def ubah(self):
if self.status != self.Browse:
return self._cursor.editBuffer()
if self._cursor.size() == 0: return self.tambah()
if not self.adaPrimaryKey(): return
if self._cursor.seek( self.currentRow() ):
b = self._cursor.primeUpdate()
self.setStatus( self.Update )
return b
def simpan(self):
if self.status == self.Browse: return 1
if self.editorAktif():
self.isiDariEditor()
self.clearCellWidget( self.currentRow(),
self.currentColumn() )
if self.beforePost: self.beforePost(self._cursor)
if self.status == self.Insert:
305
if self._cursor.insert(): self._refresh()
else:
self.salah()
return 0
elif self.status == self.Update:
if self._cursor.update(): self._refresh()
else:
self.salah()
return 0
self.setStatus( self.Browse )
if self.afterPost: self.afterPost(self._cursor)
return 1
def saatPindah(self, row, col):
if row != self._row:
if not self.simpan(): return
r = self.cellGeometry( self._row, 0 )
r.setRight( self.width() )
self.repaintContents(r)
r = self.cellGeometry( row, 0 )
r.setRight( self.width() )
self.repaintContents(r)
self._row, self._col = row, col
def naik(self):
if self.simpan() and self.currentRow() > 0:
self.setCurrentCell( self.currentRow()-1,
self.currentColumn() )
306
278|
279|
280|
281|
282|
283|
284|
285|
286|
287|
288|
289|
290|
291|
292|
293|
294|
295|
296|
297|
298|
299|
300|
301|
302|
303|
304|
305|
306|
def batal(self):
if self.status != self.Browse:
status = self.status
self.setStatus( self.Browse )
if status == self.Insert:
Grid.removeRow( self, self.currentRow() )
r = self.cellGeometry(self.currentRow(),0)
r.setRight( self.width() )
r.setBottom( self.height() )
self.repaintContents(r)
def salah(self):
pesan = "%s\nTekan Escape untuk membatalkan." % \
self._cursor.lastError().databaseText()
self._cursor.select()
if self._row != self.currentRow():
r = self.cellGeometry( self.currentRow(), 0 )
r.setRight( self.width() )
self.setCurrentCell( self._row, self._col )
self.repaintContents(r)
self.pesan( pesan )
def _refresh(self):
self._cursor.select()
self.repaintContents()
# Berguna pada cursor berkondisi pada select()-nya
def perbaharui(self):
if self.cellWidget( self.currentRow(),
307
self.currentColumn() ): return
if self.simpan():
self._cursor.select()
self.setNumRows( self._cursor.size() )
def pesan(self, s):
QMessageBox.warning(self, "Perhatian", s)
# Tentukan jumlah karakter maksimum untuk field string
def setMaxLength(self, fieldname, length):
self._maxLength.update( {fieldname:length} )
# Tentukan uppercase atau tidak untuk field string
def setCase(self, fieldname, case):
self._case.update( {fieldname:case} )
def editorAktif(self):
return self.cellWidget( self.currentRow(),
self.currentColumn() )
def isiDariEditor(self):
s = str(self.editorAktif().text())
field = self._cursor.editBuffer().field(
self.currentColumn() )
if field.type()==QVariant.Date: s = tanggal(s)
elif field.type()==QVariant.Time: s = jam(s)
elif field.type()==QVariant.DateTime: s=waktu(s)
elif field.type() in [QVariant.Int,
QVariant.Double]:
308
336|
s = angka(s)
337|
if s: s = str(s)
338|
if s: field.setValue( QVariant(s) )
339|
elif s == "": field.clear()
340|
341| if __name__ == "__main__":
342|
from login import FormLogin
343|
from qtsql import QSqlCursor
344|
import sys
345|
346|
tablename = sys.argv[1]
347|
app = QApplication([])
348|
if FormLogin(None).db.isOpen():
349|
cursor = QSqlCursor( tablename )
350|
cursor.select()
351|
fm = DBGrid(None)
352|
fm.setSqlCursor( cursor )
353|
fm.show()
354|
app.setMainWidget(fm)
355|
app.exec_loop()
Untuk mencobanya jalankan:
createEditor().
309
query ulang
refresh, yaitu
id
sebagai kode
barang.
pada eld
nama
Makna
Catatan
para pemakai.
Source
rutkan data berdasarkan eld tertentu. Kini hal yang sama akan
dibuat untuk eld
nama.
310
sqlindex.py
----------01| from qt import *
02| from qtsql import QSqlCursor, QSqlIndex
03| from login import FormLogin
04| from dbgrid import DBGrid
05|
06| app = QApplication([])
07| if FormLogin(None).db.isOpen():
08|
c = QSqlCursor( "barang" )
09|
index = QSqlIndex()
10|
index.append( c.field("nama") )
11|
c.setSort( index )
12|
fm = DBGrid(None)
13|
fm.setSqlCursor(c)
14|
fm.show()
15|
app.setMainWidget(fm)
16|
app.exec_loop()
Meski DBGrid secara default mengurutkan data berdasarkan
primary key, namun ia - melalui
sa terlebih dahulu apakah
Bi-
311
caritabel.py
-----------01| from qt import *
02| from dbgrid import DBGrid
03| from qtsql import QSqlCursor, QSqlIndex
04| from linecase import LineCase
05|
06| class FormCari(QDialog):
07|
def __init__(self, parent, cursor, searchfieldname):
08|
QDialog.__init__(self, parent)
09|
self.setCaption( cursor.name() )
10|
layout = QVBoxLayout(self)
11|
self.teks = LineCase(self, LineCase.Upper)
12|
self.tabel = DBGrid(self)
13|
layout.addWidget(self.teks)
14|
layout.addWidget(self.tabel)
15|
self._field = cursor.field(searchfieldname)
16|
index = QSqlIndex()
17|
index.append( self._field )
18|
cursor.setSort(index)
19|
self._cursor = cursor
20|
self.tabel.setSqlCursor( cursor )
21|
self.kolomCari = cursor.position(searchfieldname)
22|
self.teks.teksBerubah = self.teksBerubah
23|
24|
def keyPressEvent(self, e):
25|
if e.key() == Qt.Key_Escape: self.escape()
26|
elif e.state() == Qt.ControlButton and \
27|
e.key() == Qt.Key_PageDown: self.lanjut()
312
28|
29|
30|
31|
32|
33|
34|
35|
36|
37|
38|
39|
40|
41|
42|
43|
44|
45|
46|
47|
48|
49|
50|
51|
52|
53|
54|
55|
56|
313
57|
else: ketemu = t.find(s) > -1
58|
if ketemu:
59|
if self.tabel.currentRow() != brs:
60|
self.tabel.setCurrentCell(brs, self.kolomCari)
61|
return brs
62|
return -1
63|
64|
def lanjut(self):
65|
if self.teks.text().isEmpty(): return
66|
if self.cari(0, self.tabel.currentRow() ) < 0:
67|
self.cari(0)
68|
69|
70| if __name__ == "__main__":
71|
from login import FormLogin
72|
73|
app = QApplication([])
74|
if FormLogin(None).db.isOpen():
75|
c = QSqlCursor( "barang" )
76|
fm = FormCari(None, c, "nama" )
77|
fm.tabel.setColumnWidth(1,200)
78|
fm.tabel.setCase("nama", LineCase.Upper)
79|
fm.tabel.setMaxLength("nama",20)
80|
fm.showMaximized()
81|
fm.exec_loop()
82|
if fm.result() == QDialog.Accepted:
83|
print fm._cursor.field("id").value().toInt()
314
MAX()
pada SQL.
MAX().
sesaat
sebelum disimpan.
beforePost()
han.
315
barang.py
--------01| from qt import *
02| from qtsql import QSqlCursor, QSqlIndex
03| from caritabel import FormCari
04| from linecase import LineCase
05|
06| class FormBarang(FormCari):
07|
def __init__(self, parent):
08|
self.barang = QSqlCursor("barang")
09|
FormCari.__init__(self, parent, self.barang, "nama")
10|
self.tabel.setColumnWidth(1,200)
11|
self.tabel.setCase("nama", LineCase.Upper)
12|
self.tabel.setMaxLength("nama",20)
13|
self.urutan = QSqlCursor("urutan")
14|
self.urutan.select("tabel='barang'")
15|
self.urutan.next()
16|
self.tabel.afterInsert = self.afterInsert
17|
self.tabel.beforePost = self.beforePost
18|
self.tabel.afterPost = self.afterPost
19|
self.nama = ""
20|
21|
def afterInsert(self, cursor):
22|
self.tabel.setFocus()
23|
self.tabel.setCurrentCell(self.tabel.currentRow(),1)
24|
25|
def beforePost(self, cursor):
26|
if self.tabel.status == self.tabel.Insert:
27|
n = self.urutan.value("nomor").toInt() + 1
316
Bab 24
Kasir III
Karena sudah masuk tema database, Kasir III akan dilengkapi
tur untuk menyimpan transaksi penjualan.
header
transaksi:
318
tabel
urutan:
INSERT INTO urutan (tabel, nomor) VALUES ('penjualan', 0);
dan
si.
Sedangkan tabel kedua berisi rinciannya, yaitu daftar barang
yang dijual:
Nilai
gorikan sebagai
foreign key.
Namun struktur
1 Field
referensi.
319
buah semangka dengan berat masing-masing 3 dan 4 kg. Tentu saja kita tidak ingin mencatatnya sebagai sebuah semangka
dengan berat 7 kg karena ini bisa membuat kekeliruan dalam
menghitung banyaknya barang.
Membuang primary key juga tidak dianjurkan karena hanya
membuat tabel tersebut hanya bisa di-INSERT. Jadi kita tambahkan saja sebuah eld bertipe integer namun dengan ukuran
yang lebih kecil, yaitu
SMALLINT.2
2 Jangkauan SMALLINT
320
harga.
24.4 Pencetakan
Struk disimpan ke sebuah le yang telah ditentukan lokasinya,
untuk kemudian dicetak ke printer. Pada saat printer mencetak,
pemakai sudah dapat memasukkan data kembali. Untuk struk
yang cukup panjang dengan antrian pembeli yang juga panjang
hal ini tentu sangat menghemat waktu.
Meski program ini mewajibkan penggunaan printer, namun
ketiadaannya tidak menghalangi proses pemasukan data, karena
pencetakan diserahkan sepenuhnya pada sistem operasi, tidak
peduli pencetakan berhasil atau tidak.
24.5. PROGRAM
321
24.5 Program
Agar form lebih informatif, program ini juga menyertakan
WaktuDigital.3
kasir3.py
--------001| from qt import *
002| from qtsql import QSqlCursor, QSqlQuery
003| from waktudigital import WaktuDigital
004| from valuegrid import ValueGrid
005| from barang import FormBarang
006| from fungsi import ribu
007| from string import rjust, ljust
008| import os
009|
010| class LineControl(QLineEdit):
011|
def __init__(self, parent):
012|
QLineEdit.__init__(self, parent)
013|
self.setValidator( QDoubleValidator(self) )
014|
self.tombolDitekan = None
015|
016|
def keyPressEvent(self, e):
017|
if self.tombolDitekan: self.tombolDitekan( e )
018|
019|
# Kursor / Focus control tetap di sini
020|
def focusOutEvent(self, e):
021|
self.setFocus()
3 Lihat
322
"Nama")
"Jumlah")
"Harga")
24.5. PROGRAM
051|
052|
053|
054|
055|
056|
057|
058|
059|
060|
061|
062|
063|
064|
065|
066|
067|
068|
069|
070|
071|
072|
073|
074|
075|
076|
077|
078|
079|
323
self.urutan.select( "tabel='penjualan'" )
self.query = QSqlQuery()
self.output = "/tmp/kasir.txt"
self.reset()
self.teks.tombolDitekan = self.tombolDitekan
self.tabel.beforeDelete = self.beforeDelete
def tombolDitekan(self, e):
if e.key() in [Qt.Key_Return, Qt.Key_Enter]:
self.cariKode()
elif e.key() == Qt.Key_Asterisk: self.ubahJml()
elif e.key() == Qt.Key_Plus: self.bayar()
elif e.ascii() in self.Huruf:
self.formBarang( e.text() )
elif e.key() == Qt.Key_Escape: self.teks.clear()
elif e.key() in self.GridKeys:
if e.key() == Qt.Key_Down and \
self.tabel.currentRow() == \
self.tabel.numRows()-1:
return
self.tabel.keyPressEvent( e )
else: QLineEdit.keyPressEvent( self.teks, e )
def resizeEvent(self, e):
self.tabel.setColumnWidth( 1, self.tabel.width() self.tabel.columnWidth(2) self.tabel.columnWidth(3) - 100)
def reset(self):
324
080|
081|
082|
083|
084|
085|
086|
087|
088|
089|
090|
091|
092|
093|
094|
095|
096|
097|
098|
099|
100|
101|
102|
103|
104|
105|
106|
107|
108|
self.total = 0
self.jml = 1.0
self.tabel.setData([])
self.lcd.display(0)
self.teks.clear()
self.perluReset = 0
def ubahJml(self):
try: self.jml = float(str(self.teks.text()))
except: return
# dua desimal saja
self.jml = round(self.jml*100)/100
self.lcd.display(self.jml)
self.teks.clear()
def beforeDelete(self, row):
self.total = self.total - self.tabel.data[row][3]
self.lcd.display(ribu(self.total))
def cariKode(self):
where = "id='%s'" % self.teks.text()
self.brg.select(where)
if self.brg.next(): self.tambah( self.brg )
else:
self.pesan( "Kode barang %s tidak ada" % \
self.teks.text() )
self.teks.selectAll()
def tambah(self, cursor):
24.5. PROGRAM
109|
110|
111|
112|
113|
114|
115|
116|
117|
118|
119|
120|
121|
122|
123|
124|
125|
126|
127|
128|
129|
130|
131|
132|
133|
134|
135|
136|
137|
325
if self.perluReset: self.reset()
harga = int( self.jml *
cursor.value("harga").toDouble() )
self.total = self.total + harga
self.lcd.display(ribu(self.total))
rec = []
rec.append( cursor.value("id").toInt() )
rec.append( str(cursor.value("nama").toString()) )
rec.append( self.jml )
rec.append( harga )
if self.tabel.data:
self.tabel.turun()
row = self.tabel.currentRow()
self.tabel.data[row] = list(rec)
else: self.tabel.data.append( list(rec) )
self.tabel.repaintContents()
self.teks.clear()
self.jml = 1.0
def timerEvent(self, e):
self.killTimers()
self.fmBrg.teks.setText( self._teks )
def formBarang(self, teks):
self._teks = teks # untuk timer
self.fmBrg.showMaximized()
# Bila data yang dicari terlalu ke bawah, current
# record tidak tampak. Timer digunakan agar pada
# saat form barang tampil, huruf dimasukkan untuk
326
138|
139|
140|
141|
142|
143|
144|
145|
146|
147|
148|
149|
150|
151|
152|
153|
154|
155|
156|
157|
158|
159|
160|
161|
162|
163|
164|
165|
166|
# dicari.
self.startTimer( 500 )
self.fmBrg.exec_loop()
if self.fmBrg.result() == QDialog.Accepted:
self.tambah( self.fmBrg._cursor )
def bayar(self):
try: b = int(float(str(self.teks.text())))
except ValueError:
self.pesan("%s bukan angka" % self.teks.text())
return
k = int(b - self.total)
self.lcd.display(ribu(k))
self.teks.clear()
# Header
self.urutan.select()
self.urutan.next()
id_penjualan = \
self.urutan.value("nomor").toInt()+1
sql = """UPDATE urutan SET nomor=%s
WHERE tabel='penjualan'""" % id_penjualan
if not self.execQuery( sql ): return
# Antisipasi multiuser, tanggal mengambil
# dari database, menghindari perbedaan setting
# tanggal antar komputer client
if not self.execQuery( "SELECT NOW()" ): return
self.query.next()
24.5. PROGRAM
167|
168|
169|
170|
171|
172|
173|
174|
175|
176|
177|
178|
179|
180|
181|
182|
183|
184|
185|
186|
187|
188|
189|
190|
191|
192|
193|
194|
195|
327
tgl = self.query.value(0).toDateTime()
self.struk = "%s\n%s\n" % (
tgl.toString("dd-MM-yyyy hh:mm"), "-" * 35 )
# Cetak
nomor = 0
daftarSql = []
for rec in self.tabel.data:
nomor = nomor + 1
kode, nama, jml, harga = rec
daftarSql.append( """INSERT INTO penjualan_barang
(id_penjualan, nomor, id_barang, jumlah, harga)
VALUES (%s, %s, %s, %s, %s)""" % \
( id_penjualan, nomor, kode, jml, harga ) )
self.cetakBarang( nama, jml, harga )
self.struk = "%s%s\n" % (self.struk, "-" * 35)
self.cetakAkhir( "TOTAL", self.total )
self.cetakAkhir( "BAYAR", b )
self.cetakAkhir( "KEMBALI", k )
self.cetakFile()
self.perluReset = 1
# Simpan ke database
sql = """INSERT INTO penjualan (id, tgl)
VALUES (%s,'%s')""" % ( id_penjualan,
tgl.toString(Qt.ISODate) )
if not self.execQuery( sql ): return
for sql in daftarSql:
if not self.execQuery( sql ): return
328
196|
197|
198|
199|
200|
201|
202|
203|
204|
205|
206|
207|
208|
209|
210|
211|
212|
213|
214|
215|
216|
217|
218|
219|
220|
221|
222|
223|
224|
24.5. PROGRAM
329
225|
226|
227| if __name__ == "__main__":
228|
from login import FormLogin
229|
app = QApplication([])
230|
if FormLogin(None).db.isOpen():
231|
fm = FormKasir(None)
232|
fm.showMaximized()
233|
fm.exec_loop()
LineControl
focusOutEvent() membuat-
sor berada di
killTimers().
QDateTime.toString() menampil-
Qt.ISODate
membuat
Latihan
Nama
330
24.6 Laporan
Ada beberapa laporan yang dapat dibuat berdasarkan struktur
tabel yang ada.
24.6. LAPORAN
331
DESC (descending )
332
Bibliogra
[1] Sugiana, Owo,
ta, 2001
[2] Lutz, Mark,
[3] http://groups.yahoo.com/group/id_python/les/pytut.id.html
334
BIBLIOGRAFI
Indeks
addDatabase(), QSqlDatabase,
* perkalian, 39
184
** pangkat, 39
+ penjumlahan, 39
- pengurangan, 39
/ pembagian, 38, 39
% - string formatting, 91
__doc__, 61
__init__(), 84
addStretch(), QBoxLayout,
134
addWidget(), QGridLayout,
137
__name__, 95
akar, 74
activateNextCell(), QTable,
160
and, 55
addColumn(), QDataTable,
193
INDEKS
336
bug, 24
ka C, 93
append(), list, 44
C, 18, 22
argv, 71
C++, 18, 22
Arial, font, 96
capslock, 55
caption, 85
cast, 43
ASCII, 71
autocompletion, QComboBox,
105
autowarp, QTextEdit, 89
chdir(), 72
checkbox, QCheckBox, 99
checked, QCheckBox, 99
background, 167
child, 89
backslash, 41
chmod, 70
bahasa pemrograman, 18
chr(), 71
clear(), 93
Belanda, 21
black, 98
blok program, 51
blue, 98
BMP, 24
bold, font, 96
102
clicked(), sinyal QPushButton, 93
boolean, 98
break, 62
INDEKS
337
command line, 28
connect(), QObject, 93
connection ID, 179
currentItem(), QComboBox,
106, 189
console, 72
console environment, text editor, 29
constructor, 84
container, 123
Control, keyboard, 117
count(), QButtonGroup, 102
COUNT(), SQL, 225
Courier, 149
Courier, font, 96
CREATE DATABASE, SQL,
180, 181
CREATE TABLE, SQL, 185
createEditor(), QTable, 166,
210
cross, karakter, 35
CSV, 76
databaseText(), QSqlError,
184
currentChanged(), QTable,
157
226
day(), QDate, 140
INDEKS
338
double-click, 107
driver, 179
debugging, 42
debugging, arti, 24
debugging, proses, 24
def, 63
deklarasi variabel, 35
del, dictionary, 49
esien, 23
del, list, 44
elif, 53
else, 53
embeddable, 22
enable, 110
enter, karakter, 69
desimal, 40
development cycle, 18
device, 70
error, 73
61
dir(), info properti objek, 50
direktori aktif, 72
except, 74
disable, 110
exception, 73
dokumentasi modul, 61
exec__loop(), 84
dokumentasi, manfaat, 24
DOS Prompt, 28
dotmatrix, 76
extensible, 22
INDEKS
339
for, in range(), 60
for, perbandingan, 61
faktorial, bilangan, 60
for, perulangan, 59
faktorial, fungsi, 65
form, 84
false, 52
84
format(), locale, 40
formatting, string, 91
le, 69, 76
frame, 123
fungsi, penyisipan, 93
fungsi, rekursif, 65
gedit, 29
getcwd(), 72
getDouble(), QInputDialog,
154
getInteger(), QInputDialog,
154
getOpenFileName(), QFileDialog, 148
getSaveFileName(), QFileDialog, 148
Gnome, 29
97
for di dalam for, 60
INDEKS
340
gray, 98
green, 98
166
insertStrList(), QComboBox,
106
insertTab(), QTabWidget, 129
install, 29
int(), pembulatan, 40
has_key(), dictionary, 78
55
Helvetica, font, 96
highlight, 167
interactive interpreter, 51
interactive mode, 35
horizontalHeader(), QTable,
156
face, 93
internet, 21, 22
huruf, ukuran, 70
interpreter, exec(), 66
interpreter, lingkup sys, 72
icon, 149
if, 51
in, for, 59
in, operator, 54
italic, font, 96
Indonesia, 21, 41
input, QLineEdit, 88
insert(), list, 44
Java, 18, 22
INDEKS
341
JPEG, 24
kalkulator, 114
kalkulator, contoh, 66
library, 81
38
lightGray, 98
karakter ASCII, 71
karakter, font, 96
kate, 29
96
linecase, modul, 94
LineCase, teksBerubah, 95
keypad, 115
LineControl, 224
keyPressEvent(), QWidget,
117
keys(), dictionary, 49
173
ljust(), string, 78
konversi, kesalahan, 55
locale, modul, 40
41
loop, 59
looping, 84
lp0, 152
lp0, printer, 70
97
magenta, 98
larik, nama lain list, 43
maintenance, 22
INDEKS
342
math, modul, 38
memori, rekursif, 65
objek-tampak, QWidget, 87
ODBC, 179
open(), le, 69
mouse, 113
OpenGL, 18
MS-SQL, 179
operator bilangan, 39
option, 25
multiline, 88
or, 56
multiuser, 181
Oracle, 179
MySQL, 179181
ord(), 71
193
next(), QSqlQuery, 189, 190
non-visual class, 90
out of paper, 71
override, 94
owner, 89
parent, 89
not, 55
Pascal, perbandingan, 34
object oriented, 21
pass, 166
84
37
INDEKS
343
PyQt, 81
Python, 81
Python - C++, perbandin-
PHP, 34
gan, 191
pico, 29
Python - Java, 22
plaintext, 91
Python - Perl, 22
pointer, 76
Python - Tcl, 22
105
postgres, superuser PostgreSQL,
180
PostgreSQL, 179, 180
210
primeDelete(), QSqlCursor,
197
primeInsert(), QSqlCursor,
197
primeUpdate(), QSqlCursor,
36
Python, perbandingan bahasa,
22
Python, sejarah nama, 23
Python, text editor, 30
PytQt, 93
197
print, 33, 36
QApplication, 83, 84
QApplication, setMainWid-
print,menampilkan QString,
91
printer, 70
programmer, dokumentasi, 24
psql, PostgreSQL client, 180,
193
get(), 83
QBoxLayout, 134, 136, 137
QBoxLayout, addStretch(),
134
QBoxLayout, setDirection(),
136
INDEKS
344
QComboBox, setEditable(),
106
QDataTable, 192194
QDataTable, addColumn(),
193
QDataTable, setSqlCursor(),
193
QDate, 140
QCheckBox, 99
QColor, warna, 98
QComboBox, 105
QComboBox, currentItem(),
106, 189
QComboBox, currentText(),
106
QComboBox, insertStrList(),
QDateTime, 142
106
QComboBox, removeItem(),
189
QComboBox, setAutoCompletion(), 106
INDEKS
345
QInputDialog, 146
QInputDialog, getDouble(),
154
QInputDialog, getInteger(),
154
QDial, 126
QKeyEvent, 117
QDialog, 145
QLabel, 88, 89
QLabel, setAutoResize(), 98
QFileDialog, 146
QFileDialog, getOpenFileName(),
148
QFileDialog, getSaveFileName(),
148
QFont, 96
QFont, setBold(), 98
QLCDNumber, 111
QFont, setFamily(), 97
QFont, setItalic(), 98
QFont, setPointSize(), 97
QFont, setUnderline(), 98
QFrame, 123
105
QLineEdit, pada QTable, 160
QLineEdit, textChanged(),
98, 111
INDEKS
346
QListBox, setSelectionMode(),
109
QRegExp, 173
QScrollView, 167
QScrollView, repaintContents(),
167
QSpinBox, 124
QSpinBox, setValue(), 126
QSpinBox, valueChanged(),
126
QSqlCursor, 191
QSqlCursor, delRecords(), 197
QSqlCursor, editBuer(), 197
QSqlCursor, primeDelete(),
197
QSqlCursor, primeInsert(),
197
QSqlCursor, primeUpdate(),
197
QSqlDatabase, 184
INDEKS
347
QSqlDatabase, addDatabase(),
184
Qt, 81
QSqlDatabase, setDatabase-
Name(), 184
QSqlDatabase, setHostName(),
184
QSqlDatabase, setPassword(),
184
QSqlDatabase, setUsername(),
184
QSqlError, 184
QSqlError, databaseText(),
184
QSqlField, clear(), 197
QSqlQuery, 188, 191
QSqlQuery, at(), 190
QTable, horizontalHeader(),
156
QTable, insertRows(), 160,
166
QSqlRecord, 191
166
QTable, resizeData(), 165
QTable, setCellContentFromEditor(), 166
INDEKS
348
QTable, setColumnWidth(),
173
123
QWidget, closeEvent(), 152
QWidget, focusOutEvent(),
224
QWidget, font(), 97
QWidget, keyPressEvent(),
117
QWidget, setFocus(), 93
QWidget, setMinimumHeight(),
QTime, 139
132, 134
QWidget, show(), 84
QWidget, showMaximized(),
134
QWidget, warna, 99
radiobutton, QRadioButton,
101
random(), random, 61
random, modul, 61
range(), 60
raw_input(), 51
read, le, 69
read-only, QLabel, 88
INDEKS
349
ribuan, 40
rjust(), string, 78
root, 70
red, 98
round(), 40
script, arti, 24
scrolling, 106
second(), QTime, 139
secsTo(), QDateTime, 143
secsTo(), QTime, 139
seek(), le, 76
seek(), QSqlQuery, 190
segmentation fault, 90
select(), QSqlCursor, 191
resize(), QWidget, 88
self, 85
setAutoCompletion(), QCom-
return, 64
boBox, 106
setAutoResize(), QLabel, 98
reverse(), list, 47
setBold(), QFont, 98
ribu(), 162
INDEKS
350
setButton(), QButtonGroup,
104
setItalic(), QFont, 98
setLabel(), QHeader, 156
setCaption(), 85
setCellContentFromEditor(),
setMainWidget(), QApplica-
QTable, 166
setChecked(), QRadioButton,
102
setColor(), QBrush, 167
setColor(), QPen, 167
setColumnWidth(), QTable,
173
setCurrentCell(), QTable, 161
setDatabaseName(), QSqlDatabase, 184
setDefault(), QPushButton,
145
setDirection(), QBoxLayout,
136
setEditable(), QComboBox,
106
tion, 83
setMargin(), QLayout, 137
setMinimumHeight(), QWidget, 132, 134
setNumCols(), QTable, 156,
166
setNumRows(), QTable, 156,
160
setPaletteBackgroundColor(),
QWidget, 99
setPaletteForegroundColor(),
QWidget, 99
setPassword(), QSqlDatabase,
184
setPen(), QPainter, 168
setPointSize(), QFont, 97
setFamily(), QFont, 97
setSelectionMode(), QListBox,
setFocus(), QWidget, 93
109
setFont(), QWidget, 97
setGeometry(), QWidget, 88
setSqlCursor(), QDataTable,
193
setHostName(), QSqlDatabase,
setText(), 89
184
INDEKS
351
splitelds(), string, 78
setUnderline(), QFont, 98
setUsername(), QSqlDatabase,
184
storage, 24
str(), 42
91
string, modul, 61
sheet, 155
strip(), string, 78
shell tools, 22
su, 70
show(), QWidget, 84
showMaximized(), QWidget,
134
Sybase, 179
showmodal, 146
syntax error, 73
SIGNAL(), qt, 93
siklus pengembangan, 18
sinyal, 91, 94
sistem kepegawaian, 100
tabel, 155
sistem operasi, 27
situs, 21
slice, pemenggalan list, 45
slot, 93
sort(), list, 47
sort(), QListBox, 108
spinbox, 124
60
TableFile, le menjadi tabel,
170
tanggal(), string ke QTime,
199
Tanggal, class, 141
INDEKS
352
Tcl, 22
touch, 93
teks, pengolahan, 22
try, 55, 74
96
teksBerubah, LineCase, 95
ukuran huruf, 71
template1, 180
underline, font, 96
text editor, 29
text(), 89
Unix, 21
update(), dictionary, 49
text, CSV, 76
user, 88
textChanged(), QLineEdit,
95, 98, 111
time, modul, 61
timer, 143
valueChanged(), QSpinBox,
126
values(), dictionary, 49
toggle, QCheckBox, 99
values, dictionary, 48
variabel, 37
225
INDEKS
353
vi, 29
virtual, 186
visual object, 87
wadah, 123
waktu(), string ke QDateTime, 199
WaktuDigital, class, 143, 219
warna, QColor, 98
warning(), QMessageBox, 152
while, 60, 73, 85
white, 98
widget, istilah, 87
width(), QRect, 168
window manager, 81
Windows, 21
write(), le, 121
write, le, 69
x(), QRect, 168
y(), QRect, 168
year(), QDate, 140
yellow, 98
ZeroDivisionError, 73
zll(), string, 76