Modüller | tkinter

tkinter, nesnelerle çalışmamıza olanak tanır. Daha net bir tanım ile tkinter; GUI dediğimiz "Graphical User Interface - Grafiksel Kullanıcı Arayüzü" yapıları oluşturmamıza olanak tanır. İçerisinde butonlar, metinsel ifadeler ve normal bir uygulamada bulunabilecek neredeyse her şey vardır. Çok geniş kapsamlı ve detaylı olduğu için yaptıklarımızı okumakla kalmayıp bunları uygulamanız sizin yararınıza olacaktır.

Her şeyden önce bu modülü import etmemiz lazım. Ancak bunu, benim yaptığım şekilde yaparsanız uygulamanız daha kolay olacaktır. from tkinter import * diyorum ve modülü içe aktarıyorum.

Şimdi, yapmam gereken ilk şey bir tkinter objesi oluşturmak olmalı. Önceki modüllerden bileceğiniz üzere oluşturduğumuz bu objeler, modüldeki özellikleri kendilerine alıyor ve işimizi kolaylaştırıyor. Obje için aşağıdaki gibi bir kullanım sergiliyorum.

Gördüğünüz üzere root = Tk() diyerek root isminde bir tkinter objesi oluşturdum. Sonrasında root. dediğim zaman bir sürü özelliğe erişebildiğimi göreceksiniz. Bundan sonraki her şey root objesi çevresinde gerçekleşecektir. Bu noktada farklı bir isimde obje veya objeler de oluşturabilirsiniz.

mainloop()

Normal şartlarda bir program çalışırken; hatta şu an kod yazdığımız ortam bile çalışırken bunun sürekli olarak çalışması ve kapanmaması için bir döngü gereklidir. İşte, bizim de tkinter içerisinde bu döngüyü sağlamamıza yarayan fonksiyon mainloop() fonksiyonudur.

root.mainloop() dediğimizde aslında şunu demiş oluyoruz: "root objesini sürekli olarak çalıştır". Programı çalıştırdığım zaman gördüğünüz gibi tatlı, beyaz, güzel bir kutucuk geldi. İşte bu kutucuk içerisine butonlarımızı koyup daha başka işlemler yapacağız.

Eğer mainloop() fonksiyonu bu kutucuğun yani aslında programın çalışmasını sağladığı için yazacağımız her şeyi root = Tk() ile root.mainloop() arasına yazmamız gerekir. O zaman kodlarımızı, bu iki satır arasına yazacağımızı iyi bilelim.

Çalışma alanımızı gördük. O hâlde ilk önce bu alan üzerinde oynama yapmayı kısaca görelim; ileriki zamanlarda daha da detaya gireriz.

root.geometry("")

Örneğin; yukarıdaki kodu çalıştırdığınızda muhtemelen çok küçük bir pencere sizi karşılayacaktır. İşte biz de, varsayılan olarak bu pencerenin boyutunu ayarlayabiliyoruz ve her çalıştırıldığında verdiğimiz değerler doğrultusunda çalışıyor. Görelim.

root objesinin geometry fonksiyonunu çağırdım ve içerisine "400x400" şeklinde bir değer verdim. İçerideki 400 değerleri, bu pencerenin dikey ve yatay boyutlarını belirlememize olanak tanır. Sol taraftaki değer yatay uzunluğu temsil ederken sağ taraftaki değer dikey uzunluğu temsil eder. Bu değerleri değiştirerek size uygun büyüklüğü bulmaya çalışabilirsiniz (örn. 250x380).

root.title("")

title() fonksiyonu sayesinde, bu uygulamanın başlığını değiştirebiliriz.

root.title("Cyber Worm") ifadesi ile uygulamanın ismini/başlığını değiştirmiş oldum.

root.iconbitmap()

Bu fonksiyon, pencerenin logosunu değiştirmemize olanak tanır. Ancak bunun için, .ico uzantılı bir fotoğrafa sahip olmanız gerekir. Bunu da internette aratarak bulabilirsiniz: "png to ico".

root.iconbitmap("") dedikten sonra fonksiyonun içine, sahip olduğunuz .ico uzantılı dosyanın yolunu yazmanız gerekir. Ancak eğer bu fotoğraf çalışma dosyanızla (tk.py) aynı yerde ise sadece ismini yazarak aynı işlemi gerçekleştirebilirsiniz.

Label (Etiket) Oluşturmak

text="", pack(), grid(), padx=, pady=, font=(), bg=, fg=, root.configure(), place(), relx=, rely=, anchor=

Label dediğimiz şey aslında bildiğiniz, basit bir yazıdır. Bunları daha çok, bir şeyleri ifade etmek veya kullanıcıyı bilgilendirmek için kullanıyoruz.

9 ve 10. satırlara dikkat edelim. label1 isimli bir değişken oluşturdum ve karşısına Label() dedim. Bu, root = Tk() demek ile aynı şeydir. Yani aslında burada, bir Label objesi oluşturmuş olduk. Bu sayede Label içerisinde yer alan özelliklere, label1 değişkeninden erişebiliriz.

