Merhaba , karantina günlerinde Rails için yazılar yazarken internette gözüme takılan bir şey çok ilgimi çekti. PySimpleGUI adında bir Python GUI kütüphanesi. Aynı Ruby'nin Shoes kütüphanesi gibi kolayca GUI uygulaması yapılabiliyor. Hatta bir konsol uygulamasında bile kullanıcıya soru sormak, dosya seçtirmek vs işler için kolayca kullanılabilir.
Hadi beraber kurcalayalım. İlk önce kurulum tabi ki.
pip install pysimplegui
veya
pip3 install pysimplegui
Reçete-1A Tek Atımlık Pencere (en basit tasarım)
Bu pencereyi sadece bir işlem yapıp kapatacağınız zamanlar kullanacağınız en genel patern (Soru sormak, bilgilendirmek vs). Bu uygulamanın kodu şöyle:
import PySimpleGUI as sg
layout = [[sg.Text("Tek atımlık pencerem.")],
[sg.InputText()],
[sg.Submit(), sg.Cancel()]]
window = sg.Window("Pencere Etiketi", layout)
event, values = window.read()
window.close()
text_input = values[0]
sg.popup(text_input, " girdiniz")
Bir pencereyi okuduğumuzda (read metodu), bize bir tuple döner. İlk eleman olayı içerir, o yüzden event değişkenine aldık. İkinci elemansa kullanıcı tarafından giriş yapılabilen elemanların değerlerini içeren bir dictionary'dir, bunu da values değişkenine aldık.
event okuma işleminden çıkışa sebep olan olaydır. Bir butona basılması, listeden bir eleman seçilmesi vs. Ayrıca pencere "X" tıklanarak kapatılırsa event değeri None olur.
values tüm input stili elemanların değerlerini içeren bir dictionary'dir. Elemanların her birinin key özelliğine bağlanarak değerler kaydedilir. Eğer elemanda key özelliği tanımlanmamışsa sırayla 0'dan başlayarak otomatik key'ler sayılar şeklinde verilir. Yukarıda da layout içinde InputText elemanına bir key özelliği tanımlamadığımız için otomatik verilen sayı ile değerini alıyoruz. Yegane Input elemanı olan InputText elemanının değeri values[0] olarak kaydedilmiş olacaktır.
Otomatik üretilen key yerine kendimiz bir key tanımlamak ve kodu daha okunabilir yapmak istersek şöyle yazmalıyız.
import PySimpleGUI as sg
layout = [[sg.Text("Tek atımlık pencerem.")],
[sg.InputText(key="-IN-")],
[sg.Submit(), sg.Cancel()]]
window = sg.Window("Pencere Etiketi", layout)
event, values = window.read()
window.close()
text_input = values["-IN-"]
sg.popup(text_input, " girdiniz")
Reçete-1B Tek Atımlık Pencere (tek satırla)
Aşağıdaki gibi tek satırla da otomatik kapanan bir pencere tanımlayabiliriz. Özellikle başka bir uygulama içersinde kullanıcıdan veri almak ya da bildiri yapmak için kullanılabilir.
import PySimpleGUI as sg
event, values = sg.Window("Login Penceresi",
[[sg.T("Login ID giriniz"), sg.In(key="-ID-")],
[sg.B("Tamam"), sg.B("İptal")]]).read(close=True)
login_id = values["-ID-"]
Burada farklı olan şey close=True bildirimi. Bu sayede read metodu değer dönmeden hemen önce pencere kapatılıyor. Tabii nasıl tek satır derseniz, yerleşim açık okunabilsin diye tek satır kodu 3 satıra dağıttık.
Bir de Button yerine B , Text yerine T , InputText yerine In yazdık. Bunlar bu eleman isimlerinin kısaltmaları. Özellikle karmaşık yerleşimlerde tüm yerleşimi tek bir ekranda görebilmek için bu kısaltmalar çok faydalı olur. Zaten çok az kod yazarak GUI oluşturuyoruz, bir de bu kısaltmalar var. Demek tasarlayan kişi benim gibi tembel birisiymiş.
Reçete-2A Kalıcı Pencere (döngüyle defalarca okuma yapmak)
Bu kod bir pencere açıyor ve kullanıcının girdiği değerleri etkileşim değerleri ile birlikte konsola yazıyor.
import PySimpleGUI as sg
sg.theme("DarkAmber") # Kullanıcıların ilgisini taze tut
layout = [[sg.Text("Kalıcı Pencere")],
[sg.Input(key="-IN-")],
[sg.Button("Oku"), sg.Exit()]]
window = sg.Window("Açık kalan pencere", layout)
while True: # Olaylar döngüsü
event, values = window.read()
print(event, values)
if event in (None, "Exit"):
break
window.close()
Bu uygulamadan çıkan bir örnek şöyle olabilir
PS E:\ujk_common\prg\python\PySimpleGui\blog_apps> python PersistentWindow.py
Oku {'-IN-': 'buraya değer girdim'}
Oku {'-IN-': 'daha da yazdım'}
Exit {'-IN-': 'Artık çıkıyorum Exit butona basarım'}
PS E:\ujk_common\prg\python\PySimpleGui\blog_apps>
Bu programda event tıklanan butonların isimleri oluyor. Arkasından values değişkeni basılıyor. Bu örnekte değeri olan tek eleman sg.Input elemanı. Görüldüğü gibi Input elemanını tanımlarken verdiğimiz key değeri sonuç dictionary'de karşımıza çıkıyor. Eğer pencereyi "X" tıklayarak kapatırsak şöyle bir çıktı alırız:
None {'-IN-': None}
event değişkenine gelen bu None değeri aslında pencerenin kullanıcı tarafından kapatıldığını anlamak için çok yararlıdır.
Reçete-2B Kalıcı Pencere (okunan değeri pencere üzerinde yazmak)
Bu daha gerçekçi bir uygulama , kullanıcının girdiği değer pencere içinde kullanılıyor. Biraz daha karışık bir program.
Programımızın kodu şöyle:
PersistentWindow2.py
import PySimpleGUI as sg
sg.theme("BluePurple")
layout = [[sg.Text("Girdiğiniz yazı burada görülecek : "), sg.Text(size=(20,1), key="-OUTPUT-")],
[sg.Input(key="-IN-")],
[sg.Button("Göster"), sg.Button("Çıkış")]]
window = sg.Window("Reçete 2B", layout)
while True: # olaylar döngüsü
event, values = window.read()
print(event, values)
if event in (None, "Çıkış"):
break
if event == "Göster":
window["-OUTPUT-"].update(values["-IN-"])
window.close()
Pencerede bir elemanın içeriğini değiştirmek için onun update() metodunu çağırırız. Yukarıdaki kodda window["-OUTPUT-"] ile key değeri "-OUTPUT-" olan eleman seçiliyor. Sonra key değeri "-IN-" olan elemanın içeriği update() metodu ile "-OUTPUT-" elemanına yazılıyor.
Pencereden çıkış
Yukarıdaki programda
if event in (None, "Çıkış"):
break
satırları ile kullanıcıya bir çıkış yolu sağlıyoruz. Bunu sağlamazsak kullanıcı "Görev Yöneticisine falan başvuracaktır. Her zaman penceremizden ve uygulamamızdan kontrolümüz altında bir çıkış sağlamalıyız.
window.close() metodu ile pencereleri işimiz bittiğinde mutlaka yok etmeliyiz. Bazen pencerenin ekrandan yok olması hafızadan da yok olması anlamına gelmez.
Kodlama Alışkanlıkları
Bazı kodlama düzenlerini alışkanlık haline getirmemiz iyi olacak. Yukarıdaki programları hiç bir şey değiştirmeden kopyalayıp yapıştırırsak, PySimpleGUI programlarını tanıyan biri programın ne yaptığını anlamakta zorluk çekmeyecektir.
Genel olarak şu alışkanlıklar tavsiye edilir:
- import PySimpleGUI as sg
- Pencerenize window adını verin
- Okuma işleminden dönen değerleri event ve values değişkenlerine koyun
- Yerleşiminize layout adını verin
- Elemanları seçerken window[key] yapısını kullanın
- Key değerleri için "-KEY-" formatına sadık kalın
Tabi ki bunlar tavsiye, hiç birine uymak zorunda değilsiniz. Ancak bunlara uyarsanız başkaları daha kolay programınızı anlayacaktır.
Kodlama İpuçları
Bu yazıları yazan PySimpleGUI uzmanı birkaç tavsiyede daha bulunmuş:
- Her şart altında basit düşüncede kalmaya çalışın
- Dökümanları okuyun ve araştırın (http://www.PySimpleGUI.org)
- Yukarıda anlatılan alışkanlıkları uygulayın
- Yerleşimleri kompakt yazın
- Elemanlarda hep aynı kodları tekrarlıyorsanız "kullanıcı elemanları" tanımlayın (eleman geri dönen fonksiyonlar)
- Diğer GUI kütüphanelerinin yapılarını taklit etmeyin, PySimpleGUI yapısını kullanın
- Makul zaman aşımı değerleri kullanın (mümkün olduğunca sıfırdan büyük olmayan değerler ... iyi bir CPU dostu olun)
- Bir thread'dan herhangi bir PySimpleGUI çağrısı yapmaya çalışmayın
- Çıkmadan önce pencereyi kapatın
- Doğrusal olay döngüleri yazın
- Element.get terine values dictionary kullanın
- Daha fazla ipuçaları ve teknikler için Demo Programları ziyaret edin
Bir iki tanesini açalım
Kompakt yerleşimler oluşturun
Yerleşim satırlarının (layout) tek ekranda tamamen görünmesi için çaba sarfedin. Her satıra bütün parametreleri yazmayın, tonlarca boşluk bırakmayın.
Çok fazla eleman varsa kısaltılmış isimleri kullanın (örn. sg.Button yerine sg.B yazarak 5 karakter kazanırsınız)
Burada amaç tüm yerleşimi yukarı-aşağı kaymadan görebilmek
PySimpleGUI yapılarını kullanın
PySimpleGUI programları diğer OOP Python GUI'ler ile benzer yapıda değildir. Onu OOP tasarıma zorlamak bir sürü self. kelimesinden başka birşey kazandırmayacaktır. Çok daha karmaşık olacak ve kafa karıştıracaktır.
Tabii ki geri kalan kısımı OOP yazabilirsiniz.
Şunu belirtelim ki "App" benzeri bir konsept , bitmeyen olay döngüleri ve caal-back fonksiyonları yoktur. PySimpleGUI diğer PyQT veta Tkinter'den farklıdır. Eğer başlangıç olarak Window adında bir alt sınıf yapmaya çalışıyorsanız bir şeyler ters gidiyordur.
Temalar - Pencere güzelliği
Bir tek satır ile pencerelerin renklerini temalar yardımıyla değiştiririz.
Tkinter için en çok söylenen şey şey çirkinliğidir. Bunun yerine PySimpleGUI temalarını kullanarak sorunu çözebiliriz.
sg.theme('Dark Green 5')
theme() metodu çağırılması ile tüm yazı rengi , arkaplan rengi , buton rengi , input rengi gibi 13 parametre birden değişir.
Default tema "DarkBlue3" tema'sıdır. Mevcut 140 tane tema var bunları şu resimde inceleyebilirsiniz.
Yukarıdaki görseli kendi kurulumunuzda görmek için
sg.theme_previewer()
satırı ile açılacak pencerede görebiliriz.
Reçete - Tema Gösterici
ThemeBrowser.py
import PySimpleGUI as sg
sg.theme("DarkBrown")
layout = [[sg.Text("Tema Gösterici")],
[sg.Text("Demo penceresini görmek için listeden birini seçin")],
[sg.Listbox(values=sg.theme_list(), size=(20, 12), key="-LIST-", enable_events=True)],
[sg.Button("Çıkış")]]
window = sg.Window("Tema Gösterici", layout)
while True:
event, values = window.read()
if event in (None, "Çıkış"):
break
sg.theme(values["-LIST-"][0])
sg.popup_get_text("Bu tema {}".format(values["-LIST-"][0]))
window.close()
Reçete - Temayı modifiye etmek
Diyelim LightGreen3 temasını kullanacağız ama butonların yazılarının beyaz değil siyah olmasını istiyoruz. Bir tema ayarını görmek için kullanılan metod aynı zamanda o ayarı değiştirmek için de kullanılıt. Örneğin theme_background_color() metodu temanın arkaplan rengini bize geri dönerken , aynı metodu parametresine "blue" değeri vererek çağırmak - yani theme_background_color("blue") - arkaplan rengini mavi olarak değiştirecektir.
Şöyle bir kod yazalım:
ModifyTheme.py
import PySimpleGUI as sg
sg.theme("LightGreen3")
sg.popup_no_wait("Bu standart yüklenmiş LightGreen3 tema", "Buton yazıları beyaz")
# Temayı modifiye et
sg.theme_button_color(("black", "#6d9f85"))
sg.popup("Bu modifiye edilmiş LightGreen3 tema", "Buton yazıları siyah")
Bu kod temayı değiştirmeden önce ve değiştirdikten sonra olmak üzere iki popup pencere açarak bize değişimi gösteriyor.
Reçete - Kendi renk temamızı eklemek
Temayı değiştirdikten sonraki tüm pencerelerde değişikliklerimiz geçerli olacaktır. Ama her seferinde mevcut bir temayı tekrar tekrar modifiye etmek yerine kendi temamızı da tanımlayabiliriz.
Aşağıdaki kodu yazalım:
NewTheme.py
import PySimpleGUI as sg
# yeni tema renkleri ve ayarlarını ekleyelim
sg.LOOK_AND_FEEL_TABLE["YeniTema"] = {"BACKGROUND": "#709053",
"TEXT": "#fff4c9",
"INPUT": "#c7e78b",
"TEXT_INPUT": "#000000",
"SCROLL": "#c7e78b",
"BUTTON": ("white", "#709053"),
"PROGRESS": ("#01826b", "d0d0d0"),
"BORDER": 1, "SLIDER_DEPTH": 0,
"PROGRESS_DEPTH": 0
}
# yeni temaya geçelim
sg.theme("YeniTema")
# bir deneme ile görelim
sg.popup_get_text("Yeni temanın görünüşü böyle")
Pencereleri giydirmenin başka yolları
Renklere ilave olarak pencerelerimizi daha yakışıklı yapmak için başka yollar da var. Bunlardan bazıları:
- Title Bar'ı yok etmek
- Pencereyi yarı transparan yapmak (opacity)
- Normal butonları grafiklerle değiştirmek
Bu 3 seçeneğin kombinasyonlarını kullanarak Rainmeter stili pencereler elde edebiliriz.
Aşağıdaki pencere bir örnek gösteriyor. Gördüğünüz gibi pencere arkasından bir yazı silüeti görünüyor, çünkü "alpha" kanalı ayarlanarak pencerenin yarı şeffaf olması sağlanmış. Pencerede Title Bar yok ve kapatmak için kırmızı bir grafik "X" butonuna sahip.
Title Bar'ı yok etmek ve yarı transparan yapmak
Bu iki özellik de pencereyi oluşturan kod içinde ayarlanabilir. no_titlebar ve alpha_channel parametreleri bu işe yarar.
Fakat daha önce birşeyi düşünmeliyiz. Title Bar'ı yok edersek pencere nasıl taşınacak ve nasıl kapatılacak? Taşıma işlemini gerçekleştirmek için grab_anywhere parametresini kullanabiliriz. Bu parametre True yapıldığında pencerede herhangi bir yerden tutarak aynı Title Bar'dan tutmuş gibi ekranda taşıyabiliriz. Bu parametreyi kullanmak içim Title Bar'ı yok etmemiz gerekmez o varken de kullanabiliriz.
Pencereyi yarı transparan yapmak için alpha_channel parametresine değer girilir. Değer 0 ila 1 arasında bir noktalı sayı olacaktır. Yukarıdakine benzer bir pencere için pencerenin kodu şöyle olacaktır.
window = sg.Window("PSG System Dashboard", layout,
no_titlebar=True, alpha_channel=.5, grab_anywhere=True)
Butonu grafikle değiştirmek
PySimpleGUI'de PNG ve GIR resimleri buton olarak kullanabiliriz. Ayrıca bu dosyaları Base64 formata çevirip direk kodumuzun içine de koyabiliriz.
Bir butonu grafik yapmak için 4 adımlık bir yapılacak listemiz var
- PNG ya da GIF grafik bulunur (veya kendimiz yaparız)
- Grafik Base64 string formata çevrilir
- Base64 string programımıza değişken olarak eklenir
- Butonu tanımlarken bu değişken butonun grafiği olarak belirtilir.
Adım-1 Grafiği bulmak
Tabii bir sürü yol var. Burada bir listede çok yararlı siteler bulabilirsiniz. Google'da "red X icon" arayıp görsel seçeneklerinde "Transparent Background" seçerek de bir çok ikon görseline ulaşabiliriz. (Yaşasın internet!).
Örnek olarak şu ikonu alalım.
Adım-2 Base64 string formata çevirmek
PySimpleGUI Github reposundaki demo programlardan birisi de "Demo_Base64_Image_Encoder.py" adındaki program. Bu program klasördeki tüm resim dosyalarını dönüştürüp sonuçları output.py isimli dosyaya kaydediyor.
Başka bir demo programı olan "Demo_Base64_Single_Image_Encoder.py" ise verilen resim dosyasını Base64 format veriye dönüştürüyor. Oradan kopyalayıp programınıza yapıştırabilirsiniz.
Bundan başka https://base64.guru/converter/encode/image gibi online sitelerden de yararlanabiliriz.
Bu sitede dönüştürelim Önce datatype için Remote url seçiyoruz sonra da resim url adresini kopyalayıp yapıştırıyoruz. Sonra da "Encode image to Base64" düğmesine tıklıyoruz.
Adım-3 Base64 string değişkeni eklemek
Size tavsiyem ikon dosyasını indirin ve boyutunu 50x50 piksele küçültün ya da resmi indirin. Yoksa çok kocaman bir butonunuz olacak. Base64 stringe dönüşmüş verimizi aşağıdaki değişkene yapıştırıyoruz.
red_x_base64 = b'iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAjiKvP/9RDMrnS ...'
Adım-4 Butonumuzda Base64 stringi kullanmak
Buton arkaplan renginin görünmesini istemediğimiz için tema arkaplan rengi ile aynı yapıyoruz.
import PySimpleGUI as sg
red_x_base64 = b'iVBORw0KGgoAAAA ... '
layout = [[sg.Text("sınırları olmayan ve bir grafik butonu olan pencere")],
[sg.Button("", image_data=red_x_base64,
button_color=(sg.theme_background_color(), sg.theme_background_color()),
border_width=0, key="Çıkış")]]
window = sg.Window("Title", layout, no_titlebar=True,
alpha_channel=.8, grab_anywhere=True)
while True:
event, values = window.read()
print(event, values)
if event in (None, "Çıkış"):
break
window.close()
Ben bu kod içine resim gömme işini hiç sevmiyorum. Dosyadan resim kullanmayı tercih ederim. Diyorsanız image_data özelliği yerine image_filename özelliği kullanabilirsiniz.
import PySimpleGUI as sg
layout = [[sg.Text("sınırları olmayan ve bir grafik butonu olan pencere")],
[sg.Button("", image_filename="images/Red-X-icon-50x50.png",
button_color=(sg.theme_background_color(), sg.theme_background_color()),
border_width=0, key="Çıkış")]]
window = sg.Window("Title", layout, no_titlebar=True,
alpha_channel=.8, grab_anywhere=True)
while True:
event, values = window.read()
print(event, values)
if event in (None, "Çıkış"):
break
window.close()
Reçete-1 Tek atım pencere - Basit veri girişi - Otomatik numaralanmış
Eğer forma key değeri girilmemiş bir giriş elemanı eklersek key değeri otomatik olarak 0'dan başlayan numaralar şeklinde verilecektir.
Bu örnekte 3 tane giriş elemanı ekleyeceğiz ve numaralar 0,1,2 olacaktır. İlk eklenen eleman values[0] olarak değeri okunabilir ve diğerleri de sırasıyla okunabilir. Şöyle bir pencere tasarlayalım.
OneShot3.py
import PySimpleGUI as sg
sg.theme("Topanga")
layout = [
[sg.Text("Lütfen adınızı, adresinizi ve telefonunuzu girin")],
[sg.Text("İsim", size=(15, 1)), sg.InputText()],
[sg.Text("Adres", size=(15, 1)), sg.InputText()],
[sg.Text("Telefon", size=(15, 1)), sg.InputText()],
[sg.Submit(), sg.Cancel()]
]
window = sg.Window("Basit veri giriş ekranı", layout)
event, values = window.read()
window.close()
print(event, values[0], values[1], values[2])
Reçete - Scriptimize GUI eklemek
Mesela scriptimize komut satırında argüman olarak bir dosya adı girilmesi gerekiyor ancak kullanıcı argümanı girmeden scripti çalıştırdı. Hemen bir popup GUI açarak kullanıcıdan dosya seçmesini isteyebiliriz.
import PySimpleGUI as sg
import sys
if len(sys.argv) == 1:
event, values = sg.Window("Scripten istek",
[[sg.Text("Açılacak dosyayı seçiniz")],
[sg.In(), sg.FileBrowse()],
[sg.Open(), sg.Cancel()]]).read(close=True)
fname = values[0]
else:
fname = sys.argv[1]
if not fname:
sg.popup("İptal", "Dosya ismi girilmedi")
raise SystemExit("İptal ediliyor: dosya ismi verilmedi")
else:
sg.popup("Seçtiğiniz dosya adı ", fname)
Reçete - Yukarıdakinin popup_get_file versiyonu
Tekerleği yeniden icat etmeye gerek yok, direk dosya ismi talep eden bir popup komutu var. Şöyle tek satır kodla bunu yapabiliriz:
fname = sg.popup_get_file("Açılacak dosyayı seçiniz")
Şu pencere açılır ve kullanıcının cevabını geri döner:
FileOpen2.py
import PySimpleGUI as sg
import sys
if len(sys.argv) == 1:
fname = sg.popup_get_file("Açılacak dosyayı seçiniz")
else:
fname = sys.argv[1]
if not fname:
sg.popup("İptal", "Dosya ismi girilmedi")
raise SystemExit("İptal ediliyor: dosya ismi verilmedi")
else:
sg.popup("Seçtiğiniz dosya adı ", fname)
Reçete - Çok duyarlı girişler
Bazen kullanıcının birşeyleri seçtiğinde OK tuşuna basmadan seçimine göre birşeyler yapmak isteriz. Diyelim bir tane listbox var ve kullanıcı listeden bir elemanı seçecek.
Responsive.py
import PySimpleGUI as sg
choices = ("Kırmızı", "Yeşil", "Mavi", "Sarı", "Turuncu", "Mor", "Kahverengi")
layout = [[sg.Text("Favori renginiz hangisi?")],
[sg.Listbox(choices, size=(15, len(choices)), key="-COLOR-")],
[sg.Button("OK")]]
window = sg.Window("Renk seçimi", layout)
while True:
event, values = window.read()
if event is None:
break
if event == "OK":
if values["-COLOR-"]:
sg.popup("Favori renginiz {}".format(values['-COLOR-'][0]))
window.close()
Bir rengi seçip OK tıkladığımızda şöyle bir cevap verecek.
enable_events kullanarak olay anını yakalamak
Bu OK tuşunu tıklamadan yapılan seçimi algılamamız gerekebilir. Mesela bazı web sitelerinde adres seçimi yaparken vilayet adını seçtikten sonra OK falan bir tuş tıklamadan önümüze o vilayetin ilçelerinin isimleri gelir. Burada seçimin yapıldığı an bir kod çalışmaya başlar. Biz de yukarıdaki programda OK tuşlanmadan seçim yapıldığı anda işlem yapabilmek için enable_events kullanarak listbox seçim anını yakalayabiliriz.
Şimdi Yukarıdaki programdan OK tuşunu kaldıralım ve listbox enable_events parametresini True yaparak seçim anını algılayalım:
Responsive.py
import PySimpleGUI as sg
choices = ("Kırmızı", "Yeşil", "Mavi", "Sarı", "Turuncu", "Mor", "Kahverengi")
layout = [
[sg.Text("Favori renginiz hangisi?")],
[sg.Listbox(choices, size=(15, len(choices)), key="-COLOR-", enable_events=True)]
]
window = sg.Window("Renk seçimi", layout)
while True:
event, values = window.read()
if event is None:
break
if values["-COLOR-"]:
sg.popup("Favori renginiz {}".format(values['-COLOR-'][0]))
window.close()
Reçete - Giriş doğrulaması
Bazen kullanıcının yaptığı girişi belli özelliklere karşı test etmek gerekir. Mesela bir dosyaya verilecek şifrenin sadece rakamlardan oluşması ve 5 karakterden fazla olmamasını isteyebiliriz.
Belki de sadece 0-9 arası sayılar , nokta ve eksi işaretlerinden oluşan bir noktalı sayı girilmesini isteyebiliriz. Kullanıcı her tuşa bastığında bu karakterlerden birine basmadıysa hemen silmek isteyebiliriz.
Yukarıda olay anını yakalamayı öğrendik.Şimdi şu programa bakalım:
Restrict.py
import PySimpleGUI as sg
"""
Bir input elemanına girilen karakterleri sınırlamak ve
eğer girilen karakter yanlışsa son karakteri çıkartmak
"""
layout = [ [sg.Text("Sadece noktalı sayılar giriniz")],
[sg.Input(key="-IN-", enable_events=True)],
[sg.Exit()] ]
window = sg.Window("Noktalı sayı giriş doğrulaması", layout)
while True:
event, values = window.read()
if event in (None, "Exit"):
break
if event == "-IN-" and values["-IN-"] and values["-IN-"][-1] not in ("0123456789.-"):
window["-IN-"].update(values["-IN-"][:-1])
window.close()
Bu kod sadece doğru karakterlerin girilmesini kontrol ediyor. Ama tam olarak noktalı sayı girilmesini sağlayamıyor. Biraz daha geliştirelim. If kısmıyla biraz oynamamız gerekecek:
Restrict2.py
import PySimpleGUI as sg
"""
Bir input elemanına girilen karakterleri sınırlamak ve
eğer girilen karakter yanlışsa son karakteri çıkartmak
"""
layout = [ [sg.Text("Sadece noktalı sayılar giriniz")],
[sg.Input(key="-IN-", enable_events=True)],
[sg.Exit()] ]
window = sg.Window("Noktalı sayı giriş doğrulaması", layout)
while True:
event, values = window.read()
if event in (None, "Exit"):
break
if event == "-IN-" and values["-IN-"]:
try:
in_as_float = float(values["-IN-"])
except:
if len(values["-IN-"]) == 1 and values["-IN-"][0] == "-":
continue
window["-IN-"].update(values["-IN-"][:-1])
window.close()
İşin çoğunu Python yaptı. girişteki değeri noktalı sayıya çevirmeyi deneyip eğer hata olursa son karakteri attık. Tek istisna var eğer ilk karakter olarak "-" girilmişse sadece "-" gören python yine hata verecektir. Bu durumda silmeden devam ediyoruz.
Reçete - Yazdırmak
Bir şeyleri ekrana yazdırmak programlarda çok kullanılan bir işlem. Birçoğumuzun ilk Python programı şöyle olmuştur:
print("Merhaba Dünya!")
Fakat bu konsolda oluyordu, GUI dünyasında nereye yazdıracağız? Pekala, bir çok yazdırabileceğimiz yer mevcut. Tabii ki önceki örneklerde gördüğümüz gibi, programımızı çağırdığımız konsolda da yazdırma imkanımız hala var.
Konsola yazdırmak uygulamayı direk GUI çalıştıran Pythonw komutuyla çalıştırdığımızda geçersiz olacaktır. Genelde de geliştirirken hariç , bitmiş programlarımızın yanında bir de konsol penceresi açık olsun istemeyiz. Endişeye gerek yok PySimpleGUI'de bir çok yöntem var.
Aşağıdaki reçeteler programımızda bulunan yazdırma işlemleri için değişik yöntemler sunuyor. Konsol için yazılmış bir programdaki print() komutlarımıza alternetif 3 yöntem şöyle:
- Debug penceresine yazdırmak
- Bir elemana yazdırmak
- Çok satırlı elemanlar
Reçete-1/3 Debug penceresine yazmak
Debug penceresi bir sanal konsol gibi çalışır. 2 çalışma modu vardır. Birinde normal çıktıyı da debug penceresine yönlendirir, diğerinde yapmaz.
Print , eprint , EasyPrint komutları üçü de aynı işi yapar. Aşağıda Print ile bir örnek kod var.
Yazdırma komutlarımızı debug penceresine yönlendirmenin bir yolu basit bir eşitlik ile standart print metodunun üzerine yazmak.
print = sg.Print
DebugPrint.py
import PySimpleGUI as sg
sg.Print("stdout yönlendirme", do_not_reroute_stdout=False)
print("Bu normal print ama debug penceresine yönlendirilmiş")
sg.popup("Test")
Hem print hem de sg.Print debug penceresine yazıyorlar.
Renkli yazmak sadece standart çıkışı yönlendirmeyince geçerli olabilir.
Debug penceresine renkli satırlar yazmak istiyorsak yönlendirme yapmamalıyız.
DebugPrint2.py
import PySimpleGUI as sg
sg.Print("Bu yazı yeşil üzerine beyaz", text_color="white", background_color="green", font="Courier 10")
sg.Print("İlk satır değiştirilemeyen font özelliğini değiştirmeye çalışıyor")
sg.Print("Bu yazı print komutundaki gibi düz bir yazı")
sg.Print("Kırmızı üzerine beyaz", text_color="white", background_color="red")
sg.Print("Başka bir yazı", "sep gibi", "parametreler çalışır", sep=",")
sg.Print("Rengin sona kadar gitmesini istemiyorsak end parametresi", text_color="white", background_color="blue", end="")
sg.Print("\nBu yazının da rengi yok")
sg.popup("Test")
Son satırda "\n" koymasak önceki satır "end" parametresi ile bitirildiği için onun yanına yazılacaktı.
Reçete-2/3 Output elemanına yazmak
Eğer standart öıkışı penceremize yönlendirmek istiyorsak yerleşime bir tane Output elemanı eklemek yeterli olacaktır. Sonra kullanılan tüm print() metodları bu output elemanına yazacaktır.
Aşağıdaki kod Go butonu tıklandıkça değerleri Output elemanına yazacaktır.
OutputPrint.py
import PySimpleGUI as sg
layout = [ [sg.Text("Tüm girdikleriniz aşağıda yazılacak:")],
[sg.Output(size=(50, 10), key="-OUTPUT-")],
[sg.In(key="-IN-")],
[sg.Button("Go"), sg.Button("Clear"), sg.Button("Exit")] ]
window = sg.Window("Pencere etiketi", layout)
while True:
event, values = window.read()
print(event, values)
if event in (None, "Exit"):
break
if event == "Clear":
window["-OUTPUT-"].update("")
window.close()
Reçete-3/3 Çok satırlı elemana yazdırmak
4.18.0 dan beri yerleşimdeki bir Multiline elemana yazdırılabiliyor. Multiline.print metodu Print metoduna benzer çalışıyor. Normal Print parametreleri sep ve end'e sahip. Atrıca renk opsiyonu da var. Güçlendirilmiş bir print fonksiyonu gibi.
Bir Multiline elemanına yazdırma yönlendirmek için 2 yol var:
- Multiline.print metodunu kullanmak
- print metodunun üzerine yazmak
İlk seçenekle başlayalım. Standart print metodu başına bir Multiline eleman koyarak bunu yapıyoruz. Diyelim şöyle bir print komutumuz var
print("Test 1 2 3")
Eğer Multiline elemanımızın key değeri "-ML-" ise bunun seçimi de şöyle olacak
window("-ML-")
İkisini birleştirince Multiline print işlemini gerçekleştirmiş oluruz.
window("-ML-").print("Test 1 2 3")
Multiline elemanı sadece çıktı yazdırmak için kullanacağımızdan bunun window.read() metodu tarafından değişiminin algılanmasını istemeyiz. Bunu sağlamak için key değerine WRITE_ONLY_KEY sabitini eklemeliyiz.
window("-ML-"+sg.WRITE_ONLY_KEY).print("Test 1 2 3")
Aynı işlemi yerleşime Multiline elemanını eklerken de yapmamız gerekiyor.
Şimdi tüm bu anlatılanları bir programda toplayalım.
MultilinePrint.py
import PySimpleGUI as sg
layout = [ [sg.Text("Multiline elemanına yazdırma demosu")],
[sg.MLine(size=(40, 8), key="-ML1-"+sg.WRITE_ONLY_KEY)],
[sg.MLine(size=(40, 8), key="-ML2-"+sg.WRITE_ONLY_KEY)],
[sg.Button("Go"), sg.Button("Exit")] ]
window = sg.Window("Pencere etiketi", layout, finalize=True)
# olay döngüsüne girmeden bu satırlar işlensin diye finalize çağırdık
window["-ML1-"+sg.WRITE_ONLY_KEY].print(1,2,3,4,end="", text_color="red", background_color="yellow")
window["-ML1-"+sg.WRITE_ONLY_KEY].print("\n", end="")
window["-ML1-"+sg.WRITE_ONLY_KEY].print(1,2,3,4, text_color="white", background_color="green")
counter = 0
while True:
event, values = window.read(timeout=100)
if event in (None, "Exit"):
break
if event == "Go":
window["-ML1-"+sg.WRITE_ONLY_KEY].print(event, values, text_color="red")
window["-ML2-"+sg.WRITE_ONLY_KEY].print(counter)
counter += 1
window.close()
Kodu ve çıktıyı tek tek incelemenizi öneririm. timeout=100 ile hiç bir etkileşim olmasa bile window.read() metodu 100 ms içinde çıkarak o anki değerleri veriyor.
Gelelim 2. tekniğe, eğer yazılmış kodumuzun her print satırını değiştirmek istemiyorsak, ama Multiline elemana yazmasını istiyorsak. Yapmamız gereken print metodunun üzerine yazmak. Yeni tanımlayacağımız bir metodu print olarak Python'a tanıtacağız.
Eğer metod tanımı yapacaksak şöyle:
def mprint(*args, **kwargs):
window["-ML1-"+sg.WRITE_ONLY_KEY].(*args, **kwargs)
print = mprint
eğer lambda eşitliği olarak tanımlayacaksak böyle
print = lambda *args, **kwargs: window['-ML1-' + sg.WRITE_ONLY_KEY].print(*args, **kwargs)
yaparız. Şimdi programımızı bu şekilde yazalım:
MultilinePrint2.py
import PySimpleGUI as sg
def mprint(*args, **kwargs):
window["-ML1-"+sg.WRITE_ONLY_KEY].print(*args, **kwargs)
print = mprint
layout = [ [sg.Text("Multiline elemanına yazdırma demosu")],
[sg.MLine(size=(40, 8), key="-ML1-"+sg.WRITE_ONLY_KEY)],
[sg.MLine(size=(40, 8), key="-ML2-"+sg.WRITE_ONLY_KEY)],
[sg.Button("Go"), sg.Button("Exit")] ]
window = sg.Window("Pencere etiketi", layout, finalize=True)
# olay döngüsüne girmeden bu satırlar işlensin diye finalize çağırdık
print(1,2,3,4,end="", text_color="red", background_color="yellow")
print("\n", end="")
print(1,2,3,4, text_color="white", background_color="green")
counter = 0
# ikinci multiline elemana yazıma geçelim
print = lambda *args, **kwargs: window['-ML2-' + sg.WRITE_ONLY_KEY].print(*args, **kwargs)
while True:
event, values = window.read(timeout=100)
if event in (None, "Exit"):
break
if event == "Go":
print(event, values, text_color="red")
print(counter)
counter += 1
window.close()
Bu kadar yazdıklarımı bir yayınlayayım. Arkası gelecek, biraz daha karmaşık reçetelerle devam edeceğiz. Tekrar görüşmek ümidiyle kalın sağlıcakla..
Çok faydalı dersler. Tesekkürü borç bilirim: Teşekkürler
YanıtlaSil