Problem bei Buttons mit Bildern

Fragen zu Tkinter.
Antworten
BluePhoenix
User
Beiträge: 3
Registriert: Sonntag 12. September 2010, 17:45

Hallo,
ich habe ein kleines aber feines Problem. Ich wollte einem Button ein Bild zuweisen und habe dazu zum Testen folgenden Code benutzt:

Code: Alles auswählen

import Tkinter as tk

hf=tk.Tk()
mf=tk.Frame(hf)
photo=tk.PhotoImage(file="E:\\MyProggs\\ContactList\\ctl\\Images\\Add_Entry.gif")
b=tk.Button(mf, bg="black", foreground="blue", activeforeground="yellow", activebackground="black", font="Verdana")
b.config(image=photo)
b.pack()

mf.pack()
hf.mainloop()
Hat soweit super funktioniert, aber wenn ich diesen Code in das eigentliche Programm einbinde, erscheint auf dem Button kein Bild sondern nichts. Außerdem ist der Knopf dann nicht mehr anklickbar, aber es wird keine Fehlermeldung ausgegeben.

Auszug aus dem Hauptprogramm:

Code: Alles auswählen

def dButton(mf, text='', x=0, y=0, w=100, h=20, fg=standardbuttonfg, bg=standardbuttonbg, afg=standardbuttonafg, abg='', command='', font='Arial %s' %(standardschriftgroesse), width=-1, border=1, anchor='center', focus=0, indicatoron=0, selectcolor=standardbuttonafg, image=""):
    if width!=-1:
        w=width
    if abg=='':
        abg=bg

    b=tk.Button(mf, text=text, bg=bg, foreground=fg, activeforeground=afg, activebackground=abg, font=font, command=command)
    b.place(x=x, y=y, width=w, height=h)
    if image != "":
        photo=tk.PhotoImage("Image\\"+image)
        b.config(image=photo)
    if focus==1:
        b.focus_set()
        
    return b
(Anmerkung: mf ist die tk.Frame-Instanz)
Und der entsprechende Aufruf:

Code: Alles auswählen

dButton(mf, image="Add_Entry.gif", w=300, h=40, x=0, y=0, command=lambda: Add(mf))
    

Jetzt die Frage: Was ist falsch?

Liebe Grüße,
ein verwirrter Python-Nutzer
BlackJack

@BluePhoenix: Du musst auf der Python-Seite eine Referenz auf das Bildobjekt behalten. Wenn Python darauf keine Referenz mehr hat und das Objekt im Speicher freigibt, ist das auch von Tk nicht mehr verwendbar.

Von `place()` sollte man übrigens die Finger lassen. Das ist nur in sehr wenigen Ausnahmefällen die richtige Vorgehensweise.
BluePhoenix
User
Beiträge: 3
Registriert: Sonntag 12. September 2010, 17:45

BlackJack hat geschrieben:@BluePhoenix: Du musst auf der Python-Seite eine Referenz auf das Bildobjekt behalten. Wenn Python darauf keine Referenz mehr hat und das Objekt im Speicher freigibt, ist das auch von Tk nicht mehr verwendbar.
Und wie macht man das?
BlackJack

@BluePhoenix: Mit so einer Funktion? Gute Frage. Man könnte das `PhotoImage`-Exemplar an das `Button`-Exemplar binden und dokumentieren, dass der Aufrufer entweder dafür sorgen muss, dass eine Referenz auf den `Button` weiterhin besteht, oder dass er zumindest das `PhotoImage`-Attribut am Leben erhalten muss.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo BluePhoenix,

Du musst aus Deinen Bildern schon innerhalb des "mainloops" ein "TkImage" erzeugen. Alle Deine später verwendeten Bilder müssen auch "TkImages" sein. Erstelle eine list oder dict und werfe dort Deine Bilder als "TkImage" rein. Falls Du die Bilder in einer "Extraklasse" erzeugst, müssen sie auch dort als "TkImage" generiert werden. Das ist meine Erfahrung mit Bildern und Tkinter, evt. geht es auch anders, doch ich habe es nur so zum Laufen gebracht.

Gruß Frank
BluePhoenix
User
Beiträge: 3
Registriert: Sonntag 12. September 2010, 17:45

Hallo Kaytec,
es hat zwar ein bischen gedauert, aber letzten Endes habe ich das Problem so wie du es beschrieben hast gelöst bekommen.
Vielen Dank für die schnelle Hilfe euch beiden.

Liebe Grüße,
BluePhoenix
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo BluePhoenix,

BlackJack hat immer recht, doch er kann es nicht immer "lowlevel" erklären - oder er will es nicht ! :D

Gruß Frank
Antworten