Sonrasında parantezler içerisine root ifadesini verdik. Yani kodumuz şu hâle dönüştü: label1 = Label(root). Dikkat edelim; değişkenimiz küçük harf ile başlarken ana yapı büyük harfle başlamaktadır.

Bunu yapmamızdaki amaç, oluşturduğumuz bu Label objesinin root isimli tkinter objesine ait olduğunu belirtmektir. Programı çalıştırdığımızda karşımıza çıkan pencere de aslında root isimli objeye aittir. Dolayısıyla eğer başka bir objeniz yoksa oluşturacağınız Label ya da başka nesnelere ana yapınızı (root) belirtmeniz gerekir.

Ana objemizi belirttikten sonra bir virgül koyup devam ediyoruz. Bu noktada text isimli bir değişkenimiz mevcut. text="" içerisine vereceğiniz metin, ekrana verilecek metindir. Bu, print("Hello, Cyber Worm!") demek ile aynı şeydir.

Sonrasında verdiğimiz pack() fonksiyonu ise, oluşturduğumuz Label objesini bir paket hâline getirip yayına sokuyor. Eğer bu ifadeyi vermezseniz hata almazsınız ancak yazınız ekranda gözükmez.

pack() yerine grid() fonksiyonunu da kullanabilirsiniz. Ayrıca grid() çeşitli parametreler alabilen bir fonksiyondur.

10. satırda gördüğünüz üzere label1.grid() dedim ve yazımız, pencerenin sol üst köşesinde belirdi. Peki, biz bu yazıyı daha başka bir yere koyamaz mıyız?

padx ve pady isimli iki parametremiz mevcut. padx parametresi, yataylığı (x ekseni) hedef alırken pady parametresi dikeyliği (y ekseni) hedef alır. padx=130, pady=130 dediğim zaman 400x350 büyüklüğünde olan pencereme göre x eksenine göre 130, y eksenine göre 130 değerini alıyor; bir nevi koordinat.

Bu değerlerin bir kesinliği yoktur; deneye yanıla veya alıştıkça projenize uygun olanı seçebilirsiniz. Buradaki padx ve pady değerlerini direkt olarak Label() içerisine de verebilirsiniz; fark etmez. Bakalım.

Gördüğünüz gibi, bir değişiklik olmadı. Zaten grid() fonksiyonunun asıl amacı bu değil; ona birazdan geleceğiz. Ondan önce, yazdığımız bu yazının rengiyle oynamayı, fontunu değiştirmeyi görelim istiyorum.

Label() içerisinde, en sağda gördüğünüz gibi font belirleyebiliyoruz. font= dedikten sonra bir parantez açıyoruz ve yazı tipini tırnak işaretleri arasına giriyoruz. Yazı büyüklüğünü ise int değer olarak tırnak işaretlerinin dışına giriyoruz. Yani kodumuz şu şekilde olmak zorunda: font=("Arial", 16).

Şimdi, rengini değiştirmeyi öğrenelim.

fg="" şeklinde, renk değişimi sağlayabilirsiniz. Anlamı "foreground" yani "ön plan" şeklindedir. Bu, gördüğünüz üzere metnin yani string ifadenin kendisinin rengini değiştirir. Bir de bg="" ifademiz mevcut ve anlamı "background" yani "arka plan" şeklindedir. Bunu daha çok, butonlarda kullanacağız ancak Label() için de deneyip görebilirsiniz.

Bazı zamanlarda fg veya bg için tam olarak istediğiniz renkleri elde edemeyebilirsiniz. Örneğin siz oraya fg="blue" dersiniz ama tam olarak istediğiniz mavi tonu gelmez. Bunun için hex kodlu renkleri kullanıyoruz. Ne olduğuna bir bakalım.

Gördüğünüz gibi; buradaki her renk aslında altında bulunan koda denk geliyor. Eğer Google'a girip "hex colors" şeklinde bir aratma sağlarsanız karşınıza bir sürü site ve içlerinde bir sürü hex kodlu renkler çıkacaktır. Eğer yukarıdaki görselde en sol alt köşede bulunan rengi isterseniz bg="#abcdef" ya da fg="#abcdef" şeklinde bir kullanım sağlayabilirsiniz.

Gördüğünüz üzere hem hex kodu ile hem de normal yazı ile bunu gerçekleştirebildim.

Bunları öğrendiğimize göre grid() fonksiyonuna geri dönelim. Programı çalıştırdığınızda önünüze çıkan pencere aslına bakarsanız satır ve sütunlara bölünebilir. Ne demek istiyorum? 

3 adet Label() objesi oluşturdum ve pack() yerine grid() kullandım. Bunu yaptığımda ekrana 3 satırdan oluşan bazı yazılar geldi. Ancak bilgisayar dilinde saymaya sıfırdan başladığımızı da biliyorsunuz. Dolayısıyla oradaki "Hey!" ifadesinin sıfırıncı, "Cyber Worm!" ifadesinin birinci ve "I hope you're OK..." ifadesinin ikinci satır olduğunu biliyoruz. Peki, aşağıdaki görsele bakalım.

Son label3 ifademi sağ tarafa taşıdım. Satır olayını artık biliyorsunuz. Burada aynı zamanda sütunlarımız da mevcut ve bunları da sayarken sıfırdan başlıyoruz. Bu noktada grid() bu satır ve sütun olaylarını düzenlememize; istediğimiz satır ve sütuna bir Label() ya da Button() eklememize olanak tanıyor. Nasıl olduğuna bakalım.

