Tkinter arka plan renginden kurtulmak mümkünmü?

Merhaba, tkinter ile bir menü yapıyorum arka plana canvas kullanarak bir resmi ekledim sonrasında buton olarak da bir resim ekledigimde(png) arka planda varsayılan olarak gelen bir renk var bundan kurtulmanın bir yolu varmı ?

image

Mümkün ama bunun için biraz farklı bir yol izlemek gerekiyor çünkü tkinter widgetlerinin şeffaf arka plan özelliği yok.

Eğer arka planı şeffaf olan bir button oluşturmak istiyorsak, aslında canvas nesnelerini bu amaçla kullanabiliriz. Örneğin bir tane resim ekleyebiliriz ve eklediğimiz resme bir takım olaylar bağlayabiliriz. Bu olaylar resmin button gibi davranmasını sağlayabilir.

Aşağıda bu konuyla alakalı bir örnek görüyorsunuz.
Bu örnekte kullanılan dosyalar şunlar:
background
play

import tkinter as tk

from PIL import Image, ImageTk, ImageOps

root = tk.Tk()

# Arka plan olarak kullanılacak resmi açalım.
_background_image = Image.open("background.jpeg")
# Resmin genişlik ve yükselik değerlerini alalım.
width, height = _background_image.size
# Bir tane PhotoImage nesnesi oluşturalım.
background_image = ImageTk.PhotoImage(_background_image)

# Düğme olarak kullanılacak ikonu açalım.
_play_icon = Image.open("play.png")
# Bir tane PhotoImage nesnesi oluşturalım.
play_icon = ImageTk.PhotoImage(_play_icon)

# Canvas nesnesini oluşturuyoruz.
canvas = tk.Canvas(master=root, width=width, height=height)
canvas.pack()
# Arka planı ekrana yerleştiriyoruz.
canvas.create_image(0, 0, image=background_image, anchor="nw")


def on_button_1(img, status):
    if status == "pressed":  # Eğer resme tıklandıysa
        # Resmin modunu RGBA olarak değiştirelim.
        _img = img.convert(mode="RGBA")
        # Resmi tayflara ayıralım. İkinci -> [1] tayfı seçelim.
        # İsterseniz farklı tayflarda nasıl sonuçlar oluşuyor
        # deneyebilirsiniz.
        _img = _img.split()[1]
        # Resmin modunu greyscale olarak değiştirelim.
        _img = _img.convert(mode="L")
        # Siyah yerler siyah kalsın, beyaz yerler green olsun.
        _img = ImageOps.colorize(_img, black="black", white="green")
        # Resmin modunu tekrar RGBA olarak ayarlayalım.
        _img = _img.convert("RGBA")
        # Siyah yerleri transparan bir hale getirelim.
        _img.putdata(
            [
                (0, 0, 0, 0) if all(i[j] < 50 for j in range(3)) else i 
                for i in _img.getdata()
            ]
        )
        # Oluşturduğumuz yeni resim ile yeni bir PhotoImage 
        # nesnesi oluşturalım.
        _img = ImageTk.PhotoImage(_img)
        print("Button pressed!")
    else:  # Eğer button1 serbest bırakıldıysa
        # Resim orijinal hale geri gelsin.
        _img = ImageTk.PhotoImage(img)
    # PhotoImage garbage collector'a gitmesin diye, PhotoImage'i canvas
    # nesnesine bağlıyoruz.
    canvas._img = _img
    # button tagına sahip canvas nesnesinin image özelliğini değiştiriyoruz.
    canvas.itemconfig("button", image=canvas._img)


# Button olarak görev yapacak resim nesnemiz.
button = canvas.create_image(
    width // 2, 
    height // 2, 
    image=play_icon, 
    anchor="center",
    tag="button"
)
# Bu resme bazı olaylar ekleyelim.
# Olay 1: <ButtonPress-1>
canvas.tag_bind(
    tagOrId=button,
    sequence="<ButtonPress-1>",
    func=lambda event: on_button_1(
        img=_play_icon, 
        status="pressed"
    )
)
# Olay 2: <ButtonPress-1>
canvas.tag_bind(
    tagOrId=button,
    sequence="<ButtonRelease-1>",
    func=lambda event: on_button_1(
        img=_play_icon, 
        status="released"
    )
)

root.mainloop()

Resmin ortasında duran play simgesine tıklamadan önce resim şu şekilde görünüyor:
Ekran görüntüsü 2020-11-23 23-49-33

Resme tıkladığımızda, play simgesinin rengi aşağıdaki gibi değişiyor:
Ekran görüntüsü 2020-11-23 23-51-59

Fare’yi serbest bıraktığımızda ise resmin rengi tekrar eski haline dönüyor. Bu arada düğmeye bastığımızda ekrana button pressed yazısı yazdırılıyor.

1 Beğeni

