@MedetAk
Aşağıdaki güncelleme ise dinamik olarak uyarlanmasını sağlamaktadır.
Aşağıda, uygulamanızın ana penceredeki widget’larının (buton, font ve resimlerin) pencere boyutuna göre dinamik olarak yeniden boyutlandığı tam teşekküllü örnek kodu bulabilirsiniz. Bu örnekte:
- Orijinal Tasarım Boyutu: 1200×900 referans alınarak, yeniden boyutlandırma oranı hesaplanıyor.
- <Configure> Event: Ana pencere boyut değişikliklerinde hesaplanan ölçek oranına göre, font boyutları ve ana pencerede kullanılan butonlardaki resimler yeniden boyutlandırılıyor.
- Resimlerin Dinamik Boyutlandırılması: Uygulamanın ana ekranındaki butonlarda kullanılan resimler, orijinal PIL nesneleri saklanarak her yeniden boyutlandırmada güncelleniyor.
- Not: Toplevel pencereleri için de benzer dinamik boyutlandırma mantığını uygulayabilirsiniz; örnekte ana pencereye odaklanılmıştır.
Aşağıdaki kodu tek blok halinde inceleyebilirsiniz:
import tkinter as tk
import sqlite3
import random
import pyttsx3
import os
from PIL import Image, ImageTk
from googletrans import Translator
from customtkinter import CTk, CTkButton, CTkLabel, CTkScrollableFrame, CTkTextbox, CTkFont, CTkToplevel, CTkEntry, set_appearance_mode
class App3:
def __init__(self, root):
self.root = root
# Tasarım referans boyutu
self.design_width = 1200
self.design_height = 900
# Orijinal resimleri saklayacağımız sözlük
self.original_images = {}
# Ana pencere butonlarında kullanılacak resimlerin isimlerini belirliyoruz
# (buton oluşturulurken orijinal resim üzerinden oluşturulacak, sonra yeniden boyutlanacak)
self.original_images['pcard'] = Image.open("pluscard.png")
self.original_images['card'] = Image.open("card.png")
self.original_images['translate']= Image.open("translate.png")
self.original_images['gunluk'] = Image.open("gunluk.png")
self.original_images['img'] = Image.open("menu.png")
# Diğer resimler (Toplevel pencereler için) sabit kalabilir ya da benzer şekilde dinamik hale getirilebilir.
self.ileri_img = Image.open("next2.png")
self.img2_img = Image.open("tik.png")
self.imgev_img = Image.open("ev.png")
self.imgspeak_img= Image.open("speaker.png")
self.imgtrans_img= Image.open("translate2.png")
self.degis_img = Image.open("degistir.png")
self.imgg_img = Image.open("arka3.png")
self.ses_img = Image.open("ses.png")
# Dinamik boyutlandırma için geçici photoImage nesneleri oluşturulacak.
self.images = {}
for key in ('pcard', 'card', 'translate', 'gunluk', 'img'):
# İlk başta orijinal boyutunda yüklüyoruz
self.images[key] = ImageTk.PhotoImage(self.original_images[key])
# Uygulama dosya ve veritabanı yolları
self.base_dir = os.path.join(os.path.expanduser("~"), "WordLearnerApp")
self.yol = os.path.join(self.base_dir, "data.db")
self.yol2 = os.path.join(self.base_dir, "learned.db")
self._ensure_database_exists(self.yol)
self._ensure_database_exists(self.yol2)
# Veritabanı bağlantıları
self.baglanti = sqlite3.connect(self.yol)
self.cursor = self.baglanti.cursor()
self.cursor.execute("""CREATE TABLE IF NOT EXISTS WORKS(
WORK text UNIQUE,
meaning text UNIQUE,
example text UNIQUE
)""")
self.cursor.execute("SELECT * from WORKS")
self.veri = self.cursor.fetchall()
self.baglanti2 = sqlite3.connect(self.yol2)
self.cursor2 = self.baglanti2.cursor()
self.cursor2.execute("""CREATE TABLE IF NOT EXISTS LEARN(
LEARNED text
)""")
self.cursor2.execute("SELECT * from LEARN")
self.veri2 = self.cursor2.fetchall()
# Metin okuma motoru
self.engine = pyttsx3.init()
self.engine.setProperty("rate", 140)
self.engine.setProperty('volume', 0.9)
# Font ayarları (tasarım referansına göre)
self.base_font_size = 30
self.base_font2_size = 15
self.base_font3_size = 10
self.base_font4_size = 15
self.font = CTkFont(family="Comic Sans MS", size=self.base_font_size, weight="bold", slant="roman")
self.font2 = CTkFont(family="Comic Sans MS", size=self.base_font2_size, weight="bold", slant="roman")
self.font3 = CTkFont(family="Comic Sans MS", size=self.base_font3_size, weight="bold", slant="roman")
self.font4 = CTkFont(family="Comic Sans MS", size=self.base_font4_size, weight="bold", slant="roman")
# Yardımcı fonksiyon: Veritabanını güncelle
def guncelle():
self.cursor.execute("SELECT * from WORKS")
self.veri = self.cursor.fetchall()
# Öğrenilmiş kelimeler ekranı
def learned():
winLearned = CTkToplevel(self.root)
winLearned.title("LEARNED")
winLearned.geometry("600x500")
winLearned.resizable(False, False)
learnText = "\n".join(i[0] for i in self.veri2)
learFrm = CTkScrollableFrame(master=winLearned,
label_text="LEARNED",
label_font=self.font4,
fg_color="#315ffd")
learFrm.pack(expand=True, fill="both", padx=10, pady=10)
labLearn = CTkLabel(master=learFrm, text=learnText, font=self.font4)
labLearn.pack(padx=10, pady=10)
# Çeviri ekranı (Toplevel sabit boyutlu, örnekte dinamik yenileme ana pencerede uygulanıyor)
def trans():
winceviri = CTkToplevel(self.root)
winceviri.title("TRANSLATE")
winceviri.geometry("600x500")
winceviri.resizable(False, False)
src1, dest1 = "tr", "en"
def oku2():
if transXten.cget("text") == "türkçe":
self.engine.say(transLabel.cget("text"))
self.engine.runAndWait()
else:
self.engine.say(transBox.get("1.0", 'end'))
self.engine.runAndWait()
def dildegis():
nonlocal src1, dest1
if dest1 == "en":
dest1, src1 = "tr", "en"
transXten.configure(text="english")
transYe.configure(text="türkçe")
else:
dest1, src1 = "en", "tr"
transXten.configure(text="türkçe")
transYe.configure(text="english")
def cevir():
translator = Translator()
translated = translator.translate(transBox.get("1.0", "end-1c"), src=src1, dest=dest1)
newText = "\n".join(translated.text[i:i+15] for i in range(0, len(translated.text), 15))
transLabel.configure(text=newText)
transXten = CTkLabel(winceviri, font=self.font2, text="türkçe")
transXten.place(relx=0.2, rely=0.1, anchor="center")
transYe = CTkLabel(winceviri, font=self.font2, text="english")
transYe.place(relx=0.7, rely=0.1, anchor="center")
transBox = CTkTextbox(winceviri, width=200, height=150, font=("helvetica", 20))
transBox.place(relx=0.1, rely=0.4, anchor="w")
transLabel = CTkLabel(winceviri, font=self.font, text="", bg_color="#242424", width=150, height=80, corner_radius=15)
transLabel.place(relx=0.5, rely=0.2, anchor="center")
degis = CTkButton(winceviri, text="", width=55, height=55, fg_color="#242424", hover_color="#333333",
command=dildegis, image=ImageTk.PhotoImage(self.degis_img), corner_radius=10)
degis.pack(pady=40)
cevirBtn = CTkButton(winceviri, command=cevir, text="ÇEVİR")
cevirBtn.place(relx=0.4, rely=0.8, anchor="center")
sesBtn = CTkButton(winceviri, command=oku2, text="", image=ImageTk.PhotoImage(self.ses_img), width=15, height=15,
fg_color="#242424", hover_color="#333333")
sesBtn.pack(pady=120)
# Kelime ekleme ekranı
def ekle():
winekle = CTkToplevel(self.root)
winekle.title("ADD A WORD")
winekle.geometry("600x500")
winekle.resizable(False, False)
def guncelle_inner():
self.cursor.execute("SELECT * from WORKS")
self.veri = self.cursor.fetchall()
def kelime():
ing_icerik = self.enting.get().strip()
tr_icerik = self.enttr.get().strip()
ex_icerik = self.entex.get().strip() or "."
if ing_icerik and tr_icerik:
self.cursor.execute("INSERT INTO WORKS (WORK, meaning, example) VALUES (?,?,?)",
(ing_icerik, tr_icerik, ex_icerik))
self.baglanti.commit()
self.enting.delete(0, tk.END)
self.enttr.delete(0, tk.END)
self.entex.delete(0, tk.END)
self.kelimekart.configure(image=self.images['card'], state="NORMAL")
else:
# Renk ile hata belirtimi yapılabilir
pass
guncelle_inner()
self.lab1 = CTkLabel(master=winekle, text="", font=("Times", 30), image=ImageTk.PhotoImage(self.imgg_img), bg_color="red")
self.lab1.pack(expand=True, fill="both")
self.frm = CTkScrollableFrame(master=self.lab1, width=330, height=300, corner_radius=35,
bg_color="#FF7F47", fg_color="#315ffd",
scrollbar_button_color="#315ffd", scrollbar_button_hover_color="#315ffd")
self.frm.place(relx=0.5, rely=0.5, anchor="center")
ingwork = CTkLabel(self.frm, font=self.font3, text="english")
ingwork.place(relx=0.1, rely=0.0, anchor="w")
trwork = CTkLabel(self.frm, font=self.font3, text="türkçe")
trwork.place(relx=0.1, rely=0.2, anchor="w")
exwork = CTkLabel(self.frm, font=self.font3, text="example")
exwork.place(relx=0.1, rely=0.4, anchor="w")
self.enting = CTkEntry(self.frm, width=250, height=40, placeholder_text="LÜTFEN BİR KELİME GİRİNİZ",
corner_radius=25, fg_color="#404040")
self.enting.pack(pady=10, padx=30)
self.enttr = CTkEntry(self.frm, width=250, height=40, placeholder_text="LÜTFEN BİR KELİME GİRİNİZ",
corner_radius=25, fg_color="#404040")
self.enttr.pack(pady=10, padx=30)
self.entex = CTkEntry(self.frm, width=250, height=40, placeholder_text="LÜTFEN BİR ÖRNEK GİRİNİZ",
corner_radius=25, fg_color="#404040")
self.entex.pack(pady=10, padx=30)
self.btn = CTkButton(self.frm, width=200, height=35, command=kelime, text="EKLE",
text_color="black", fg_color="#FFD700", hover_color="#FFD700")
self.btn.pack(pady=35, padx=5)
# Kelime kartı ekranı
def calis():
wincalis = CTkToplevel(self.root)
wincalis.geometry("600x520")
wincalis.title("WORD CARD")
wincalis.resizable(False, False)
if self.veri:
kelime = random.choice(self.veri)
else:
self.kelimekart.configure(image=self.images['card'], state="DISABLED")
kelime = None
def guncelle_inner():
self.cursor.execute("SELECT * from WORKS")
self.veri = self.cursor.fetchall()
if not self.veri:
self.kelimekart.configure(image=self.images['card'], state="DISABLED")
def ogrenildi():
kel = lab.cget("text")
self.cursor2.execute("INSERT INTO LEARN (LEARNED) VALUES (?)", (kel,))
self.baglanti2.commit()
self.cursor.execute("DELETE from WORKS WHERE WORK = ?", (kel,))
self.baglanti.commit()
guncelle_inner()
siradaki()
def siradaki():
nonlocal kelime
if self.veri:
kelime = random.choice(self.veri)
if kelime[0] != lab.cget("text"):
lab.configure(text=f"{kelime[0]}")
self.ses.place(relx=0.1, rely=0.8, anchor="center")
self.btnAnlam.place(relx=0.5, rely=0.8, anchor="center")
self.ogrendi.place(relx=0.3, rely=0.8, anchor="center")
else:
siradaki()
for widget in self.frm.winfo_children():
if widget != lab:
widget.destroy()
else:
lab.configure(text="Kelime yok")
def anlamAl():
guncelle_inner()
if self.veri and kelime:
labAnlam = CTkLabel(master=self.frm, text=f"= {kelime[1]}", font=self.font)
labAnlam.pack(pady=3)
labOrn = CTkLabel(master=self.frm, text=f"{kelime[2]}", font=self.font4)
labOrn.pack(pady=140)
self.btnAnlam.place_forget()
if len(labOrn.cget("text")) >= 30:
newText = "\n".join(labOrn.cget("text")[i:i+30] for i in range(0, len(labOrn.cget("text")), 30))
labOrn.configure(text=newText)
labOrn.pack_configure(pady=135)
def oku():
self.engine.say(lab.cget("text"))
self.engine.runAndWait()
def anamenugit():
self.root.destroy()
self.font = CTkFont(family="Comic Sans MS", size=int(self.base_font_size*1.1667), weight="bold", slant="roman")
self.frm = CTkScrollableFrame(master=wincalis, width=320, height=280, corner_radius=35,
scrollbar_button_color="#315ffd", scrollbar_button_hover_color="#315ffd",
fg_color="#315ffd", label_fg_color="red")
self.frm.place(relx=0.5, rely=0.3, anchor="center")
lab = CTkLabel(master=self.frm, text="GO GO GO!!!", font=self.font)
lab.pack(padx=10, pady=10)
self.btnileri = CTkButton(master=wincalis, text="", fg_color="#242424", command=siradaki,
image=ImageTk.PhotoImage(self.ileri_img), corner_radius=155, hover_color="#333333")
self.btnileri.place(relx=0.8, rely=0.3, anchor="center")
self.btnAnlam = CTkButton(master=wincalis, text="", fg_color="#242424", command=anlamAl,
corner_radius=155, image=ImageTk.PhotoImage(self.imgtrans_img), hover_color="#333333")
self.ses = CTkButton(master=wincalis, text="", fg_color="#242424", command=oku,
image=ImageTk.PhotoImage(self.imgspeak_img), hover_color="#333333")
self.ogrendi = CTkButton(master=wincalis, text="", fg_color="#242424", command=ogrenildi,
image=ImageTk.PhotoImage(self.img2_img), hover_color="#333333")
self.anamenu = CTkButton(master=wincalis, text="", width=32, height=32, fg_color="#242424",
command=anamenugit, image=ImageTk.PhotoImage(self.imgev_img), hover_color="#333333")
self.anamenu.place(relx=0.0, rely=0.0, anchor="nw")
# Ana pencere üzerindeki butonlar (relatif konumlandırma kullanılıyor)
self.kelimeekle = CTkButton(master=root, image=self.images['pcard'], text="",
fg_color="#242424", hover_color="#333333", command=ekle)
self.kelimeekle.place(relx=0.15, rely=0.0778, anchor="center")
self.kelimekart = CTkButton(master=root, image=self.images['card'], text="",
fg_color="#242424", hover_color="#333333", command=calis)
self.kelimekart.place(relx=0.4333, rely=0.0722, anchor="center")
self.ceviri = CTkButton(master=root, image=self.images['translate'], text="",
fg_color="#242424", hover_color="#333333", command=trans)
self.ceviri.place(relx=0.7167, rely=0.0722, anchor="center")
self.kitap = CTkButton(master=root, text="",
fg_color="#242424", hover_color="#333333", state="DISABLED")
self.kitap.place(relx=0.5917, rely=0.4222, anchor="center")
self.gunluk = CTkButton(master=root, image=self.images['gunluk'], text="",
fg_color="#242424", hover_color="#333333", command=learned)
self.gunluk.place(relx=0.4167, rely=0.4444, anchor="center")
self.btn = CTkButton(master=root, image=self.images['img'], text="", width=30, height=30,
fg_color="#242424", hover_color="#333333")
self.btn.place(relx=0.001, rely=0.001, anchor="nw")
# Pencere yeniden boyutlandırıldığında dinamik güncelleme yapıyoruz.
self.root.bind("<Configure>", self.on_resize)
def on_resize(self, event):
# Yeni pencere boyutlarını al
new_width = event.width
new_height = event.height
# Ölçek oranını hesapla (en küçük oranı kullanıyoruz)
scale = min(new_width / self.design_width, new_height / self.design_height)
# Font boyutlarını güncelle (minimum boyut sınırı koyabilirsiniz)
new_font_size = max(8, int(self.base_font_size * scale))
new_font2_size = max(8, int(self.base_font2_size * scale))
new_font3_size = max(8, int(self.base_font3_size * scale))
new_font4_size = max(8, int(self.base_font4_size * scale))
self.font.configure(size=new_font_size)
self.font2.configure(size=new_font2_size)
self.font3.configure(size=new_font3_size)
self.font4.configure(size=new_font4_size)
# Ana pencere butonlarında kullanılan resimleri yeniden boyutlandır
for key in self.images:
orig = self.original_images[key]
new_w = max(1, int(orig.width * scale))
new_h = max(1, int(orig.height * scale))
self.images[key] = ImageTk.PhotoImage(orig.resize((new_w, new_h), Image.ANTIALIAS))
# Butonlardaki image özelliklerini güncelle
self.kelimeekle.configure(image=self.images['pcard'])
self.kelimekart.configure(image=self.images['card'])
self.ceviri.configure(image=self.images['translate'])
self.gunluk.configure(image=self.images['gunluk'])
self.btn.configure(image=self.images['img'])
def _ensure_database_exists(self, path):
directory = os.path.dirname(path)
if not os.path.exists(directory):
os.makedirs(directory)
if not os.path.exists(path):
open(path, 'a').close()
if __name__ == "__main__":
set_appearance_mode("dark")
root = CTk()
root.geometry("1200x900")
root.resizable(True, True)
app = App3(root)
root.mainloop()
Açıklamalar
Dinamik Boyutlandırma:
Ana pencere boyutu değiştiğinde on_resize
metodu çağrılır. Bu metodda, tasarım referansına göre ölçek hesaplanır, fontlar ve ana penceredeki butonların resimleri yeniden boyutlandırılır.
Relatif Yerleşim:
Butonların yerleştirilmesinde relx
ve rely
kullanılmıştır; böylece pencere boyutu değişse bile orantılar korunur.
Genişletilebilirlik:
Toplevel pencereler için de benzer dinamik boyutlandırma mantığını uygulayabilir, isterseniz benzer şekilde <Configure>
event’ini ekleyebilirsiniz.
Bu yapı, uygulamanızın farklı cihaz ve ekran çözünürlüklerinde uyumlu çalışmasını sağlayacaktır.