row=0 diyorum. Bu, sıfırıncı satır anlamına geliyor. Hemen yanına da column=1 diyorum. Bu ise, birinci kolon/sütun anlamına geliyor. Bunu label3 için yaptığımı düşünürseniz, "I hope you're OK..." ifadesinin sıfırıncı satır, birinci sütuna taşınacağını görebilirsiniz.

Eğer aynı yazıyı birinci satırda yer alan "Cyber Worm!" ifadesinin yanına koymak isteseydim şunu yazardım: label3.grid(row=1, column=1). Aşağı sizin için bir örnek bıraktım. Bu konuyu geçmeden önce dolu dolu pratik yapıp bu yapıya alışmanızı istiyorum.

Eğer isterseniz ayrı bir şekilde label1.grid() demek yerine aşağıdaki gibi bir kullanım sağlayabilirsiniz:

Gördüğünüz üzere label1 = Label(...).grid() diyebiliyoruz.

Dilerseniz, oluşturduğunuz yazıları belli yönlere (doğu, batı, kuzeybatı gibi) yerleştirebilirsiniz. Bunun için place() fonksiyonunu kullanacağız. place() fonksiyonu üç adet parametre alır. Bunlar; relx, rely ve anchor şeklindedir.

relx, yatay uzaklığı ifade ederken rely, dikey uzaklığı ifade eder. Bu noktada bu iki değişken, 0 ile 1 arasında değer almak zorundadır. Bu noktada 0.5 değeri, ekranın tam ortasını ifade edecektir. İsterseniz bunu, hazırladığım bir görselden yararlanarak anlamaya çalışalım.

Yatay alanların x, dikey alanların y olduğunu biliyoruz. Yukarıdaki örnekte beyaz çizgilere ve yanlarındaki değerlere (x=0.5, y=0.5) dikkat edelim.

Biz, örneğin relx=0.5 ve rely=0.5 dediğimiz zaman seçilecek olan nokta şöyle belirleniyor: "İlk önce x'in sıfır değerinden sağa doğru yani yatay olarak yol katediliyor, sonra y'nin sıfır değerinden aşağı doğru yani dikey olarak yol katediliyor. Bu değerler; 0.1, 0.2, 0.3, 0.4 ve 0.5 olarak gidiliyor ve belirttiğiniz nokta gelene kadar bu değerler ilerlemeye devam ediyor". Bir Label() objesinin yerini belirlerken bu şekilde bir yol izliyoruz. Şimdi, anchor yapısına bakalım.

anchor, yönlerle (doğu, batı, kuzeydoğu gibi) çalışır. Ancak bunların kısaltılmış hâllerini İngilizce bir şekilde vermek zorundayız. O zaman yönleri kısaca öğrenelim, sonrasında örneklerle devam edelim.

North (N): Kuzey

South (S): Güney

East (E): Doğu

West (W): Batı

North East (NE): Kuzeydoğu

North West (NW): Kuzeybatı

South East (SE): Güneydoğu

South West (SW): Güneybatı

İşte, anchor kullanırken parantez içerisinde verdiğim değerleri kullanacağız. Bir örnek görelim ve açıklamaya devam edelim.

relx, rely ve anchor kullanabilmemiz için place() fonksiyonuna ihtiyacımız olduğunu söylemiştim. place() fonksiyonunu, pack() ve grid() gibi; LABEL(...).place(...) şeklinde veya label1.place(...) şeklinde kullanıyoruz.

anchor için söz etmediğim tek parametre CENTER parametresidir. relx ve rely değerlerini 0.5 olarak ayarlayıp anchor'a da CENTER değerini verirseniz verdiğiniz yazıyı ortalayacaktır. Şimdi, yönler hakkında örnekler yapalım.

Yukarıdaki görseli iyice inceleyin lütfen. relx=0.2, rely=0.2, anchor=NW dediğim zaman kuzeybatı içerisinde 0.2 birimlik hareket gerçekleşecektir. Bu sefer de güneydoğu deneyelim.

Sizce neden böyle olmuş olabilir? Dikkat ederseniz ben, relx=0.38, rely=0.38 şeklinde değerler verdim. Bu noktada x ve y değerleri, pencerenin solunda kalan değerler için hesaplama yaptığından dolayı böyle bir çıktı aldım. Hâlbuki örneğin 0.78 şeklinde bir değer verseydim pencerenin sağ tarafında işlem yapılacaktı. Söz konusu alanları anlamadıysanız; 0.5 noktası orta nokta idi. Eğer 0.5'ten küçük bir değer verirseniz işleminiz sol tarafta kalan alanda yer alacaktır. Sağ tarafta işlem yapılsın istiyorsanız 0.5'ten büyük değerler vermeniz gerekecektir. Doğrusunu yapalım.

Sonuç gayet güzel duruyor. Peki, sizce SW yani güneybatı nasıl işleme alınır?

Bu noktada x tarafı için sadece ufak bir boşluk bıraktım, y tarafı için ise çok aşağı indim. Lütfen siz de kendi pratiklerinizi yapın.

