1. Grafik Arayüz Tasarımı // Temel Bilgiler¶
Bir programlama dilini ne kadar iyi bilirseniz bilin, bu programlama diliyle ne kadar güçlü programlar yazarsanız yazın, eğer programınız kullanışlı bir arayüze sahip değilse programınızın kullanıcı düzeyinde pek ilgi çekmeyeceği kesin... Belki bilgisayar kurtları komut satırından çalışan programları kullanmaktan rahatsız olmayacaktır, hatta sizi takdir de edecektir, ama “son kullanıcı” denen kesime hitap etmediğiniz sürece dikkati çekmeniz güç... Bu dikkati çekme meselesi de çoğunlukla kullanıcıya pırıltılı arayüzler sunularak aşılabiliyor. Diyelim ki komut satırı üzerinden harika işler yapan muhtemeşem bir program yazdınız ve programınızı kullanıma sundunuz... “Son kullanıcı”, programınızı kurup çalıştırmayı denediğinde vereceği ilk tepki: “Ama bu program çalışmıyor!” şeklinde olacaktır... Kızsak da kızmasak da ne yazık ki durum bu.. Dost acı söyler!
Madem arayüz denen şey bu kadar önemli şu halde biz de bu bölümde Python’da nasıl grafik arayüzler tasarlayabileceğimizi inceleyelim.
Python’da arayüz tasarımı için birden fazla seçeneğimiz var. Bunları bir çırpıda sıralayacak olursak, seçeneklerimizin şunlar olduğunu görürüz:
Arayüz tasarlamak üzere geliştirilmiş yukarıdaki alternatifler içinde biz Python tarafından resmi olarak desteklenen Tkinter’i kullanacağız. Peki neden ötekiler değil de Tkinter?
- Öncelikle Tkinter’in öteki seçeneklere karşı en büyük üstünlüğü Python dağıtımı ile birlikte gelmesidir.
- Dolayısıyla Tkinter Python tarafından resmi olarak desteklenen bir arayüz tasarım takımıdır.
- Tkinter hem Windows’ta hem de GNU/Linux üzerinde rahatlıkla çalışabilir. Aslında artık günümüzde öteki arayüz takımları da birden fazla platform üzerinde çalışabilmektedir. Ama dağıtımla birlikte geldiği için Tkinter ötekilere göre çok daha kolay ve rahat bir şekilde kurulup kullanıma hazır hale getirilebilir. Eğer Windows kullanıyorsanız, Tkinter sizde zaten Python’la beraber sisteminize kurulmuştur. Eğer GNU/Linux kullanıyorsanız, kullandığınız dağıtımın paket yöneticisini kullanarak tkinter paketini sisteminize kurabilirsiniz. Farklı GNU/Linux dağıtımlarında bu paketin adı farklı olabilir. Paket yöneticiniz içinde “tk” şeklinde arama yaparsanız muhtemelen doğru paketi bulabilirsiniz. Paket adı python-tk veya python2.x-tk gibi bir şey olacaktır...
- Tkinter oldukça sağlam, kararlı ve oturmuş bir arayüz takımıdır. Üstelik kullanımı da oldukça basittir. Öteki seçeneklere göre çok daha temiz ve sade bir sözdizimi vardır.
- Tkinter’in tek eksiği, bu arayüz takımıyla yapılan programların biraz “çirkin” görünmesidir. Ama mesela resim düzenleme yazılımlarını kullanarak Tkinter’in cemalini düzeltmek o kadar da zor bir iş değildir.
- Ben şahsen, Python programcılarının Tkinter’i kullanmayacak bile olsalar en azından temelini bilmeleri gerektiğini düşünüyorum. Tabii ki sizler Tkinter’i öğrendikten sonra öteki seçenekleri de incelemek isteyebilirsiniz...
Aslında Tkinter Python içinde bir modül... Neyse... Lafı daha fazla uzatmadan işe koyulalım:
1.1. Pencere Oluşturmak¶
Arayüz denilen şey tabii ki penceresiz olmaz. Dolayısıyla arayüz programlamanın ilk adımı çalışan bir pencere yaratmak olacaktır.
Başta söylediğimiz gibi, arayüz tasarlarken Tkinter modülünden faydalanacağız. Daha önceki yazılardan, Python’da nasıl modül “import” edildiğini hatırlıyorsunuz. Şimdi hemen Python’un etkileşimli kabuğunda şu komutu veriyoruz:
from Tkinter import *
Eğer hiçbir şey olmadan alt satıra geçildiyse sorun yok. Demek ki sizde Tkinter modülü yüklü. Ama eğer bu komutu verdiğinizde alt satıra düşmek yerine bir hata mesajı alıyorsanız, sebebi gerekli modülün, yani Tkinter’in sizde yüklü olmamasıdır. Eğer hal böyleyse yapacağımız işlem çok basit: Kullandığımız GNU/Linux dağıtımının paket yöneticisinden Tkinter modülünü içeren paketi gidip kuracağız. Benim şu anda kullandığım dağıtım olan Kubuntu’da bu paketin adı “python2.5-tk”. Sizde de paketin adı buna benzer bir şey olmalı. Mesela Pardus’ta Tkinter modülünü kullanmak için kurmanız gereken paketin adı “python-tk”. Dediğim gibi, eğer Windows kullanıyorsanız, sizde Tkinter modülü zaten yüklüdür. Windows kullanıcılarının Tkinter modülünü kullanabilmesi için ayrı bir şey yüklemesine gerek yok...
Modülle ilgili kısmı sağ salim atlattıysanız, artık şu komutu verebilirsiniz:
Tk()
Eğer buraya kadar herhangi bir hata yapmadıysak, ekrana pırıl pırıl bir arayüz penceresi zıpladığını görmemiz gerekiyor. Çok güzel, değil mi? Ne yalan söyleyeyim, ben bu pencereyi ilk gördüğümde çok heyecanlanmıştım... Neyse... Konumuza dönelim... Burada komutumuzu sadece “Tk()” şeklinde kullanabilmemiz, yukarıda Tkinter modülünü içe aktarma şeklimizden kaynaklanıyor. Yani Tkinter modülünü “from Tkinter import *” şeklinde içe aktardığımız için komutu “Tk()” şeklinde yazmamız yeterli oluyor. Eğer Tkinter modülünü “import Tkinter” şeklinde içe aktarsaydık, sadece “Tk()” dememiz yeterli olmayacaktı. O zaman “Tk()” yerine “Tkinter.Tk()” dememiz gerekirdi... İsterseniz modülü “import Tkinter” şeklinde içe aktarıp, sadece “Tk()” yazdığınızda ne tür bir hata aldığınızı kontrol edebilirsiniz. Neyse, konuyu daha fazla dağıtmadan yolumuza devam edelim:
Gördüğünüz gibi “Tk()” komutuyla önümüze atlayan pencere, bir pencerenin sahip olması gereken bütün temel özelliklere sahip. Yani pencerenin sağ üst köşesinde pencereyi kapatmaya yarayan bir çarpı işareti, onun solunda pencereyi büyütüp küçültmemizi sağlayan karecik ve en solda da pencereyi görev çubuğuna indirmemizi sağlayan işaret bütün işlevselliğiyle karşımızda duruyor. Ayrıca farkedeceğiniz gibi bu pencereyi istediğimiz gibi boyutlandırmamız da mümkün.
Bu komutları hangi platformda verdiğinize bağlı olarak, pencerenin görünüşü farklı olacaktır. Yani mesela bu komutları Windows’ta verdiyseniz, Windows’un renk ve şekil şemasına uygun bir pencere oluşacaktır. Eğer Gnome kullanıyorsanız, pencerenin şekli şemali, Gnome’nin renk ve şekil şemasına uygun olarak KDE’dekinden farklı olacaktır...
Yukarıda verdiğimiz “Tk()” komutuyla aslında Tkinter modülü içindeki “Tk” adlı sınıfı çağırmış olduk. Bu sınıfın neye benzediğini merak eden arkadaşlar /usr/lib/python2.5/lib-tk/ klasörü içindeki Tkinter.py modülü içinde “class Tk” satırını arayarak bunun ne menem bir şey olduğuna bakabilir (Gereksiz bilgi: “ne menem” ifadesinin doğrusu aslında “ne mene”... Ama hep “ne menem” biçiminde kullanıla kullanıla, yanlış kullanım doğru kullanım halini almış...) Bu arada herhangi bir hayal kırıklığı yaşamak istemiyorsanız, yukarıdaki “from Tkinter import *” ve “Tk()” komutlarını verirken büyük-küçük harfe dikkat etmenizi tavsiye ederim. Çünkü “Tkinter” ile “tkinter” aynı şeyler değildir...
Eğer bir arayüz oluşturacaksak sürekli komut satırında çalışamayız: Mutlaka yukarıda verdiğimiz komutları bir yere kaydetmemiz gerekir. Bunun için hemen boş bir belge açıp içine şu satırları ekleyelim:
from Tkinter import *
Tk()
Eğer bu dosyayı bu şekilde kaydeder ve çalıştırmayı denersek açılmasını beklediğimiz pencere açılmayacaktır. Burada komut satırından farklı olarak ilave bir satır daha eklememiz gerekiyor. Yani kodumuzun görünümü şu şekilde olmalı:
from Tkinter import *
Tk()
mainloop()
Belgemizin içine yukarıdaki kodları yazdıktan sonra bunu “.py” uzantılı bir dosya olarak kaydediyoruz ve normal Python dosyalarını nasıl çalıştırıyorsak öyle çalıştırıyoruz...
İsterseniz yukarıdaki kodu biraz derleyip toparlayalım. Çünkü bu şekilde kodlarımız çok sefil görünüyor. Yukarıdaki kodlar aslında bir program içinde şu şekilde görünecektir:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
mainloop()
Bu kodlar içinde gördüğümüz tek yenilik en sondaki “mainloop()” satırı. Bu satır program içinde bir “döngü” yaratarak, kendisinden önce gelen kodlarla belirlenen özelliklere göre bir pencere oluşturulmasını sağlıyor. Bu satırla yaratılan “döngü” sayesinde de oluşturulan pencere (aksi belirtilmedikçe veya kullanıcı pencereyi kapatmadıkça) ekranda hep açık kalabiliyor. Eğer bu son satırı yazmazsak, penceremiz yine de oluşur, ama biz pencereyi ekranda göremeyiz!.. Bu arada buraya küçük bir not düşelim. Eğer yazdığınız programı Python’la birlikte gelen bir metin düzenleyici olan IDLE içinden çalıştırıyorsanız, yazdığınız programın son satırına “mainloop()” ifadesini yerleştirmeseniz bile programınız hatasız bir şekilde çalışacaktır. Neden? Çünkü IDLE da Tkinter ile yazılmış bir uygulamadır. Dolayısıyla IDLE’nin de kendisine ait bir “mainloop()” satırı vardır. Yani siz kendi programınız içine mainloop()’u koymasanız bile IDLE’nin kendi mainloop()’u sizin programınızın da çalışmasını sağlayacaktır. Ancak mainloop() satırını koymadığınız halde programınız IDLE içinden çalışsa da başka yerde çalışmayacaktır. O yüzden bu mainloop() satırını mutlaka yerine koymalıyız...
Dilerseniz kodlarımızın derli toplu hale getirilmiş biçimine şöyle bir bakalım:
İlk satırı anlatmaya gerek yok. Bunun ne olduğunu zaten biliyorsunuz. Ayrıca zaten bildiğiniz gibi, bu satır sadece GNU/Linux kullanıcılarına yöneliktir. Windows kullanıcıları bu satırı yazmasalar da olur.
İkinci satırımız, yine bildiğiniz gibi, programımızı utf-8 ile kodlamamızı sağlıyor... Windows kullanıcılarının “utf-8” yerine “cp1254” kullanması gerekebilir...
Üçüncü satırda Tkinter modülünü programımızın içine aktarıyoruz (Yani “import” ediyoruz...).
Sonraki satırda, daha önce komut satırında kullandığımız “Tk()” sınıfını bir değişkene atadık. Nesne Tabanlı Programlama konusundan hatırlayacağınız gibi, bir sınıfı değişkene atama işlemine Python’da “instantiation”, yani “örnekleme” adı veriliyordu. İşte biz de burada aslında Tkinter modülü içindeki Tk() sınıfını örneklemiş olduk...
Son satırdaki “mainloop()” ise yazdığımız pencerenin ekranda görünmesini sağlıyor.
Daha önceki derslerimizde “Nesne Tabanlı Programlama” konusunu işlerken, sınıflı yapıların genellikle arayüz programlamada tercih edildiğini söylemiştik. İsterseniz yukarıda yazdığımız minik kodun sınıflar kullanılarak nasıl yazılabileceğine bakalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
pass
pencere = Tk()
mainloop()
Tabii yukarıdaki sınıf örneğinin pek bir anlamı yok... Yaptığı tek şey ekrana boş bir pencere getirmek. Üstelik yukarıdaki örnek, kod yapısı olarak mükemmel olmaktan uzak bir iskeletten ibaret... Bütün eksikliklerine rağmen yukarıdaki örnek bize bir Tkinter programının sınıflı bir yapı içinde temel olarak nasıl görüneceğini gösteriyor. Biz sayfalar ilerledikçe bu sınıfımızı daha iyi ve standart bir hale getireceğiz. Bu arada sınıfımızı oluştururken, Python’un yeni sınıf yapısına göre “object” adlı sınıfı miras aldığımıza dikkat edin.
Şimdiye kadar Python’da Tkinter yardımıyla boş bir pencere oluşturmayı öğrendik... Bu heyecan içinde bu kodları elli defa çalıştırıp elli defa boş bir pencere oluşmasını izlemiş olabilirsiniz... Ama bir süre sonra boş pencere sizi sıkmaya başlayacaktır. O yüzden, gelin isterseniz şimdi de bu boş pencereyi nasıl dolduracağımızı öğrenelim. Hemen yeni bir dosya açarak içine şu satırları ekliyoruz:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
İlk iki satırın ne olduğunu zaten biliyorsunuz, o yüzden açıklamaya gerek yok. Ondan sonra gelen satırda da bildiğiniz gibi Tkinter modülünü çağırdık. Bir alt satırda ise yaptığımız şey daha önce gördüğümüz “Tk()” komutuna bir ad vermekten, yani daha teknik bir dille ifade etmek gerekirse Tk() sınıfını örneklemekten ibaret... Biz “örnekleme” (instantiation) işlemi için burada “pencere” adını tercih ettik.. Tabii ki siz isterseniz emmoğlunuzun adını da verebilirsiniz... Hiç problem değil... Hatta hiç isim vermeseniz de olur. Ama kullanım kolaylığı ve performans açısından isimlendirmenin zararını değil, yararını görürsünüz... Şimdi kodlamaya kaldığımız yerden devam ediyoruz:
etiket = Label(text="Elveda Zalim Dünya!")
etiket.pack()
mainloop()
Burada “etiket” adlı yeni bir değişken oluşturduk. Her zamanki gibi bu “etiket” adı zorunlu bir isimlendirme değil. İstediğiniz ismi kullanmakta serbestsiniz. Ancak değişkenin ismi önemli olmasa da, içeriği önemli... “pencere = Tk()” komutu yardımıyla en başta oluşturduğumuz pencereyi bir kutu olarak düşünürsek, “etiket” adıyla tanımladığımız değişken de bu kutu üzerine yapıştırılacak bir etiket olarak düşünülebilir. Bahsettiğimiz bu kutunun üzerine etiketini yapıştırmak için “Label” adlı özel bir işlevden faydalanıyoruz. (Bu arada “label” kelimesi İngilizce’de “etiket” anlamına geliyor) “Label” ifadesini bu adla aklımıza kazımamız gerekiyor. Daha sonra bu Label ifadesine parametre olarak bir metin işliyoruz. Metnimiz “Elveda Zalim Dünya!”. Metnimizin adı ise “text”. “Label” ifadesinde olduğu gibi, “text” ifadesi de aklımıza kazımamız gereken ifadelerden birisi. Bunu bu şekilde öğrenmemiz gerekiyor. Kendi kendinize bazı denemeler yaparak bu satırda neleri değiştirip neleri değiştiremeyeceğinizi incelemenizi tavsiye ederim...
Bir alt satırda “etiket.pack()” ifadesini görüyoruz. Bu satır, yukarıdaki satırın işlevli hale gelmesini sağlıyor. Yani kutu üzerine etiketi yapıştırdıktan sonra bunu alıp kargoya vermemize yarıyor. Eğer bu satırı kullanmazsak bir güzel hazırlayıp etiketlediğimiz kutu kargoya verilmemiş olacağı için kullanıcıya ulaşmayacaktır.
En sondaki “mainloop()” ifadesini ise zaten tanıyorsunuz: Yukarıda yazdığımız bütün kodların döngü halinde işletilerek bir pencere şeklinde sunulmasını sağlıyor.
Kodlarımızın son hali şöyle olmalı:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Elveda Zalim Dünya!")
etiket.pack()
mainloop()
Gördüğünüz gibi yine gayet şık, içinde “Elveda Zalim Dünya!” yazan bir pencere elde ettik. Alıştırma olsun diye, yukarıda yazdığımız kodlara çok benzeyen başka bir örnek daha yapalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text = "Resimler klasörünü silmek istediğinizden emin misiniz?")
etiket.pack()
mainloop()
Şimdi isterseniz yukarıdaki kodları sınıflı yapı içinde nasıl gösterebileceğimize bakalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.etiket = Label(text="Dosyayı silmek istediğinize emin misiniz?")
self.etiket.pack()
pencere = Tk()
uyg = Uygulama()
mainloop()
Sınıfsız yapıdaki kodların sınıflı yapı içinde nasıl değişikliklere uğradığına dikkat edin. self’leri nasıl kullandığımızı inceleyin. Burada “pencere = Tk()” satırıyla Tk() sınıfını örnekledikten sonra “uyg = Uygulama()” satırıyla da, yukarıdaki kodların içinde yazdığımız “Uygulama” adlı sınıfımızı örnekliyoruz. En son satıra da “mainloop()” ifadesini yerleştirmeyi unutmuyoruz. Aksi halde oluşturduğumuz pencere ekranda görünmeyecektir...
Yukarıdaki sınıflı kodu isterseniz şu şekilde de yazabilirsiniz:
# -*- coding: utf-8 -*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.araclar()
def araclar(self):
self.etiket = Label(text="Dosyayı silmek istediğinizden emin misiniz?")
self.etiket.pack()
pencere = Tk()
uyg = Uygulama()
mainloop()
Gördüğünüz gibi burada “etiket” öğesini ayrı bir fonksiyon olarak belirledik. Programınız büyüyüp birbirinden farklı öğeler içermeye başladığı zaman bu öğeleri yukarıdaki şekilde farklı bölümlere ayırmak, kodlarınızı daha düzenli bir hale getirecek, ileride kodlarınızın bakımını yapmayı kolaylaştıracaktır.
Eğer bu sınıflı kodları anlamakta zorluk çekiyorsanız, yukarıda da bağlantısını verdiğimiz “Nesne Tabanlı Programlama” konusunu gözden geçirebilirsiniz. Bu arada hatırlatalım, Tkinter’i kullanmak için sınıflı yapıları bilmek zorunda değilsiniz. Ben de zaten bu sayfalarda sınıflı ve sınıfsız kullanımları bir arada vereceğim. Eğer sınıflı yapıyı anlamazsanız, sadece sınıfsız örneklerle de ilerleyebilirsiniz. Ama yine de benim size tavsiyem, sınıfları öğrenmeniz yönünde olacaktır. Çünkü internet üzerinde belli bir seviyeden sonra bu sınıflı yapılar hep karşınıza çıkacaktır. Yani siz kullanmasanız da, sınıfları kullanmayı bilmeniz sizin için faydalı olacaktır. Bu arada dikkat ederseniz, yukarıda verdiğimiz sınıflı son iki kod, daha önce verdiğimiz sınıflı koddan daha yetkin. Dediğimiz gibi, yeni özellikler öğrendikçe, kodlarımızı adım adım standartlara daha yakın hale getireceğiz.
Bu derste Tkinter’i kullanarak basit bir pencereyi nasıl oluşturabileceğimizi öğrendik. Örneklerimizi hem sınıflı hem de sınıfsız kodlarla gösterdik. Tabii ki sınıflı kodlar bu tür küçük örneklerde çok lüzumlu değildir. Ama büyük bir projede çalışırken sınıflı yapı size esneklik ve vakit kazandıracak, kodlarınızın bakımını daha kolay yapmanızı sağlayacaktır.
Bu açıklamaları da yaptığımıza göre başka bir bölüme geçebiliriz.
1.2. Pencere Başlığı¶
Bildiğiniz gibi, gündelik yaşamda karşımıza çıkan pencerelerde genellikle bir başlık olur. Mesela bilgisayarınız size bir hata mesajı gösterirken pencerenin tepesinde “Hata” ya da “Error” yazdığını görürsünüz. Mesela şu anda baktığınız pencerenin en tepesinde, “Grafik Arayüz Tasarımı // Temel Bilgiler – Tkinter 2.x Belgelendirme Çalışması” yazıyor. Eğer istersek biz de oluşturduğumuz pencerelerin tepesine böyle ifadeler yerleştirebiliriz. İşte bu işi yapmak, yani penceremizin başlığını değiştirmek için “title()” adlı metottan yararlanmamız gerekiyor. Yani bunun için yazdığımız kodlara şuna benzer bir satır eklemeliyiz:
pencere.title("Başlık")
Hemen bu özelliği bir örnekle gösterelim ki bu bilgi kafamızda somutlaşsın:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
baslik = pencere.title("Hiç bir işe yaramayan bir pencereyim ben...")
etiket= Label(text="...ama en azından bir başlığım var!")
etiket.pack()
mainloop()
Gördüğünüz gibi pencereye başlık eklemek son derece kolay... Tek bir satırla işi halledebiliyoruz. Üstelik herhangi bir “paketleme” işlemi yapmamız da gerekmiyor.
Dilerseniz şimdi yukarıdaki kodları sınıflı yapı içinde gösterelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.etiket = Label(text="Sabit diskiniz siliniyor...")
self.etiket.pack()
self.baslik = pencere.title("Çok Önemli Uyarı!")
pencere = Tk()
uyg = Uygulama()
mainloop()
Bu kodlar içindeki tek yenilik, “self.baslik = ......” satırıdır. Geri kalan kısımları zaten önceki örneklerden de biliyorsunuz.
Pencerelerle ilgili daha karmaşık özelliklere geçmeden önce isterseniz burada bir durup şimdiye kadar öğrendiklerimizi çok kısa bir şekilde özetleyelim:
- Tkinter’le arayüz tasarımı yapabilmek için öncelikle “from Tkinter import *” diyerek gerekli modülü yüklememiz gerekiyor.
- Ardından “Tk()” yardımıyla boş bir pencere oluşturuyoruz. Kullanım kolaylığı ve performans açısından “Tk()” ifadesini isimlendirerek bir değişkene atamayı (yani Tk() sınıfını örneklemeyi) tercih edebilirsiniz. Örneğin; kebap = Tk(). Performans açısından sınıflarımızı örneklemek gerekir, çünkü Nesne Tabanlı Programlama adlı dersten hatırlayacağınız gibi, örneklenmeyen sınıflar çöp toplama (garbage collection) adı verilen bir sürece tabi tutulacaktır...
- Bundan sonra pencere içine yazmak istediğimiz ifadeyi içeren bir etiket hazırlamamız gerekiyor. Bu etiketi alıp “Tk()” isimli kutunun üzerine yapıştıracağız. Bu iş için bize “Label()” adlı araç yardımcı olacak. Bu fonksiyonun parametresi olarak yazacağımız “text” adlı değişkene istediğimiz metni girebiliriz. Mesela: oyun = Label(text=”Bilgisayarınıza virüs bulaşmış!”)
- Etiketimizi hazırladıktan sonra paketleyip kargoya vermemiz gerekiyor. Grafik arayüzün kullanıcıya ulaşması için bu gerekli... Bunun için “xxx.pack()” ifadesini kullanacağız. Buradaki “xxx” yerine, bir üst satırda hazırladığımız etiket için kullandığımız ismi yazacağız. Mesela: oyun.pack()
- Bütün bu yazdığımız kodların işlevli hale gelebilmesi için ise en sona “mainloop()” ifadesini yerleştirmemiz gerekiyor.
- Eğer hazırladığımız pencerenin bir de başlığı olsun istiyorsak “title()” adlı metottan yararlanıyoruz.
Şu ana kadar yapabildiğimiz tek şey bir pencere oluşturup içine bir metin eklemek ve pencerede basitçe bir başlık oluşturmak. Ama tabii ki bir süre sonra bu da bizi sıkacaktır. Hem sadece bu özellikleri öğrenerek heyecan verici arayüzler hazırlamamız pek mümkün değil... En fazla, arkadaşlarımıza ufak tefek eşek şakaları yapabiliriz bu öğrendiklerimizle!
Yeri gelmişken, hazırladığımız programı, simgesi üzerine çift tıklayarak nasıl çalıştıracağımızı görelim şimdi. Gerçi daha önceki bölümlerden hatırlıyoruz bu işin nasıl yapılacağını, ama biz yine de tekrar hatırlatalım:
GNU/Linux kullanıcıları:
- .py uzantılı dosyamızı hazırlarken ilk satıra “#!/usr/bin/env python” ifadesini mutlaka yazıyoruz.
- Kaydettiğimiz .py uzantılı dosyaya sağ tıklayarak “özellikler”e giriyoruz
- Burada “izinler” sekmesinde “çalıştırılabilir” ifadesinin yanındaki kutucuğu işaretliyoruz
- “Tamam” diyerek çıkıyoruz.
Windows kullanıcıları:
- Windows kullanıcıları .py uzantılı dosyaya çift tıklayarak programı çalıştırabilir. Ancak bu şekilde arkada bir de siyah DOS ekranı açılacaktır.
- O DOS ekranının açılmaması için, kodlarımızı barındıran dosyamızı .py uzantısı ile değil .pyw uzantısı ile kaydediyoruz.
- Dosya uzantısını .pyw olarak belirledikten sonra dosya üzerine çift tıklayarak Tkinter programınızı çalıştırabilirsiniz.
- Windows kullanıcıları dosya kodlaması için “#--coding:cp1254” veya “#--coding:utf-8-*-” satırlarını kullanabilir.
Böylece artık programımızın simgesi üzerine çift tıklayarak arayüzümüzü çalıştırabiliriz.
1.3. Renkler¶
Dikkat ettiyseniz şimdiye dek oluşturduğumuz pencerelerde yazdığımız yazılar hep siyah renkte. Tabii ki, siz oluşturduğunuz pencereler içindeki metinlerin her daim siyah olmasını istemiyor olabilirsiniz. Öntanımlı renkleri değiştirmek sizin en doğal hakkınız. Tkinter’le çalışırken renklerle oynamak oldukça basittir. Renk işlemleri Tkinter’de birtakım ifadeler vasıtasıyla hallediliyor. Python dilinde bu ifadelere “seçenek” (option) adı veriliyor. Mesela daha önce öğrendiğimiz ve etiket içine metin yerleştirmemizi sağlayan “text” ifadesi de bir “seçenek”tir... Şimdi öğreneceğimiz seçeneklerin kullanımı da tıpkı bu “text” seçeneğinin kullanımına benzer.
1.4. fg seçeneği¶
Diyelim ki pencere içine yazdığımız bir metni, daha fazla dikkat çekmesi için kırmızı renkle yazmak istiyoruz. İşte bu işlem için kullanmamız gereken şey “fg” seçeneği... Bu ifade İngilizce’deki “foreground” (önplan, önalan) kelimesinin kısaltması oluyor. Hemen bir örnek verelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
pencere.title("Hata!")
etiket = Label(text = "Hata: Bilinmeyen Hata 404", fg="red")
etiket.pack()
mainloop()
Gördüğünüz gibi yaptığımız tek şey “fg” seçeneğini etiketin içine yerleştirmek. Burada kırmızı renk için kullandığımız kelime, İngilizce’de “kırmızı” anlamına gelen “red” sözcüğü... Yani “insan” dilinde kullanılan renkleri doğrudan Tkinter’de de kullanabiliyoruz. Tabii bu noktada biraz İngilizce bilmek işinizi bir hayli kolaylaştıracaktır. Tkinter’de kullanabileceğimiz, İngilizce renk adlarından birkaç tanesini hemen sıralayalım:
red = kırmızı
white = beyaz
black = siyah
yellow = sarı
blue = mavi
brown = kahverengi
green = yeşil
pink = pembe
Tkinter’de kullanılabilecek renk adları bunlarla sınırlı değil. Eğer mevcut renk listesini görmek isterseniz, şu adrese bir bakabilirsiniz: http://www.tcl.tk/man/tcl8.3/TkCmd/colors.htm. Tabii o listede sıralanan renkler arasından istediğinizi bulup çıkarmak pek kolay değil. Aynı zamanda renklerin kendisini de gösteren bir liste herhalde daha kullanışlı olurdu bizim için... Neyse ki çaresiz değiliz... Tkinter bize, renk adlarının yanısıra renk kodlarını kullanarak da yazılarımızı renklendirebilme imkanı veriyor. Renk kodlarını bulmak için şu adresten yararlanabilirsiniz: http://html-color-codes.info. Buranın avantajı, renklerin kendisini de doğrudan görebiliyor olmamız. Mesela orada beğendiğimiz herhangi bir rengin üzerine tıkladığımızda, alttaki kutucukta o rengin kodu görünecektir. Diyelim ki renk paletinden bir renk seçip üzerine tıkladık ve alttaki kutucukta şu kod belirdi: #610B0B. Bu kodu kopyalayıp kendi yazdığımız program içinde gerekli yere yapıştırabiliriz:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
pencere.title("Hata!")
etiket = Label(text = "Hata: Bilinmeyen Hata 404", fg="#610B0B")
etiket.pack()
mainloop()
Doğrudan renk adları yerine renk kodlarını kullanmak daha kesin sonuç verecektir. Ayrıca renk kodları size daha geniş bir renk yelpazesi sunacağı için epey işinize yarayacaktır.
Son olarak, yukarıdaki kodu sınıflı yapı içinde kullanalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.etiket = Label(text="Hello",fg = "red")
self.etiket.pack()
pencere = Tk()
uyg = Uygulama()
mainloop()
Veya öğeleri ayrı bir fonksiyon içinde belirtmek istersek...
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.araclar()
def araclar(self):
self.etiket = Label(text="Hata: Bilinmeyen Hata 404", fg="#610B0B")
self.etiket.pack()
pencere = Tk()
uyg = Uygulama()
mainloop()
Gördüğünüz gibi, bir önceki sınıflı örnekten pek farkı yok. Tek yenilik fg seçeneğinin de kodlar arasına eklenmiş olması...
1.5. bg seçeneği¶
Bu da İngilizce’deki “background” (arkaplan, arkaalan) kelimesinin kısaltması. Adından da anlaşılacağı gibi pencereye yazdığımız metnin arkaplan rengini değiştirmeye yarıyor. Kullanımı şöyle:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
pencere.title("Hata!")
etiket = Label(text = "Hata: Bilinmeyen Hata 404", bg="blue")
etiket.pack()
mainloop()
Yukarıda verdiğimiz renkleri bu seçenek için de kullanabilirsiniz. Ayrıca bu seçenek bir önceki “fg” seçeneğiyle birlikte de kullanılabilir:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
pencere.title("Hata!")
etiket = Label(text = "Hata monitörle sandalyenin tam arasında!",
fg="white",
bg="black")
etiket.pack()
mainloop()
Son örnekte renk kodları yerine renk adlarını kullandığımıza dikkat edin.
1.6. Yazı Tipleri (Fonts)¶
Tkinter bize renklerin yanısıra yazı tipleriyle de oynama imkanı veriyor. Hazırladığımız pencerelerdeki yazı tiplerini değiştirmek için, tıpkı renklerde olduğu gibi, yine bazı seçeneklerden faydalanacağız. Burada kullanacağımız seçeneğin adı, “font”. Bunu kullanmak için kodlarımız arasına şuna benzer bir “seçenek” eklememiz gerekiyor:
font= "Helvetica 14 bold"
Burada tahmin edebileceğiniz gibi, “Helvetica” yazı tipini; “14” yazı boyutunu; “bold” ise yazının kalın olacağını gösteriyor. Örnek bir kullanım şöyledir:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Merhaba Dostlar!", font="Times 15 italic")
etiket.pack()
mainloop()
Burada yazı tipi olarak “Times”; yazı boyutu olarak “15”; yazı biçimi olarak ise “italic”, yani “yatık” biçim seçtik. “font” seçeneği ile birlikte kullanabileceğimiz ifadeler şunlardır:
italic = yatık
underline = altı çizili
bold = kalın
overstrike = kelimenin üstü çizili
Yazı tipi olarak neleri kullanabileceğinizi, daha doğrusu kendi sisteminizde hangi yazıtiplerinin kurulu olduğunu ise şöyle öğrenebilirsiniz:
from Tkinter import *
import tkFont
pencere = Tk()
yazitipleri = list(tkFont.families() )
yazitipleri.sort()
for i in yazitipleri:
print i
Bu listede birden fazla kelimeden oluşan yazı tiplerini gösterirken kelimeleri birleşik yazmamız gerekiyor. Mesela “DejaVu Sans”ı seçmek için “DejaVuSans” yazmamız lazım...
1.7. Metin Biçimlendirme¶
Daha önceki yazılarımızda öğrendiğimiz metin biçimlemeye yarayan işaretleri Tkinter’de de kullanabiliyoruz. Yani mesela şöyle bir şey yapabiliyoruz:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Merhaba Dostlar!\n\tNasılsınız?", font="DejaVuSans 15 italic")
etiket.pack()
mainloop()
Gördüğünüz gibi, daha önceki yazılarımızda öğrendiğimiz “\n” ve “\t” kaçış dizilerini burada da kullanabiliyoruz.
1.8. İmleçler¶
Arayüzlerinizi oluştururken farklı imleç şekilleri kullanmak da isteyebilirsiniz. Bunun için kullanacağımız seçenek “cursor”. Mesela:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Deneme 1,2,3...", cursor="bottom_side")
etiket.pack()
mainloop()
Burada, imleci pencere üzerine getirdiğimizde imlecin ters ok şekli aldığını görürüz. Kullanılabilecek imleç isimleri için şu sayfaya bakabilirsiniz: http://www.dil.univ-mrs.fr/~garreta/PythonBBSG/docs/Tkinter_ref.pdf
Burada 10. ve 11. sayfalarda hoşunuza gidebilecek imleç isimlerini seçebilirsiniz. Bunun dışında yararlanabileceğiniz başka bir kaynak da şudur: http://www.tcl.tk/man/tcl8.4/TkCmd/cursors.htm
1.9. Pencere Boyutu¶
Diyelim ki içinde sadece bir “etiket” barındıran bir pencere oluşturduk:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
etiket = Label(text="Hata!")
etiket.pack()
mainloop()
Bu kodları çalıştırdığımızda karşımıza çıkan pencere çok küçük. O yüzden pencerenin tepesindeki eksi, küçük kare ve çarpı işaretleri görünmüyor. Bunları görebilmek için pencereyi elle boyutlandırmamız gerekiyor. Tabii bu her zaman arzu edilecek bir durum değil. Bu gibi durumları engelleyebilmemiz ve penceremizi istediğimiz boyutta oluşturabilmemiz için, Tkinter bize gayet kullanışlı bir imkan sunuyor:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
pencere.geometry("100x100+15+100")
etiket = Label(text="Hata!")
etiket.pack()
mainloop()
Gördüğünüz gibi, burada pencere.geometry ifadesinin karşısına birtakım sayılar ekleyerek penceremizi boyutlandırıyoruz. İlk iki rakam (100x100) penceremizin 100x100 boyutunda olduğunu; son iki rakam ise (+15+100) penceremizin ekrana göre soldan sağa doğru 15. pozisyonda; yukarıdan aşağıya doğru ise 100. pozisyonda açılacağını gösteriyor. Yani bu satır sayesinde penceremizin hem boyutunu hem de konumunu değiştirmiş oluyoruz. Bu dört rakamı değiştirerek kendi kendinize denemeler yapmanızı tavsiye ederim.
Şimdi son bir özellikten bahsedip bu konuyu kapatalım... Gördüğünüz gibi oluşturduğumuz bir pencere ek bir çabaya gerek kalmadan bir pencerenin sahip olabileceği bütün temel nitelikleri taşıyor. Buna pencerenin kullanıcı tarafından serbestçe boyutlandırılabilmesi de dahil... Ancak bazı uygulamalarda bu özellik anlamsız olacağı için (mesela hesap makinelerinde) kullanıcının pencereyi boyutlandırmasına engel olmak isteyebilirsiniz. Bu işi yapmak için şu kodu kullanıyoruz:
pencere.resizable(width=FALSE, height=FALSE)
Örnek bir uygulama şöyle olacaktır:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
pencere = Tk()
pencere.resizable(width=FALSE, height=FALSE)
etiket = Label(text="Deneme 1,2,3...", cursor="bottom_side")
etiket.pack()
mainloop()
Gördüğünüz gibi bu kodlar çalıştırıldığında ortaya çıkan pencere hiçbir şekilde boyutlandırma kabul etmiyor...
Şimdi isterseniz yukarıda verdiğimiz kodları sınıflı yapı içinde nasıl kullanacağımızı görelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
class Uygulama(object):
def __init__(self):
self.etiket = Label(text="Hata!")
self.etiket.pack()
pencere = Tk()
pencere.resizable(width=FALSE, height=FALSE)
uyg = Uygulama()
mainloop()
Böylelikle Arayüz Tasarımı konusunun “Temel Bilgiler” kısmını bitirmiş oluyoruz. Bir sonraki bölümde Tkinter’de “Pencere Araçlarını” (widgets) kullanmayı öğreneceğiz. Ama isterseniz yeni bölüme geçmeden önce şimdiye kadar öğrendiğimiz hemen hemen bütün konuları kapsayan bir örnek yapalım.
1.10. == Tekrar ==¶
Şimdiye kadar Tkinter’in özelliklerine ve nasıl kullanılacağına ilişkin pek çok konu işledik. Yani artık temel olarak Tkinter’in neye benzediğini ve bununla neler yapabileceğimizi az çok biliyoruz. Temel Bilgiler kısmını geride bırakıp yeni bir bölüme geçmeden önce, şimdiye kadar öğrendiklerimizi bir araya getiren bir örnek yapalım. Böylece öğrendiklerimizi test etme imkanı bulmuş olacağız. Bu yazıda vereceğim örneği olabildiğince ayrıntılı bir şekilde açıklayacağım. Eğer aklınıza takılan bir yer olursa bana nasıl ulaşacağınızı biliyorsunuz...
Şimdi örneğimize geçelim... Amacımız 1 ile 100 arasında 6 tane rastgele sayı üretmek. Yalnız bu 6 sayının her biri benzersiz olacak. Yani 6 sayı içinde her sayı tek bir defa geçecek... Önce kodlarımızın tamamını verelim:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
import random
liste = []
pencere = Tk()
pencere.geometry("200x50+600+460")
etiket = Label(fg="white", bg="#61380B",font="Helvetica 12 bold")
etiket.pack()
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
mainloop()
Bu kodları her çalıştırışımızda, 1 ile 100 arasında, birbirinden farklı altı adet rastgele sayı ekranda görünecektir... Tkinter’e ilişkin kodlara geçmeden önce, isterseniz yukarıda kullandığımız, rastgele sayı üretmemizi sağlayan Python kodunu biraz açıklayalım:
- Rastgele sayılar üreteceğimiz için öncelikle Python’un “random” adlı modülünü içe aktarıyoruz. Bu modül bu tür rastgele sayı üretme işlemlerinde kullanılır.
- random modülü içindeki randint metodu bize, örneğin, 1’den 100’e kadar rastgele sayılar üretme imkanı sağlar. Ancak random.randint(1,100) dediğimiz zaman, bu kod 1’den 100’e kadar rastgele tek bir sayı üretecektir. Bizim amacımız altı adet rastgele sayı üretmek.
- Amacımız altı adet sayı üretmek olduğu için öncelikle “for i in range(6):” satırı yardımıyla altı kez işletilecek bir döngü oluşturuyoruz. (Bunun mantığıyla ilgili aklınızda şüpheler varsa, for i in range(6): print “Merhaba Dünya!” komutunu vererek şüphelerinizi giderebilirsiniz...) Bu döngü nihai olarak random.randint() fonksiyonunu altı kez çalıştıracaktır. Böylelikle elimizde altı adet sayı olmuş olacak. Ancak üretilen bu altı sayının hepsi birbirinden farklı olmayabilir. Yani bazı sayılar birden fazla üretilebilir. Dolayısıyla “1, 5, 5, 7, 56, 64” gibi bir diziyle başbaşa kalabiliriz. Ama bizim amacımız altı sayının hepsinin birbirinden farklı olması. O yüzden bunu sağlayacak bir önlem almamız gerekiyor.
- Bu bahsettiğimiz önlemi “if a not in liste: liste.append(a)” satırlarıyla alıyoruz. Aradaki while döngüsü başka bir işe yarıyor. Onu birazdan açıklayacağız. “If a not in liste: liste.append(a)” satırlarıyla, “Eğer random.randint(1,100) komutu ile üretilen sayı liste içinde yer almıyorsa bu sayıyı listeye ekle!” emrini veriyoruz. Yani random.randint ile her sayı üretilişinde Python’un bu sayıyı listeye eklemeden önce, listede bu sayının zaten var olup olmadığını kontrol etmesini istiyoruz. Eğer üretilen sayı listede yoksa, liste.append() komutu sayesinde sayımız listeye eklenecek, yok eğer üretilen sayı listede zaten varsa o sayı listeye alınmayacaktır. Ancak burada bir sorun çıkıyor karşımıza. Eğer üretilen sayı listede zaten varsa, yukarıda yazdığımız komut gereği o sayı listeye alınmayacak, bu durumda listede 6’dan az sayı kalacaktır. Bizim, üretilen sayıların aynı olması durumunda random.randint’in altıyı tamamlayana kadar tekrar tekrar sayı üretmesini sağlamamız gerekiyor.
- İşte bu işlemi yukarıdaki while döngüsü yardımıyla yapacağız. “while len(liste) != 6:” satırı ile liste uzunluğunun 6’ya eşit olup olup olmadığını denetliyoruz. Yani Python’a şu emri veriyoruz. “liste’nin uzunluğu 6’ya eşit olmadığı sürece random.randint(1,100) komutunu işletmeye devam et!”. Böylelikle, listedeki tekrar eden sayılar yüzünden liste içeriği 6’dan küçük olduğunda, bu “while” döngüsü sayesinde Python listeyi altıya tamamlayana kadar random.randint’i çalıştırmaya devam edecektir... “if a not in liste:” satırı nedeniyle zaten listede var olan sayıları listeye ekleyemeyeceği için de, benzersiz bir sayı bulana kadar uğraşacak ve neticede bize altı adet, birbirinden farklı sayı verecektir...
Kodların Tkinter ile ilgili kısmına gelecek olursak... Esasında yukarıdaki kodlar içinde geçen her satırı anlayabilecek durumdayız. Şimdiye kadar görmediğimiz tek biçim, “etiket[“text”] = liste” satırı... Bu biçimle ilgili olarak şunu söyleyebiliriz: Tkinter’deki etiket, düğme, vb öğelerin niteliklerini, yukarıda görüldüğü şekilde, tıpkı bir sözlüğün öğelerini değiştirirmiş gibi değiştirebiliriz. Yukarıdaki yapının, sözlük öğelerini değiştirme konusunu işlerken gördüğümüz sözdiziminin aynısı olduğuna dikkat edin... Mesela bu yapıyı kullanarak şöyle bir şey yapabiliriz. Diyelim ki programımız içinde aşağıdaki gibi bir etiket tanımladık:
etiket = Label(fg="white", bg="#61380B",font="Helvetica 12 bold")
etiket.pack()
Etiketin “text” seçeneğinin bulunmadığına dikkat edin. İstersek yukarıdaki satırda “text” seçeneğini, text = “” şeklinde boş olarak da tanımlayabiliriz. Bu etiketi bu şekilde tanımladıktan sonra, programımız içinde başka bir yerde bu etiketin “text” seçeneğini, öteki özellikleriyle birlikte tek tek değiştirebiliriz. Şöyle ki:
etiket["text"] = "www.istihza.com"
etiket["fg"] = "red"
etiket["bg"] = "black"
etiket["font"] = "Verdana 14 italic"
Bu yapının Python’daki sözlüklere ne kadar benzediğine bir kez daha dikkatinizi çekmek isterim... Bu yüzden bu yapıyı öğrenmek sizin için zor olmasa gerek.
Şimdi isterseniz yukarıda verdiğimiz örneğin sınıflı yapı içinde nasıl görüneceğine bir bakalım:
#!/usr/bin/env python
#-*-coding:utf-8-*-
from Tkinter import *
import random
liste = []
class Uygulama(object):
def __init__(self):
self.araclar()
self.kodlar()
def kodlar(self):
for i in range(6):
while len(liste) != 6:
a = random.randint(1,100)
if a not in liste:
liste.append(a)
self.etiket["text"] = liste
def araclar(self):
self.etiket = Label(fg="white", bg="#61380B",font="Helvetica 12 bold")
self.etiket.pack()
pencere = Tk()
pencere.geometry("150x50+600+460")
uyg = Uygulama()
mainloop()
Gördüğünüz gibi, sınıflı yapı içinde, kodları ufak bölümlere ayırarak incelenmelerini kolaylaştırmış olduk... Artık örneğimizi de verip açıklamalarımızı da yaptığımıza göre, gönül rahatlığıyla bir sonraki bölüme geçebiliriz.