Transparente Bilder in Python einfügen
@M96Wayne: Das geht nicht. Schalflächen haben immer eine Hintergrundfarbe. Was willst Du denn *eigentlich* damit erreichen?
@M96Wayne: Was bedeutet „ständig”? Man könnte schon jedes mal wenn man den Hintergrund wechselt auch ein entsprechendes Bild für die Schaltfläche erstellen.
Ich habe wahrscheinlich 50 oder mehr Hintergrundbilder, die ich da miteinbringen muss, dazu müsste ich dann ~50mal die Hintergrundfläche ändern. Ist auch nicht gerade das Wahre. Hatte gehofft man könnte es ganz Transparent machen.
@M96Wayne: Wo ist denn das Problem dabei? Wenn man den Hintergrund der Schaltfläche transparent machen könnte, dann passiert doch vom Programmablauf her genau das gleiche. Wenn man ein neues Hintergrundbild setzt, muss die Grafik auf der Schaltfläche neu berechnet werden, damit dort das neue Bild ”durchscheint” Dann gäbe es den Code schon in Tkinter. So musst Du selber ein paar Zeilen schreiben.
Die Problematik dabei ist, dass die Hintergrundbilder verschiedene Farbverläufe haben und man diese nicht als Hintergrundfarbe der Schaltfläche darstellen kann.
Ich wüsste nämlich nicht wie man von einem Bild die genau exakten Farbverläufe auf die Schaltfläche übertragen könnte.
Ich wüsste nämlich nicht wie man von einem Bild die genau exakten Farbverläufe auf die Schaltfläche übertragen könnte.
@M96Wayne: Die Hintergrundfarbe der Schaltfläche ist egal, Du setzt da ein Bild ohne Transparenz drauf, denn das Hintergrundbild ist ja nicht transparent. Was passiert muss, egal ob das nun das GUI-Toolkit für Dich machen würde oder Du das selber machst, ist den Ausschnitt vom Hintergrundbild nehmen der von der Schaltfläche verdeckt wird, da das Bild mit der Transparenz drauf klatschen, und das Ergebnis dann als Bild für die Schaltfläche verwenden. `PIL` hast du ja sowieso schon als Abhängigkeit, damit kann man diese Grafikoperationen durchführen. Das ganze kapselt man am besten in einer Klasse die eine Methode zum Setzen eines neuen Hintergrundbildes besitzt und sowohl das Bild im Hintergrund setzt als auch das Bild für die Schaltfläche neu berechnet und setzt.
Kleines Beispiel:
Code: Alles auswählen
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
from itertools import cycle
from PIL import Image, ImageTk
class PleaseFindABetterNameForThisClass(tk.Frame):
def __init__(self, master, image, button_image, command=None):
tk.Frame.__init__(self, master)
self.button_image = button_image
self.background_photo = None
self.background = tk.Label(self)
self.background.pack()
self.button_photo = None
self.button = tk.Button(self, command=command)
width, height = self.button_image.size
self.button.place(x=0, y=0, width=width, height=height)
self.set_background_image(image)
def set_background_image(self, image):
button_width, button_height = self.button_image.size
button_image = image.crop((0, 0, button_width, button_height))
button_image.paste(self.button_image, mask=self.button_image)
self.button_photo = ImageTk.PhotoImage(button_image)
self.background_photo = ImageTk.PhotoImage(image)
self.button['image'] = self.button_photo
self.background['image'] = self.background_photo
def main():
background_filenames = cycle(['test.jpg', 'test2.jpg'])
root = tk.Tk()
widget = PleaseFindABetterNameForThisClass(
root,
Image.open(next(background_filenames)),
Image.open('test.png'),
lambda: widget.set_background_image(
Image.open(next(background_filenames))
)
)
widget.pack()
root.mainloop()
if __name__ == '__main__':
main()
Wow! Vielen Dank! Bin gerade dabei das Programm langsam zu durchblicken.
Danke für die Mühe!
Edit: Wie bekomm ich es denn, wenn ich meinen Button verschiebe (x-y Koordinaten verschieden wähle, dass sich die Schaltfläche dann auch verändert?
Ist das diese Zeile?
Danke für die Mühe!
Edit: Wie bekomm ich es denn, wenn ich meinen Button verschiebe (x-y Koordinaten verschieden wähle, dass sich die Schaltfläche dann auch verändert?
Code: Alles auswählen
button_image = image.crop((0, 0, button_width, button_height))
@M96Wayne: Ja, die Zeile müsste man auch entsprechend anpassen damit der richtige Bereich aus dem Hintergrundbild für die Schaltfläche gewählt wird.
Also wenn ich das so ändere (zB):
Kommt bei mir der Fehler:
ValueError: images do not match
Code: Alles auswählen
self.button.place(x=100, y=100, width=width, height=height)
button_image = image.crop((100,100, button_width, button_height))
ValueError: images do not match
@M96Wayne: Die beiden letzten Werte in dem Tupel bei `crop()` sind nicht die Breite und die Höhe des Ausschnitts sondern die Koordinate der rechten unteren Ecke. Breite und Höhe kann man da nur einsetzen wenn die linke obere Ecke die Koordinate 0, 0 hat.
Die Überlegung ist doch eine ganz einfache: Wenn das Bild auf Position (0, 0) ist und die untere rechte Ecke sich bei (width, height) befindet, wo befindet sich dann die Ecke, wenn du das Bild auf die Position (x, y) verschiebst. Wenn du die Lösung nicht sofort siehst, dann male dir das ganze mal auf kariertem Papier auf.
Das Leben ist wie ein Tennisball.
@M96Wayne: Das Argument gibt die Koordinaten der beiden gegenüberliegenden Ecken eines Rechtecks an (x_1, y_1, x_2, y_2), wobei `x_1` und `y_1` die linke obere Ecke beschreiben und `x_2` und `y_2` die rechte untere Ecke. Wenn also das Bild auf der Schaltfläche 128 Pixel breit und hoch ist, dann schneidet man mit (0, 0, 128, 128) aus dem Hintergrundbild ganz oben links einen Bereich aus der 128 Pixel breit und hoch ist, und da wird dann das Bild für die Schaltfläche mit `paste()` drüber gelegt. Du hast jetzt aus den 0en jeweils eine 100 gemacht, das bedeutet also `crop()` wird (100, 100, 128, 128) übergeben, also ein viel kleineres Stück ausgeschnitten, das nur noch 28 Pixel breit und hoch ist, und da kann man kein 128×128 Pixel Bild drüber legen. Wenn Du beim Ausschneiden die linke obere Ecke verschiebst, dann musst Du das mit der rechten unteren ebenfalls machen, wenn der Ausschnitt gleich gross bleiben soll.
@M96Wayne: Da die 100 an zwei verschiedenen Stellen im Programm vorkommen sollte man die übrigens besser als Konstanten definieren oder den Benutzer der Klasse als Argumente (möglicherweise mit Default-Werten) übergeben lassen. Sonst muss man wenn man diesen Wert mal ändern will, daran denken auch alle Vorkommen zu verändern, statt nur an einer zentralen Stelle den Wert einmal zu ändern.
Wie kann ich das dann ändern würde es nämlich dann so machen:
Bloß weiß ich halt nich wie man das dann definiert bzw umsetzt, aber vom Prinzip her ist es ja richtig. Man müsste nur noch x bzw k irgendwo eingeben können
Code: Alles auswählen
self.button.place(x=k, y=f, width=width, height=height)
button_image = image.crop((k, f, button_width+k,button_height+f))
@M96Wayne: Man könnte die Werte wie gesagt als Argumente übergeben lassen wenn so ein `PleaseFindABetterNameForThisClass`-Exemplar erzeugt wird. Da die in der anderen Methode benötigt werden, gehören sie zum Zustand des Objekts, müssen also als Attribute gesetzt werden. Und auf jeden Fall unter besseren Namen als `k` und `f`.