Button (Buton) Oluşturmak

width=, height=, side=""

Şimdi, hem buton oluşturmayı hem de butona tıklandığında gerçekleştirilecek bazı işlevleri tanımlamayı göreceğiz. Buton tanımlamak için Label() için yaptığımız kullanımın aynısını sağlamamız lazım. Yani örneğin;

buton1 = Button() şeklinde bir kullanım sağlıyoruz. Bakalım.

Gördüğünüz gibi, temel yapı ve aldığı parametreler aynı. Yalnızca burada button1 = Button() diyerek bir buton objesi oluşturuyoruz. Sonrasında bunu pack() ile paketliyor ve ekrana veriyoruz. Bir de grid() kullanmayı deneyelim.

grid() fonksiyonunu da başarılı bir şekilde kullanabildiğimizi görüyorsunuz. Burada pack() yapmamamızın sebebi, önceki kısımlardan hatırlayacağınız üzere grid() kullanıyor olmamızdan kaynaklı.

Butonlarda padx ve pady kullanmak yerine width ve height değişkenlerini kullanabilirsiniz. Zaten bunlar, daha çok butonlarda kullanılır. width, butonun genişliğini ifade ederken height, yüksekliğini ifade eder. Bakalım.

Gördüğünüz üzere benzer sonuçlar aldık.

Eğer butonunuz için belirlediğiniz; sağ, sol, aşağı, yukarı şeklinde özel bir alan varsa bunu yapabilirsiniz. Bunun için pack() fonksiyonunu kullanacağız. pack() fonksiyonu, side isimli bir değişken alır ve bu değişkene verdiğiniz değer sayesinde az önce belirttiğim konumları sağlayabilirsiniz.

Buradaki kelimeleri İngilizce bir şekilde yazmanız gerekir. Dolayısıyla sağ, sol, alt, üst gibi kelimelerin İngilizcesini bilmeniz gerekir.

Peki, butonlar hakkındaki ilk örneklerimizde butonların çok bitişik olduğunu fark etmişsinizdir. Bunu nasıl engelleriz? Yani aralarına biraz boşluk bırakmak istesek bunu yapabilir miyiz?

Label() konusunu işlerken öğrendiğimiz relx ve rely değerlerini kullanarak bunu sağlayabilirsiniz. Ancak, vereceğiniz değerlerin en iyisini deneye deneye bulmanız gerekecektir. Dikkat ederseniz rely kısımları sabit çünkü butonları yukarıdan hafif bir şekilde ayırmak istedim. Ancak relx değerleri birbirinden gerçekten farklı durumda. Butonların boyutlarını düşünecek olursanız bu gayet normaldir; iç içe geçecekleri için butonları iyice kaydırmanız, aradaki hassas çizgiyi ayarlamanız gerekir.

Eğer isterseniz butonların tıklanamamasını sağlayabilirsiniz. Bunu, state değişkeniyle yapıyoruz. Eğer state=DISABLED derseniz buton tıklanamaz hâle gelecektir. Eğer state=ACTIVE derseniz buton tekrar tıklanabilir duruma gelir. Zaten varsayılan değerimiz state=ACTIVE şeklindedir.

Gördüğünüz üzere, butonlar işlevsiz hâle geldi. Peki, bir butona tıkladıktan sonra belli bir iş yaptırmak istersek bunu nasıl yapabiliriz?

Bunun için bildiğimiz def yapısıyla bir fonksiyon oluşturup bunu butonun içerisine yerleştiriyoruz. Nasıl yapıldığına bakalım.

def button1_click() şeklinde bir fonksiyon tanımladım ve içerisine, l isminde bir Label() oluşturdum; nasıl olduğunu biliyorsunuz. Bu fonksiyonu, button1'e tıklanması durumunda çalışması için ayarlamamız lazım. Şimdi, bunu yapmaya çalışalım.

Fonksiyonu tanımladıktan sonra Button() içerisine girip command anahtar kelimesini kullanıyorum. Hemen sonrasında bunu, fonksiyonuma eşitliyorum. Sonuçta şöyle bir yapı kurmanız gerekiyor:

command=<fonksiyon_adı> yani

command=button1_click şeklinde.

Bu noktada fonksiyon içerisine istediğiniz özellikleri ekleyebilirsiniz. Örneğin tıklanması durumunda bir web sitesi açmasını isteyebilirsiniz.

Label() konusunu konuşurken bg ve fg şeklinde iki özelliğimiz olduğundan söz etmiştim. Aynı özellikleri, butonların renkleriyle oynamak için de kullanabilirsiniz. Hemen görelim.

Butonların rengini değiştirdik. Bu noktada çok detay vermeyeceğim çünkü renk ve font değiştirme işlemlerini Label() konusunda gördük. Renkler için hex kodlarını da kullanabilirsiniz. Ayrıca şu an telefondan okuyorsanız ekranı yakınlaştırabilir, inceleyebilirsiniz.

Hatırlarsanız, pencere ile ilgili düzenlemeler yaptığımızda root. gibi ifadeler kullanıp pencereyle ilgili özelliklere erişebiliyorduk; örneğin, root.geometry("500x500"). Butonları öğrendiğimize göre artık "Çıkış" butonu da yapabiliriz.