Cevapladığınız için teşekkürler aklıma bir kaç soru takıldı bunları sormak isterim ve birde problemle karşılaştım.

öncelikle sorunumdan bahsedeyim eğer bir resime farenin sol tuşunu basılı tutarsak resimin arka planında yeşil bir ekran gözüküyor ve sol tuşa basılı tutmayı bırakana kadar orada kalıyor.
image
Sorularım:
herhangi bir buton vs. ekledigimizde kanvasın üzerinde degilde aşşagısında yer alıyor her seferine place ile yer mi belirtmemiz gerek yoksa pack kullanarak yapmakta mümkünmüdür.

Herhangi bir resimin yerini degiştirmek istedigimde width // 2,
height // 5, parametrelerini mi kullanmalıyım place felan kullanamazmıyım bunuda sormadan geçmek istemem :slight_smile:

Resmin o yeşil gözüken kısımlarını silmediğiniz için komple resmi alıyor sanırım. Genelde, bir resim kullanacaksam, o resme bir katman ekler sonra da resmin çerçevesi dahil olmak üzere istenmeyen kısımları resimden kaldırırım. Bunun için GIMP kullanabilirsiniz.

place veya pack kullanmıyoruz artık. Çünkü burada widgetlerimizi canvas nesnelerinden oluşturuyoruz. create_window ile eğer başka bir tkinter widgeti ekleyecekseniz, ekleme sıranız önemli hale gelir.

Örneğin, button görevi görecek bir resim ekleyip, onun da üstüne create_window ile bir tk.Frame’i getirebilirsiniz. Ancak böyle yaparsanız button görevi görecek olan resim, frame tarafından kaplanmış olur. Ekrana yerleşecek widgetleri tasarlarken, buna dikkat etmek gerekiyor.

Aynen, ekran koordinatlarına göre nesneleri yerleştirmek lazım. Bu yöntemle maalesef place, grid ve pack metodlarını kullanamazsınız. Ama ekranın koordinatlarını kullanmak da zevkli (bence), her şeyi hesaplayarak kendiniz belirlemiş olursunuz.

1 Beğeni

Canvas ile ilk deneyimim olduğu için biraz yadırğadım herhalde zamanla alışırım :slight_smile:
spliti 3 yapıtığımda ise resmi yeşile boyuyor basılı tutarken galiba farklı bir sorun var
image
image

Boyama işlemini yapan kod parçalarını kullandığım ikon için yazmıştım, dilerseniz kaldırabilirsiniz tabi. Benim kullandığım resim, tek bir renge sahip olduğu için, resim üzerinde yapılan işlemi de ona göre ayarladım. Sizin eklediğiniz resimde çok değişik renkler var. Dolayısıyla aslında PIL kütüphanesine biraz bakarak, birçok rengi olan resimlerin renklerini nasıl değiştirebileceğinizi öğrenebilirsiniz.

img.split() 4 elemanlı bir tuple verisi döndürüyor ve her bir eleman (kanal) üzerinde yapılan değişiklik farklı sonuçlar üretiyor. Bu 4 kanal RGBA. A yani alpha şeffaflık kanalıdır. Bu yüzden denemeler yapmanız gerektiğini söylemiştim. Siz 3. tayfda (şeffaflık kanalında) bir değişiklik yaptığınız için, resmin geri kalan kısımları şeffaflaştırıldı.

Bu renk değiştirme işlemini de, kullanıcının düğmeye basıp basmadığı görsel olarak belli olsun diye eklemiştim.

1 Beğeni

Öneriler için minnettarım hepsi benim için çok değerli fakat bir şey fark ettim bilmiyorum yanlışmı anladım olayı ama sizinde bi fikrinizi almak isterim.

Tıklama işlemlerine çok takılmayın biri için aslında (Görsel açıdan )
image
bu şekilde kullanılabilir resime tıkladıgımda sabit bir biçimde duruyor herangi bir problemi yok arka planı vs. temiz şekilde ama ille bir tıklama hissiyatı verilicek olunursa tıklanan resimi anlık olarak kaldırıp yerine biraz daha büyüğü veya küçüğü eklenilebilir daha sonra resim eski haline döndürülür tıklama hissiyatı birazda olsa karşı tarafa geçebilir diye düşündüm.

1 Beğeni

Elbette, neden olmasın. :+1: Tasarımın nasıl olacağını siz belirlersiniz.

1 Beğeni

Dediğiniz yöntemi test ediyordum fakat bir soru aklıma geldi resim hariç entry,label gibi arka plan rengi olan widgetlerin arka planını nasıl temizleyebilirim ?

image

widget = tk.Label(canvas,width=20,text="Merhaba")
widget.pack()
canvas.create_window(200, 200, window=widget)

Entry’ye yazı yazılacağı için, arka plan için daha mat renkler kullanılabilir. tk.Label yerine de create_text ile yazı oluşturabilirsiniz.

1 Beğeni