Tkinter Buton üzerindeki resmi değiştirme

Merhaba, Python da ve Tkinter da oldukça yeniyim 6 farklı buton oluşturup bu butonların üzerinde ki resimleri bastığım zaman değiştirmek istiyorum. Örneğin birinci buton üzerinde sıcaklık_on.png isimli bi resim varken üzerine tıkladığımda sıcaklık_off.png olan bir resimle değişsin istiyorum (aynı şekilde sıcaklık_off.png resmide basınca değişsin) ve bunu 6 buton için yapmaya çalışıyorum her bir butonu oluşturdum ve yanlızca ilk buton için denedim ancak resmi değiştirmek istediğimde butonu yanlızca pencere üzerinden kaldırıyor yeni buton meydana getiremiyorum. Nasıl yapabilirim.


from tkinter import *

pencere = Tk()

pencere.geometry("800x480")
pencere.resizable(width= FALSE, height= FALSE)

def sıcaklık_off():
buton1.destroy()
sıcaklık_off = PhotoImage(file="sıcaklık_off.png")
buton7 = Button(pencere, text="sıcaklık_off", image = sıcaklık_off)
buton7.place(relx=0.33, rely=0.11)

sıcaklık_on = PhotoImage(file="sıcaklık_on.png")
buton1 = Button(pencere, text="sıcaklık_on", image = sıcaklık_on, command= sıcaklık_off())
buton1.place(relx=0.33, rely=0.11)

ısıtıcı_on = PhotoImage(file="ısıtıcı_on.png")
buton2 = Button(pencere, text="ısıtıcı", image = ısıtıcı_on)
buton2.place(relx=0.33, rely=0.11)

lamba_on = PhotoImage(file="lamba_on.png")
buton3 = Button(pencere, text="lamba", image = lamba_on)
buton3.place(relx=0.66, rely=0.11)

titresim_on = PhotoImage(file="titresim_on.png")
buton4 = Button(pencere, text="titresim", image = titresim_on)
buton4.place(relx=0.0, rely=0.56)

kemer_on = PhotoImage(file="kemer_on.png")
buton5 = Button(pencere, text="kemer_belt", image = kemer_on)
buton5.place(relx=0.33, rely=0.56)

servis_on = PhotoImage(file="servis_on.png")
buton6 = Button(pencere, text="servis_on", image = servis_on)
buton6.place(relx=0.66, rely=0.56)

mainloop()

Merhaba, aşağıdaki kodları bir inceleyin isterseniz. Sizinle kullandığım resim dosyalarını da paylaşayım. Bu resimleri images isimli bir klasöre koymuştum. images klasörü ile python dosyası aynı dizinde yer alıyor. Eğer dosyaları başka bir yerde tutacaksanız, adresi bu yere göre tekrar düzenlersiniz.
switch-on -> switch-on.png
switch-off -> switch-off.png
turn-on -> turn-on.png
turn-off -> turn-off.png

import tkinter as tk

from os import listdir
from os.path import splitext
from PIL.ImageTk import PhotoImage