Direkt olarak command=root.quit diyebiliyor, ve butona tıkladığımız zaman programın sonlanmasını sağlayabiliyoruz.

Kullanıcıdan Girdi Almak (Entry())

Kullanıcıdan girdi de alabiliyoruz ve yine bir obje yaratmamız lazım. Burada kullanacağımız şey, 'Entry()' olacak. Önce nasıl tanımladığımıza bakalım.

Odaklanmanızı istediğim nokta; getEntry = Entry(root). Gördüğünüz gibi diğer yapılarla aynı şekilde kullanabiliyoruz. C# programlama biliyorsanız bunu, oradaki textbox'lara benzetebilirsiniz. Entry() kullandığınızda azı yazmanız için bir alan yaratılır ve oraya veri girişi sağlarsınız.

Bunun da boyutunu x ekseni cinsinden ayarlayabiliyoruz.

Bunu, width= ile sağlıyoruz. Duruma göre istediğiniz boyutu sağlayabilirsiniz.

Eğer isterseniz, bu girdi alanını dolgularla kaplayabilir ve bunun bir girdi alanı olduğunu daha da belli edebilirsiniz. Bakalım.

Bunu, border= ifadesiyle sağlıyoruz. Girdi alanına baktığınızda dolgulu bir hâle geldiğini görürsünüz. Elbette ben, siz daha net görün diye bu kadar kalın bir dolgu seçtim, siz istediğiniz gibi ayarlayabilirsiniz.

Kullanıcının girdiği veriyi tutabilirsiniz. Bunu, get() ile sağlıyoruz.

getTheEntry = getEntry.get() dedik. Burada aslında şunu demiş oluyoruz: "getEntry değişkeniyle aldığın girdiyi, getTheEntry değişkeninde sakla (get())". Eğer bu değişken get() sayesinde girdileri saklayabiliyorsa ben girilen bu girdi ile istediğimi yapabilirim. Mesela bununla alakalı ufak bir örnek yapalım.

Örnekte yaptığım konumlandırma işlemlerini anlatmayacağım, biliyorsunuz.

getEntry = Entry(...).place(...) satırını bozuyorum ve place() olan kısmı aşağı alıyorum. Eğer bunu yapmazsanız get() çalışmayacaktır. O yüzden bir alt satıra getEntry.place(...) şeklinde bir kod yazdım.

Sonrasında submitButton() isimli bir fonksiyon tanımladım ve bu fonksiyonun görevi, tetiklendiği zaman bir Label() oluşturmak, Label() içerisindeki yazıyı da kullanıcıdan almaktır. text=getEntry.get() dememin sebebi bu; yazı, kullanıcıdan alınacak ve ekrana bastırılacak.

Son olarak aşağıda submit isimli bir buton oluşturdum ve az önce oluşturduğum fonksiyonu buraya aktardım. Artık submit isimli butona tıklandığında submitButton fonksiyonu çalışacaktır. Önce çıktımıza bakalım sonra kendi incelemenizi ve denemelerinizi yapabilirsiniz.

Gördüğünüz gibi girdi alanına Cyber Worm yazıp Submit butonuna tıkladım; alt tarafta yazdığım şeyin aynısı ortaya çıktı.

İsterseniz küçük bir tarayıcı da yapabilirsiniz. Örneğin girdi alanına bir URL eklersiniz ve oraya gitmeye çalışırsınız. Bunu, tkinter blogundan sonra bir uygulama olarak yapacağım. Uygulama gelene kadar aynısını siz yapmayı deneyebilirsiniz.

Çerçeveleme İşlemleri (LabelFrame())

Birbiriyle alakalı yazıları, butonları veya daha başka şeyleri bir çerçeve içerisine alabiliyoruz. Örneğin bir marketin ürünlerini listeleyecekseniz bunları gruplandırmanız gerekir; çikolatalar, kekler, asitli içecekler, asitsiz içecekler vb.). LabelFrame() yapısını kullanarak bunları gruplandırabilirsiniz. Bir örnek yapalım.

10. satırda frameSite = LabelFrame() diyerek çerçevemi hazırlıyorum. Referans olarak root objesini veriyorum ve text= kısmına bir başlık koyuyorum.

13. satırda ise buttonSite = Button() şeklinde bir buton hazırlıyorum. Bu sefer referans olarak root değil, frameSite objesini veriyorum. Şimdiye kadar oluşturduğumuz objelerde hep root objesini referans verdik. Ancak şimdi, oluşturduğumuz bu buton, çerçevenin içinde olacağı için çerçevenin kendisini referans olarak veriyoruz. Çerçeve zaten root referansına sahip olduğu için buton da dolaylı yoldan root referansına sahip olacaktır. Yani herhangi bir sorun olmadan çalışabilecektir.

Çıktı kısmına baktığınızda gayet güzel görünen bir çerçevemiz ve çerçevenin içerisinde bir butonumuz olduğunu görüyorsunuz. Peki, ikinci bir buton koymak istersek ne olur?

