2. Pencere Araçları (Widgets) – 1. Bölüm¶
Arayüz uygulamaları tabii ki sadece pencerelerden ibaret değildir. Arayüzler üzerinde, istediğimiz işlemleri yapabilmemiz için yerleştirilmiş birtakım menüler, yazılar, düğmeler, kutucuklar ve buna benzer araçlar da bulunur. İşte herhangi bir programın arayüzü üzerinde bulunan düğmeler, etiketler, sağa-sola, yukarı-aşağı kayan çubuklar, kutular, kutucuklar, menüler, vb. hepsi birden pencere araçlarını, yani widget’leri, oluşturuyor.
Aslında şimdiye kadar bu pencere araçlarından bir tanesini gördük. Bildiğimiz bir pencere aracı olarak elimizde şimdilik “Label” bulunuyor. Gelin bu “Label” adlı pencere aracına biraz daha yakından bakalım:
2.1. “Label” Pencere Aracı¶
Daha önce de söylediğimiz gibi bu kelime İngilizce’de “etiket” anlamına geliyor. Bu araç, anlamına uygun olarak pencerelerin üzerine etiket misali öğeler yapıştırmamızı sağlıyor.
Hatırlayacağınız gibi bu aracı “Label()” şeklinde kullanıyorduk. İsterseniz bununla ilgili olarak hemen basit bir örnek verelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text = "Hata: Bellek Read Olamadı!")
etiket.pack()
mainloop()
Gördüğünüz gibi yukarıdaki kullanımda “Label” aracı bir metnin pencere üzerinde görüntülenmesini sağlıyor.
2.2. “Button” Pencere Aracı¶
Bu araç yardımıyla pencerelerimize, tıklandıklarında belli bir işlevi yerine getiren düğmeler ekleyebileceğiz. Hemen bir örnek verelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
dugme = Button(text="TAMAM", command = pencere.quit)
dugme.pack()
mainloop()
Dikkat ederseniz, “Button()” aracının kullanımı daha önce gördüğümüz “Label” aracının kullanımına çok benziyor. Burada da parantez içinde bazı parametreler kullandık. “text” parametresini zaten biliyoruz: Kullanıcıya göstermek istediğimiz metni bu “text” parametresi yardımıyla belirliyoruz. Aynı parantez içinde gördüğümüz “command” parametresi ise düğme üzerine tıklandığında işletilecek komutu gösteriyor. Biz burada “pencere.quit” komutunu vererek, düğmeye tıklandığında pencerenin kapatılmasını istedik. Dolayısıyla bir satır içinde üç yeni özellik görmüş oluyoruz:
- Button
- Kullanacağımız pencere aracı (İngilizce “button” kelimesi Türkçe’de “düğme” anlamına gelir).
- command
- Oluşturduğumuz düğmeye tıklandığında çalıştırılacak komut
- xxx.quit
- Düğmeye tıklandığında pencerenin kapatılmasını sağlayan komut.
Daha sonra gelen satırdaki ifade size tanıdık geliyor olmalı: “dugme.pack()”. Tıpkı daha önce “etiket.pack()” ifadesinde gördüğümüz gibi, bu ifade de hazırladığımız pencere aracının kargoya verilmek üzere “paketlenmesini” sağlıyor.
En son satırdaki “mainloop()” ifadesinin ne işe yaradığını artık söylemeye bile gerek yok...
Yukarıda bahsettiğimiz “command” parametresi çok güzel işler yapmanızı sağlayabilir. Mesela diyelim ki, “oluştur” düğmesine basınca bilgisayarda yeni bir dosya oluşturan bir arayüz tasarlamak istiyoruz. O halde hemen bu düşüncemizi tatbik sahasına koyalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
def olustur():
dosya = open("deneme.txt", "w")
dugme = Button(text = "oluştur", command=olustur)
dugme.pack()
mainloop()
Gördüğünüz gibi, Tkinter modülünü çağırıp “pencere = Tk()” şeklinde penceremizi oluşturduktan sonra bir fonksiyon yazdık. Tkinter dışından bir komut çalıştırmak istediğimizde bu şekilde bir fonksiyon tanımlamamız gerekir.
Daha sonra Button() pencere aracı yardımıyla, pencereye yerleştireceğimiz düğmeyi meydana getirdik. Burada “command” parametresine biraz önce oluşturduğumuz fonksiyonu atayarak düğmeye basıldığında yeni bir dosya oluşturulmasına zemin hazırladık. “text” parametresi yardımıyla da düğmemizin adını “oluştur” olarak belirledik. Ondan sonraki satırları ise zaten artık ezbere biliyoruz.
Eğer bu kodları yazarken, yukarıdaki gibi bir fonksiyon oluşturmadan;
dugme = Button(text = "oluştur", command=open("deneme.txt","w"))
gibi bir satır oluşturursanız, “deneme.txt” adlı dosya düğmeye henüz basmadan oluşacaktır...
İsterseniz bu arayüze bir de “çıkış” düğmesi ekleyebiliriz:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
def olustur():
dosya = open("deneme.txt", "w")
dugme = Button(text = "oluştur", command=olustur)
dugme.pack()
dugme2 = Button(text = "çıkış", command=pencere.quit)
dugme2.pack()
mainloop()
Burada yaptığımız şey, ikinci bir düğme oluşturmaktan ibaret... Oluşturduğumuz “dugme2” adlı değişken için de “dugme2.pack” ifadesini kullanmayı unutmuyoruz.
Düğmelerin pencere üstünde böyle alt alta görünmesini istemiyor olabilirsiniz. Herhalde yan yana duran düğmeler daha zarif görünecektir. Bunun için kodumuza şu eklemeleri yapmamız gerekiyor:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
def olustur():
dosya = open("deneme.txt", "w")
dugme = Button(text = "oluştur", command=olustur)
dugme.pack(side=LEFT)
dugme2 = Button(text = "çıkış", command=pencere.quit)
dugme2.pack(side=RIGHT)
mainloop()
“Paketleme” aşamasında düğmelerden birine “side=LEFT” parametresini ekleyerek o düğmeyi sola; öbürüne de “side=RIGHT” parametresini ekleyerek sağa yaslıyoruz.
İsterseniz gelin şu son yaptığımız örneği sınıflı yapı içinde göstererek sınıflarla ufak bir pratik daha yapmış olalım...
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.dugme = Button(text="oluştur", command=self.olustur)
self.dugme.pack(side=LEFT)
self.dugme2 = Button(text="çıkış", command=pencere.quit)
self.dugme2.pack(side=RIGHT)
def olustur(self):
self.dosya = open("denene.txt","w")
pencere = Tk()
uyg = Uygulama()
mainloop()
Hatırlarsanız önceki derslerimizden birinde, 1-100 arası sayılar içinden rastgele altı farklı sayı üreten bir uygulama yazmıştık. Artık “Button” adlı pencere aracını öğrendiğimize göre o uygulamayı birazcık daha geliştirebiliriz. Mesela o uygulamaya bir düğme ekleyebilir, o düğmeye basıldıkça yeni sayıların üretilmesini sağlayabiliriz:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
import random
pencere = Tk()
pencere.geometry("300x50+600+460")
def kodlar():
liste = []
for i in range(6):
while len(liste) != 6:
a = random.randint(1,100)
if a not in liste:
liste.append(a)
etiket["text"] = liste
etiket = Label(text="Sayı üretmek için düğmeye basınız!",
fg="white",
bg="#61380B",
font="Helvetica 12 bold")
etiket.pack()
dugme = Button(text="Yeniden",command=kodlar)
dugme.pack()
mainloop()
Burada, programda ana işlevi gören kodları “kodlar()” adlı bir fonksiyon içine aldık. Çünkü “Button” pencere aracı içindeki “command” seçeneğine atayabilmemiz için elimizde bir fonksiyon olması gerekiyor. Düğmeye bastığımızda Tkinter, fonksiyon içindeki bu kodları işletecek. Düğmeye her basıldığında liste öğelerinin yenilenebilmesi için “liste = []” satırını fonksiyon içine alıyoruz. Böylece düğmeye ilk kez basıldığında önce liste öğesinin içi boşaltılacak, ardından altı adet sayı üretilip etikete yazdırılacaktır. Böylelikle düğmeye her basışımız yeni bir sayı dizisi oluşturacaktır. Eğer “liste = [ ]” satırını fonksiyon dışında tanımlarsak, düğmeye ilk basışımızda altı adet sayı üretilecektir, ama ikinci kez düğmeye bastığımızda, liste hâlâ eski öğeleri tutuyor olacağı için etiket yenilenmeyecek, düğmeye her basışımızda eski sayılar etikete yazdırılmaya devam edecektir. Bizim istediğimiz şey ise, düğmeye her basışta yeni bir sayı setinin etikete yazdırılması. Bunun için “liste = []” satırını fonksiyon içine almamız gerekiyor...
Programımızın işlevini yerine getirebilmesi için kullanıcının bir düğmeye basması gerekiyor. Bu yüzden kullanıcıya ne yapması gerektiğini söylesek iyi olur. Yani kullanıcımızı düğmeye basmaya yönlendirmemiz lazım. Bu amaçla etiket’in “text” seçeneğine “Sayı üretmek için düğmeye basınız!” şeklinde bir uyarı yerleştirdik. Programımız ilk kez çalıştırıldığında kullanıcı öncelikle bu uyarıyı görecek, böylelikle programı kullanabilmek için ne yapması gerektiğini bilecektir. Belki bu küçük programda çok belirgin olmayabilir, ama büyük programlarda, etiketler üzerine yazdığımız yönergelerin açık ve anlaşılır olması çok önemlidir. Aksi halde kullanıcı daha programı deneyemeden bir kenara atabilir... Tabii biz böyle olmasını istemeyiz, değil mi?
Şimdi de bu kodları sınıflı yapıya çevirelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
import random
class Uygulama(object):
def __init__(self):
self.araclar()
def kodlar(self):
self.liste = []
for i in range(6):
while len(self.liste) != 6:
a = random.randint(1, 100)
if a not in self.liste:
self.liste.append(a)
self.etiket["text"] = self.liste
def araclar(self):
self.etiket = Label(text="Sayı üretmek için düğmeye basınız!",
fg="white",
bg="#61380B",
font="Helvetica 12 bold")
self.etiket.pack()
self.dugme = Button(text="Yeniden", command = self.kodlar)
self.dugme.pack()
pencere = Tk()
pencere.geometry("300x50+600+460")
uyg = Uygulama()
mainloop()
Bu kodlar da önceki gördüklerimizden çok farklı değil. Artık sınıflı bir Tkinter kodunun neye benzediğini gayet iyi biliyoruz...
2.3. “Entry” Pencere Aracı¶
Bu araç yardımıyla kullanıcının metin girebileceği tek satırlık bir alan oluşturacağız. Bu pencere aracının kullanımı da diğer araçların kullanımına benzer. Hemen bir örnek verelim:
from Tkinter import *
pencere = Tk()
giris = Entry()
giris.pack()
mainloop()
Her zamanki gibi ilk önce Tkinter modülünü çağırarak işe başladık. Hemen ardından da “pencere” adını verdiğimiz boş bir pencere oluşturduk. Dediğimiz gibi, “Entry” aracının kullanımı daha önce sözünü ettiğimiz pencere araçlarının kullanımına çok benzer. Dolayısıyla “giris” adını verdiğimiz “Entry()” aracını rahatlıkla oluşturabiliyoruz. Bundan sonra yapmamız gereken şey, tabii ki, bu pencere aracını paketlemek. Onu da “giris.pack()” satırı yardımıyla hallediyoruz. Son darbeyi ise “mainloop” komutuyla vuruyoruz.
Gördüğünüz gibi, kullanıcıya tek satırlık metin girme imkanı veren bir arayüz oluşturmuş olduk. İsterseniz şimdi bu pencereye birkaç düğme ekleyerek daha işlevli bir hale getirelim arayüzümüzü. Mesela pencere üzerinde programı kapatmaya yarayan bir düğme ve kullanıcının yazdığı metni silen bir düğme bulunsun:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from Tkinter import *
pencere = Tk()
def sil():
giris.delete(0, END)
giris = Entry()
giris.pack()
dugme1 = Button(text = "KAPAT", command = pencere.quit)
dugme1.pack(side = LEFT)
dugme2 = Button(text = "SİL", command = sil)
dugme2.pack(side = RIGHT)
mainloop()
Bu kodlar içinde bize yabancı olan tek ifade “giris.delete(0, END)”. Bu komut, görünüşünden de anlaşılacağı gibi, “giris” değişkeninin içeriğini silmeye yarıyor. Parantez içindeki “0, END” ifadesi, metin kutusuna girilen kelimenin en başından en sonuna kadar bütün harflerin silinmesi emrini veriyor. Eğer “0, END” yerine, mesela “2, 4” gibi bir ifade koysaydık, girilen kelimenin 2. harfinden itibaren 4. harfine kadar olan kısmın silinmesi emrini vermiş olacaktık. Son bir alıştırma yaparak bu aracı da tamamlayalım:
#!/usr/bin/env python
#-*- coding:utf-8-*-
from Tkinter import *
pencere = Tk()
def olustur():
dosya = open("deneme.txt","w")
metin = giris.get()
dosya.write(metin)
giris = Entry()
giris.pack()
dugme = Button(text = "OLUŞTUR", command = olustur)
dugme.pack(side=LEFT)
dugme2 = Button(text = "ÇIK", command = pencere.quit)
dugme2.pack(side=RIGHT)
mainloop()
Burada da bize yabancı olan tek ifade “giris.get()”... Bu ifade “Entry” pencere aracı ile kullanıcıdan aldığımız metni elimizde tutup saklamamızı sağlıyor. Burada bu ifadeyi önce “metin” adlı bir değişkene atadık, sonra da bu metin değişkeninin içeriğini “dosya.write(metin)” komutunun yardımıyla boş bir dosyaya aktardık. Metin kutusunun içeriğini barındıran “deneme.txt” isimli dosya /home klasörünüzün altında veya masaüstünde oluşmuş olmalı...
Bir örnek daha yapalım...
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
import random
pencere = Tk()
def bas():
a = random.randint(1, 100)
giris.delete(0, END)
giris.insert(0, a)
giris = Entry(width=10)
giris.pack()
dugme = Button(text="bas", command=bas, width=2, height=0)
dugme.pack()
mainloop()
Gördüğünüz gibi, bu uygulama 1 ile 100 arasında rastgele sayılar seçiyor... Aslında yaptığımız işlem çok basit:
Öncelikle Python’un “random” adlı modülünü çağırdık. Daha önce de gördüğümüz gibi, rastgele sayılar seçerken bize bu modül yardımcı olacak. Ardından da bu rastgele sayıları oluşturup ekrana yazdırmamızı sağlayacak fonksiyonu oluşturuyoruz. Bu fonksiyonda öncelikle rastgele sayıların hangi aralıkta olacağını belirleyip bunu “a” adlı bir değişkene atıyoruz. Böylece rastgele sayıları ekrana yazdırmak için gereken altyapıyı oluşturmuş olduk. Şimdi bu noktada eğer bir önlem almazsak ekrana basılacak sayılar yan yana sıralanacaktır. Yani mesela diyelim ki ilk rastgele sayımız 3 olsun. Bu 3 sayısı ekrana yazıldıktan sonra ikinci rastgele sayı ekrana gelmeden önce bu ilk sayının ekrandan silinmesi gerekiyor. Bütün sayılar yan yana ekrana dizilmemeli. Bunun için kodumuza şu satırı ekliyoruz:
giris.delete(0, END)
Bu satır sayesinde, ilk sayı ekrana basıldıktan sonra ekranın 0. konumundan sonuncu konumuna kadar bütün her şeyi siliyoruz. Böylelikle ikinci gelecek sayı için yer açmış oluyoruz. İsterseniz yukarıdaki kodları bu satır olmadan çalıştırmayı bir deneyebilirsiniz. Ondan sonra gelen satırın ne işe yaradığını anlamışsınızdır: “a” değişkenini 0. konuma yerleştiriyoruz. Fonksiyonumuzu böylece tamamlamış olduk. Daha sonra normal bir şekilde “Entry” ve Button” adlı pencere araçları yardımıyla düğmelerimizi ve metin alanımızı oluşturuyoruz. Burada bazı yeni “seçenekler” dikkatiniz çekmiş olmalı: Bunlar, “width” ve “height” adlı seçenekler... “width” seçeneği yardımıyla bir pencere aracının genişliğini; “height” seçeneği yardımıyla ise o aracın yüksekliğini belirliyoruz.
2.4. Frame()¶
Frame() Tkinter içinde bulunan sınıflardan biridir. Bu sınıf aynı zamanda bir pencere aracı (widget) olarak da kullanılabilir. Bir pencere aracı olarak kullanıldığında bu sınıfın görevi, pencere içindeki öbür pencere araçlarını pencere içinde rahatça konumlandırmayı sağlamaktır. Bu araçtan, ileride geometri yöneticilerini (geometry managers) işlerken daha ayrıntılı olarak bahsedeceğiz. Bu derste Frame() pencere aracının temel olarak nasıl kullanıldığına dair birkaç örnek vermekle yetineceğiz. Mesela şu örneğe bir bakalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Aşağıdaki kutucuğa e.posta adresinizi yazınız!")
etiket.pack()
giris = Entry()
giris.pack()
dugme = Button(text="Gönder",command=pencere.destroy)
dugme.pack()
mainloop()
Burada gördüğünüz gibi, “gönder” düğmesi hemen üstündeki kutucuğa çok yakın duruyor. Bu arayüzün daha iyi görünmesi için bu iki pencere aracının arasını biraz açmak isteyebiliriz. İşte Frame() aracı böyle bir ihtiyaç halinde işimize yarayabilir:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Aşağıdaki kutucuğa e.posta adresinizi yazınız!")
etiket.pack()
giris = Entry()
giris.pack()
cerceve = Frame()
cerceve.pack()
dugme = Button(text="Gönder",command=pencere.destroy)
dugme.pack()
mainloop()
Gördüğünüz gibi, Frame() aracını “giris” ve “dugme” adlı pencere araçlarının arasına yerleştirdik. Bu kodları çalıştırdığımızda, düğmenin azıcık da olsa aşağıya kaydığını göreceksiniz. Eğer kayma oranını artırmak isterseniz, “pad” seçeneğinden yararlanabilirsiniz. Bu seçenek, bir pencere aracının, öteki pencere araçları ile arasını açmaya yarıyor. pad seçeneği iki şekilde kullanılabilir: “padx” ve “pady”. Bu iki seçenekten “padx”, x düzlemi üzerinde işlem yaparken, “pady” ise y düzlemi üzerinde işlem yapıyor. Yani:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Aşağıdaki kutucuğa e.posta adresinizi yazınız!")
etiket.pack()
giris = Entry()
giris.pack()
cerceve = Frame()
cerceve.pack(pady=5)
dugme = Button(text="Gönder",command=pencere.destroy)
dugme.pack()
mainloop()
Burada sadece “pady” seçeneğini kullanmamız yeterli olacaktır. Çünkü bizim bu örnekte istediğimiz şey, iki pencere aracının arasını y düzlemi üzerinde açmak. Yani yukarıdan aşağıya doğru... Eğer x düzlemi üzerinde işlem yapmak isteseydik (yani soldan sağa doğru), o zaman padx seçeneğini de kullanacaktık. İsterseniz bu padx ve pady seçeneklerine bazı sayılar vererek birtakım denemeler yapabilirsiniz. Bu sayede bu seçeneklerin ne işe yaradığı daha net anlaşılacaktır. Ayrıca dikkat ederseniz, bu padx ve pady seçenekleri, daha önce gördüğümüz “side” seçeneğine kullanım olarak çok benzer. Hem padx ve pady, hem de side seçenekleri, pack aracının birer özelliğidir. Bu özelliklere ileride daha ayrıntılı olarak değineceğiz.
İsterseniz yukarıdaki kodların sınıflı yapı içinde nasıl görüneceğine de bir bakalım...
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.guiPenAr()
def guiPenAr(self):
self.etiket = Label(text="Aşağıdaki kutucuğa e.posta adresinizi yazınız!")
self.etiket.pack()
self.giris = Entry()
self.giris.pack()
self.cerceve = Frame()
self.cerceve.pack(pady=5)
self.dugme = Button(text="Gönder",command=pencere.destroy)
self.dugme.pack()
pencere = Tk()
uyg = Uygulama()
mainloop()
Şimdilik bu Frame() pencere aracını burada bırakıyoruz. Bir sonraki bölümde bu araçtan ayrıntılı olarak bahsedeceğiz.
Böylelikle Pencere Araçları konusunun ilk bölümünü bitirmiş olduk. Şimdi başka bir pencere aracı grubuna geçmeden önce çok önemli bir konuya değineceğiz: Tkinter’de Geometri Yöneticileri (Geometry Managers).