class Button(tk.Button):
    def __init__(self, img: str = "", *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.pack()
        self.status = False
        self.img = img
        self.configure(
            image=images[img], 
            borderwidth=0,
            highlightthickness=0,
            bg="white",
            activebackground="white",
            command=self.command        
        )
        
    def command(self):
        if not self.status:
            self.configure(image=images[self.img.replace("off", "on")])
            self.status = True
        else:
            self.configure(image=images[self.img.replace("on", "off")])
            self.status = False
        
        
root = tk.Tk()
root.geometry("500x500")

frame = tk.Frame(master=root, bg="white")
frame.pack(expand=True, fill=tk.BOTH)

images = {
    splitext(i)[0]: PhotoImage(file=f"./images/{i}", size="200x300") 
    for i in listdir("./images")
}

switch = Button(master=frame, img="switch-off")
turn = Button(master=frame, img="turn-off")

root.mainloop()

Her bir düğme için tekrar tekrar aynı tanımlamaları yapmanıza aslında gerek yok. Bunun yerine eğer düğmelerin bazı ortak özellikleri varsa, bu özellikleri içeren ve düğme sınıfının bütün özelliklerini miras alan bir sınıf tanımlayabilirsiniz. Ve bu sınıftan oluşturacağınız her örneğin ilgili parametrelerinde ufak değişiklikler yaparak, örneği özelleştirebilirsiniz.

Ayrıca bütün resimleri tek tek elle tanımlamanıza da gerek yok. Bunun yerine resimleri bir tane klasörde tutup, os modülünü kullanarak bu klasöre erişebilir ve bütün resimleri bir for döngüsü yardımıyla alabilir ve resimleri list, tuple veya dict gibi veri tiplerinde tutabilirsiniz. Bu yukarıdaki kodlarda, resimler dict veri tipine ait bir örneğin içine aktarıldı.

Ve gördüğünüz gibi, Button sınıfından örnek oluştururken sadece aşağıdaki kodları yazmak yeterli oldu.

switch = Button(master=frame, img="switch-off")
turn = Button(master=frame, img="turn-off")

Başka resimleri kullanan yeni düğmeler oluşturmak istiyorsanız, bu resimleri images klasörünün içine mevcut isimlendirme kuralına uygun olarak atarsınız. Ve sonra da düğmelerinizi aşağıdaki gibi tanımlarsınız.

# Örneğin sıcaklık için
temperature = Button(master=frame, img="temperature-off")

# Örneğin titreşim için
vibration = Button(master=frame, img="vibration-off")

Resimlerin ilk değerini kapalı olarak belirledim. Siz bunu isterseniz değiştirebilirsiniz.

Not: Eğer düğmeler açıkken bazı işlemler yapılacaksa, kodları buna göre düzenleyebilirsiniz. Yani düğmeye bastığınızda hem düğmenin resmi değişir hem de yapılması gereken başka işlemler de yapılır.

2 Beğeni

Çok teşekkür ederim çok yardımcı oldunuz :slight_smile:
kendi resimlerimi images isimli bir dosyaya atıp son satırı dediğiniz şekilde düzenleyip tekrar denedim ancak şöyle bir hata alıyorum nerede hata yapmış olabilirim

Bu resim dosyalarının listesini gösterebilir misiniz? Ve denemek açısından bizimle de paylaşabilir misiniz? Aynı zamanda kendi bilgisayarınıza aktardığınız kodları da buraya resim şeklinde değil de, yazı şeklinde atar mısınız?
Bunun için kodlarınızı üç çentik arasına alabilirsiniz.

```
# python kodları bu çentikler arasına yazılacak.
```

Çözdüm tamamdır çok teşekkür ediyorum gerçekten çok yardımcı oldunuz

merhaba yeniden rahatsız ediyorum kusura bakmayın. Sizin kodunuzu sorunsuz çalıştırmıştım ancak 6 resmi 2 satır 3 sütundan oluşacak şekilde düzenleyip hazır bir background üzerine eklemek istedim epeyce araştırdım ve uğraştım yine de içinden çıkamadım yeniden yardıma ihtiyacım var sanırım nerede hata yaptığımı bulamıyorum

import tkinter as tk

from os import listdir
from os.path import splitext
from PIL.ImageTk import PhotoImage


class Button(tk.Button):
    def __init__(self, img: str = "", *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.satirno= 0
        for satir in range(0,2):
            self.sutunno= 0
            for sutun in range(0,3):
               self.grid(row= satirno, column = sutunno)
            self.sutunno += 1
        self.satirno +=1
        self.status = False
        self.img = img
        self.configure(
            image=images[img],
            borderwidth=0,
            highlightthickness=0,
            bg="white",
            activebackground="white",
            command=self.command
        )

    def command(self):
        if not self.status:
            self.configure(image=images[self.img.replace("off", "on")])
            self.status = True
        else:
            self.configure(image=images[self.img.replace("on", "off")])
            self.status = False


root = tk.Tk()
root.geometry("500x500")

frame = tk.Frame(master=root, bg="white")
frame.pack(expand=True, fill=tk.BOTH)

background= PhotoImage(file="backgroung.png")
label = Label(root, text"background", image = background)
label.place(relx=0.0, rely=0.0)

images = {
    splitext(i)[0]: PhotoImage(file=f"./images/{i}", size="200x300")
    for i in listdir("./images")
}

sun-off = Button(master=frame, img="sun-off")
rainy-off = Button(master=frame, img="rainy-off")
cloudy-off = Button(master=frame, img="cloudy-off")
lightning-off = Button(master=frame, img="lightning-off")
flower-off = Button(master=frame, img="flower-off")
grass-off = Button(master=frame, img="grass-off")

root.mainloop()
```

Tespit ettiğim bir kaç hatadan bahsedeyim:

  1. Siz tek bir Button nesnesini iç içe iki tane for döngüsünün içinde tekrar tekrar grid ile ekrana eklemeye çalışmışsınız. Halbuki bir widget sadece bir kez grid veya pack veya place yöntemi kullanılarak ekrana yerleştirilebilir.

  2. Değişken isimlerinin arasında - işareti olamaz.

  3. Tkinter’i, tk ismiyle import etmişsiniz ama Label widgetini tk.Label olarak değil de Label olarak örneklemeye çalışmışsınız.

  4. Label'in, ismi text olan parametresini yazdıktan sonra, değer ataması yapmadan önce = işaretini eklemeliydiniz, eklememişsiniz.

Ekrana önce background.png resim dosyasını sonra da Button nesnelerini içeren frame widgetini eklemeniz gerekiyor. Ayrıca tk.Frame nesnesi ekrana eklenirken expand ve fill parametreleri kullanılmamalı, aksi taktide frame ekranı kaplayacaktır.

Aşağıdaki kodları bir inceleyin isterseniz. Resimleri ekrana ekleme işlemini sınıfın içinde değil de sınıfın dışında yaptım.

#!/usr/bin/python3.8
# -*- coding: utf-8 -*-

import tkinter as tk

from os import listdir
from os.path import splitext
from PIL.ImageTk import PhotoImage


class Button(tk.Button):
    buttons = []

    def __init__(self, img: str = "", *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.status = False
        self.img = img
        self.configure(
            image=images[img],
            borderwidth=0,
            highlightthickness=0,
            bg="white",
            activebackground="white",
            command=self.command
        )
        self.buttons.append(self)

    def command(self):
        if not self.status:
            self.configure(image=images[self.img.replace("off", "on")])
            self.status = True
        else:
            self.configure(image=images[self.img.replace("on", "off")])
            self.status = False


root = tk.Tk()
root.geometry("500x500")

background = PhotoImage(file="background.png")
label = tk.Label(root, text="background", image=background)
label.place(relx=0.0, rely=0.0)

frame = tk.Frame(master=root, bg="white")
frame.pack()

images = {
    splitext(i)[0]: PhotoImage(file=f"./images/{i}", size="200x300")
    for i in listdir("./images")
}

sun_off = Button(master=frame, img="sun-off")
rainy_off = Button(master=frame, img="rainy-off")
cloudy_off = Button(master=frame, img="cloudy-off")
lightning_off = Button(master=frame, img="lightning-off")
flower_off = Button(master=frame, img="flower-off")
grass_off = Button(master=frame, img="grass-off")

row = 0
column = 0
for i, j in enumerate(Button.buttons):
    if i == 3:
        row += 1
        column = 0
    j.grid(row=row, column=column)
    column += 1

root.mainloop()
1 Beğeni

Tamamdır tüm sorunlar çözüldü gerçekten çok çok teşekkür ederim ellerinize sağlık

Rica ederim kolay gelsin.