Yapacağımız şey tamamen aynı, sadece içerisindeki yazıyı değiştirdik. Bu noktada dilerseniz çerçevenin ve butonların rengiyle, konumlarıyla oynayabilirsiniz. Bir çerçeve içindeki butonların daha iyi gözükmesi için arasını açabilirsiniz. Bunları daha önceden öğrendik, lütfen deneyin.

Kullanıcıya Seçenek Sunmak (Radiobutton())

Herhangi bir sitede ya da bir ankette görmüşsünüzdür; size bir soru sorarlar ve alt alta verilen seçeneklerden birini seçmeniz istenir. Yani daha çok Evli-Bekâr, Kadın-Erkek şeklinde gelen bu seçeneklerle karşılaşmışsınızdır. İşte, tkinter ile bunu yapmayı öğreneceğiz ve bunu yaparken Radiobutton() kullanacağız.

Seçenekleri, yukarıda gördüğünüz gibi belirliyoruz. Radiobutton() dedikten sonra root ve text kısımlarını kendimiz belirliyoruz. Bu noktada value= değeri, seçeneklerin sırasını ifade eder. Ancak dikkat edelim, seçeneklerin yazılma sırasını ifade etmez, seçeneklerin sırasını ifade eder. Bunu index'leme gibi düşünebilirsiniz. Her seçeneğe bir value= değeri veriyorsunuz ve başka bir yerde bu seçeneği kontrol etmek istediğinizde bunu, bu değer ile sağlıyorsunuz.

Bir seçenek daha ekleyelim ve varsayılan seçeneği belirlemeyi öğrenelim.

Biraz önce value=1 gibi tanımlamalar yaptık. Bu noktada burası integer yani int bir değerdir. Eğer value="1" şeklinde yapsaydık bu bir string değer olurdu; biliyorsunuz. İşte tam olarak bu yüzden 10. satırda default = IntVar() ifadesi mevcut. Eğer value değerine string bir değer verseydiniz default = StringVar() şeklinde yazmanız gerekirdi. 

value=1 şeklindeki tanımlamaların solunda kalan variable=default ifadesinde ise bir değişken veriyoruz. Biraz önce bu değişkeni default = IntVar() olarak tanımladık. Bunun anlamı şudur: "Değişkenlerim IntVar veri tipinde olacak (default = IntVar() ve variable=default). Sana söylediğim Int değer ise value=<sayi> değeridir."

Umarım anlatabilmişimdir; pratik yaptığınızda daha net anlayacaksınızdır. 11. satırda bulunan kod ise, program çalıştığında otomatik olarak seçili şekilde gelmesini istediğimiz değeri ifade ediyor. default = IntVar() dedik ve default.set("") dedik. Yani değeri int olan değişkenlerden birini seçeceğimizi söylemiş olduk ve tırnak işaretleri arasına verdiğimiz 3 değeri ise, üçüncü değişkeni seçtiğimiz anlamına gelmiş oldu.

Şimdi, buradaki mantığı daha iyi anlayabileceğiniz bir örnek yapalım. Yapacağımız örnekte, seçtiğimiz seçeneğin değeri (1, 2 veya 3) ekrana yazdırılacak. Bakalım.

def click(value): şeklinde bir fonksiyon oluşturdum ve içerisine bir adet Label() yaratılması emrini verdim. Bu Label() objesinin text özelliği ise, fonksiyona verdiğim argümanla bağdaştırılarak ekrana verilecektir.

command=lambda: click(default.get()) yapısına bakalım. lambda fonksiyonunun geçici fonksiyon olduğunu önceki bloglardan biliyorsunuz. Bu noktada ben, click(default.get()) diyerek az önce bahsettiğim Label() objesinin değerine erişiyorum. Örneğin click(default.get()) = 1 ya da click(default.get()) = 2 şeklinde. Burada kullandığım lambda ise, bunun dinamik olarak değişmesini ve fonksiyona atanmasını sağlıyor. Örneğin üçüncü değere tıkladığımda lambda yapısı sayesinde Label() objesinin değeri 3 olacak. Ancak ikinci seçeneğe tıkladığımda değerim değişip 2 olacak. İşte, bunun temel sebebi lambda fonksiyonunun geçici değer alabilme özelliğidir.

Bu kısımları anlayabilirsiniz ama uygulamadan öğrenemeyebilirsiniz. Şimdi, çıktımıza bir bakalım.

Sırasıyla; Belirtmek istemiyorum, Erkek ve Kadın seçeneklerini bir defa seçtim ve ekrana sırasıyla 3, 2 ve 1 değerleri yazdırıldı.

Başka bir örnek yapalım istiyorum. 4 adet kripto paranın ismini ve fiyatını tutan bir liste hazırlayalım ve tıkladığımız seçenek neyse onun fiyatı ekrana gelsin. Bunun için ilk önce status = [] şeklinde bir liste hazırlıyorum ve içerisine 4 adet Tuple ekliyorum.

Gördüğünüz gibi; status isimli listenin dört Tuple elemanı, dört Tuple elemanının her birinin de iki string elemanı mevcut. Sonrasında klasik fonksiyonumuzu açıyorum ve oluşturduğum Label() objesinin text değerini value olarak kullanıcıdan alacağımı söylüyorum.

Şimdi, bir set yani varsayılan değer ayarlamaya çalışalım.

Bunun için crypto = StringVar() diyorum çünkü değerlerimin veri tipi string. Altına da crypto.set() diyorum ve içerisine Bitcoin ifadesini veriyorum. Bu sayede Bitcoin varsayılan değer olacak.

Şimdi, bu elemanları otomatik bir şekilde teker teker kontrol etmemiz lazım. Bunun için birden fazla değer alan bir for döngüsü açıyorum; for coin, price in status:

Bu döngü, status listesindeki kripto paraların ismini (coin) ve fiyatını (price) dolaşacak.

Döngünün içerisine de bir Radiobutton() objesi ekliyorum ve içerisine bildiğiniz parametreleri koyuyorum. Diğer ifadelere bakalım.

text=coin ifadesi ile, text="Bitcoin" ya da text="Rose" demek yerine bunu otomatize ediyorum ve her elemanı tek tek text= değişkenine veriyorum.

Sonrasında gelen variable=crypto ifadesinde ise bu değerlerin birer string olduklarını belirtiyorum. Çünkü biraz önce yukarıda crypto=StringVar() dedim.

value=price ifadesinin mantığı, text=coin mantığıyla aynıdır. Otomatik olarak listedeki bütün price değerlerini sırayla buraya topluyorum.

for döngümüz var, otomatize de ettik. Ancak yetmez. Çünkü bu değerlerin sürekli olarak değişmesi ve crypto değişkenine atanması gerekiyor. Bunun için command=lambda: click(crypto.get()) ifadesini veriyorum. Bu sayede seçtiğim her değer click() fonksiyonundaki Label() objesine yansıyacaktır.

Kodu çalıştırıp sonuçları görelim.

Sırasıyla; Bitcoin, Polkadot ve Rose seçeneklerine tıkladım ve fiyatlar geldi.

Kullanıcıya Mesaj Göstermek (Messagebox())

Normal bir şekilde bilgisayar kullandığınızda karşınıza çıkan uyarı, bilgilendirme veya hata mesajlarını bilirsiniz. Bu kısımda tkinter ile bunları yapmayı öğreneceğiz. Her şeyden önce tkinter modülünün messagebox sınıfını import etmemiz gerekiyor. Sınıf kavramını henüz bu seride görmedik. Şu an çok da önemli değil, bir özellik import ettiğimizi düşünebilirsiniz.

İkinci satırda import işlemini gerçekleştirdim: from tkinter import messagebox

messagebox.showinfo() dedim ve ona iki parametre verdim. Bunlardan biri başlık, diğeri ise içeriktir; okların renklerini takip edin. Sonrasında bir buton oluşturdum ve command= değeri olarak bu fonksiyonu verdim. Butona tıkladığımızda karşımıza bir mesajın geldiğini görürsünüz. Ayrıca bunu denediğiniz zaman, cihazınızdaki bildirim sesinin de çalışacağını göreceksinizdir. Hatta bu ses, birazdan vereceğimiz mesajın türüne göre değişecektir.

showwarning() fonksiyonunu çağırdım ve ona da iki tane parametre verdim. Konsept aynı. Değişen şeyler çıkan ses ve bildirimin içindeki ikon. Az önce mavi yuvarlak içerisinde 'i' sembolü varken şimdi sarı bir üçgen içerisinde ! işareti mevcut. Bu da, verdiğimiz mesajın bir uyarı mesajı olduğunu gösterir.

Şimdi de hata mesajı gösterelim.

Bu sefer showerror() fonksiyonunu kullandım ve bir hata mesajı vermiş oldum.

Şimdi, kullanıcıya bir pencere ile soru soralım.

Bu defa askquestion() fonksiyonunu kullandım. Normal şartlarda henüz bir şey tanımlamadığımız için Yes veya No butonlarına basarsanız herhangi bir geri dönüş alamayacaksınız ve pencere kapanacaktır ama arka planda dönen bazı değerler olmalı. Dolayısıyla bunu reply isimli bir değişkene atadım ve Yes veya No butonlarına tıkladığım hâlde döndürülecek sonucu bu Label() objesine, text=reply şeklinde atadım; ekrana yazdıracağım.

Sırasıyla Yes ve No butonlarına tıkladım. Dönen sonuçlar ise yes ve no oldu. O zaman biz, dönen bu sonuçlardan yola çıkarak çeşitli koşullar oluşturabilir miyiz? Örneğin; "kullanıcı Yes butonuna basarsa şunu yap, No butonuna basarsa bunu yap" gibi. Bakalım.

Gördüğünüz gibi programı çalıştırdım, Info butonuna tıkladım ve karşıma gelen pencerede Yes butonuna tıkladım. Koşulumuz doğru bir şekilde çalıştı. Bence çok yararlı bir kontrol.

Şimdi, askokcancel() fonksiyonunu kullanalım. Buradaki seçenekler de OK veya Cancel olacak.

Peki, burada OK ve Cancel butonları arka planda nasıl bir değer döndürüyor olabilir?

OK butonu 1, Cancel butonu 0 şeklinde bir değer döndürüyor. O zaman bunları da kontrol edebiliriz diye düşünüyorum.

Gördüğünüz gibi bunun da kontrolünü sağlayabildik. Ancak burada kontrol sağlarken vereceğiniz değeri int olarak vermeniz gerekir. Zaten 1 ve 0'ın bilgisayar camiasında ne anlama geldiğini biliyorsunuz.

askyesno() fonksiyonu da Yes ve No olmak üzere iki seçenek sunar. Döndürülen değerlere de bakalım.

Yes butonu 1, No butonu 0 değerini döndürüyor. O zaman bunları da kontrol edebiliriz ama ben göstermeyeceğim, kendiniz yapmayı deneyin.

Gördüğünüz üzere çeşit çeşit pop-up'lar çıkarabiliyoruz. Hangisini kullanacağınız, amacınıza göre değişkenlik gösterecektir; bir geliştirici olarak karar tamamen sizde.

Yeni Bir Pencere Oluşturmak (Toplevel())

Hâlihazırda çalıştığınız pencerenin yanında başka bir pencere daha açabilirsiniz. Hatta birkaç tane de açabilirsiniz; size bağlı. Önce bunun nasıl olduğuna bakalım sonra biraz daha bunun hakkında konuşalım.

Biraz önceden kalma bir butonum var ve bu, mavi tonlarındaki pencerede yani ana penceremde duruyor. Ona bastığım zaman yeni bir pencere oluşuyor.

def createWindow(): fonksiyonunun içine newWindow = Toplevel() şeklinde bir ifade bıraktım. Toplevel() yeni bir pencere açmamıza olanak tanıyor. Sağ taraftaki beyaz pencere, yeni açılan penceredir ve dikkat ederseniz sadece başlık değişmemiş; ikon dahil, geri kalan her şey değişmiş.

Normal şartlarda root.title("Cyber Worm") şeklinde kullanımlar sağlayabiliyoruz. Peki, aynı şeyi yeni açılan pencere için newWindow.title() şeklinde yapabilir miyiz? Tabii ki, yapabiliriz. Sonuç olarak bu artık bir obje ve yeni bir pencere. O zaman ben de özellikleriyle oynayabilirim. Bakalım.

Gördüğünüz gibi ana penceremiz için yaptıklarımızın hepsini açtığımız yeni pencerelere de yapabiliyoruz. Burada özellikle 14. satıra, Label() objesi tanımladığımız kısma bakmanızı istiyorum. Normalde şu şekilde bir kullanım yaparız:

info = Label(root, ...) yani referans olarak root objesini veririz. Ancak yeni pencere için root değil, yeni pencerenin ismini veriyoruz. Bunu önceki kısımlardan da hatırlarsınız, objeler birbirine bağlansa da çıkış noktası hep root objesi olur. Dolayısıyla her pencere için Label() gibi özel şeyler tanımlarken verdiğimiz referans, oluşturduğumuz pencere olmalıdır.

Kullanıcıdan Dosya Seçmesini İstemek (filedialog)

Başlıkta da gördüğünüz üzere kullanıcıdan, cihazından herhangi dosya seçmesini isteyebiliyoruz. Bunun için yine bir sınıf import etmemiz lazım. Bunu, from tkinter import filedialog şeklinde yapıyoruz.

Sınıfı import ettikten sonra fileName isimli bir değişken oluşturuyorum ve karşısına şunu diyorum: "filedialog.askopenfilename()". Bu fonksiyon sayesinde dosya gezgini otomatik olarak açılacak ve istediğiniz dosyayı seçebileceksiniz. Yeşil yazılara dikkat edelim.

Sonrasında dosyanın başarılı bir şekilde seçildiğini görmek adına bunu bir Label() objesi ile yazdırıyorum. Şimdi, programı çalıştırıp ne olacağını görelim.

Butona tıkladığımda karşıma direkt olarak dosya gezgini açıldı. Bu noktada istediğiniz lokasyondan istediğiniz dosyayı seçebilirsiniz. Örneğin ben, sitemizin logolarından biri olan, D:/ altındaki logo.png dosyasını seçmek istiyorum.

Gördüğünüz üzere seçim işlemi başarılı oldu ve seçtiğimiz dosyanın lokasyonunu yazdırdı. Elbette, bu noktada her şey size kalmıştır. Bilgi ve tecrübenize bağlı olarak örneğin, seçtiğiniz veya seçtirdiğiniz dosyanın zararlı yazılım içerip içermediğini kontrol edebilirsiniz. Ben sadece kullanıcıya dosya nasıl seçtirilir, onu gösterdim.

DUYURU: Bu blog içerisinde öğrendiklerinizle ortalama bir uygulama geliştirebilirsiniz. Blog içerisinde tam 68 adet ekran görüntüsü mevcut ve blogun büyüklüğü 41 sayfalık bir Word dosyasına tekâbül ediyor. Yani bu blog gerçekten uzun ve yorucu oldu; şimdilik bu bloga ara veriyorum. Yeni bilgiler ekleyerek bu blogu güncelleyebilirim. Duyuruları kaçırmamak adına Instagram ve Telegram hesaplarımızı takip edebilirsiniz.


Yayınlanma Tarihi: 2022-12-09 00:57:30

Son Düzenleme Tarihi: 2022-12-12 22:37:27