Bild in Tkinter wird nicht angezeigt

Fragen zu Tkinter.
Antworten
thorsten160970
User
Beiträge: 3
Registriert: Montag 6. Februar 2017, 17:43
Wohnort: Berlin

Hallo und "Guten Tag" zusammen,
Als Python - Neuling probiere ich in einem Label eine .jpg Datei anzuzeigen.
Nach einem Klick au den Button kann man ein Bild auswählen, welches in der linken seite Fensters angezeigt werden soll.
( Die links / rechts Aufteilung ist nur zum Testen). Das rechts angezeigte Bild mit angegeben Pfad funktioniert.

Der Dateiname stimmt, denke ich soweit, wenn ich ihn als 'text' im label anzeigen lasse.

Als 'image' wird es "leer" angezeigt und der Button ist verschwunden, d.h. keine Fehlermeldung.

Über Hilfe, wo der Fehler liegt wäre ich sehr dankbar.

Hier mal der Code:

Code: Alles auswählen

from tkinter import *
from tkinter.filedialog import askopenfilename
from PIL import ImageTk, Image

# Ereignisbehandlung
def buttonNullClick():

# show askopenfilename dialog without the Tkinter window
# default is all file types
    file_name = askopenfilename()
    rose = Image.open(file_name)
    bild = ImageTk.PhotoImage(rose)

#-------------------------------------------------------------------------------
    w2 = Label(root, text = bild).pack(side="left")
#    w2 = Label(root, image = bild).pack(side="left")

#-------------------------------------------------------------------------------

root = Tk()
root.title('Schnaufis Fenster')
root.geometry('600x600')
logo = PhotoImage(file="c:/1.gif")

w1 = Label(root, image=logo, text=logo).pack(side="right")

# Button
buttonNull = Button(master=root, text='Bild', bg='#FBD975', command=buttonNullClick)
buttonNull.place(x=5, y=5, width=50, height=30)

root.mainloop()
Zuletzt geändert von Anonymous am Montag 6. Februar 2017, 19:01, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
La surexpression du chaperon a empГЄchГ© le sorafГ©nib sildГ©nafil ou le pazopanib sildГ©nafil l'insuline et le niveau de lipides via la prГ©vention de l'inflammation hГ©patique et l'amГ©lioration de la rГ©sistance Г  l'insuline.
BlackJack

@thorsten160970: Die Links/Rechts-Aufteilung dürfte der Grund sein warum die Schaltfläche verschwindet — nämlich *hinter* dem Links angezeigten Bild. `place()` ist keine gute Idee und bei `pack()` sollte man sich innerhalb eines Container-Widgets auf *einen* Wert für alle darin angeordneten Widgets beschränken. Sonst wird es schnell schwierig das Verhalten der UI vorherzusagen.

Das Problem mit dem geladenen Bild ist, dass man auf Python-Seite eine Referenz darauf behalten muss, denn Python hat keine Ahnung ob das auf Tk-Seite noch benötigt wird und räumt das Objekt sonst aus dem Speicher. Also wenn `bild` nach Ablauf der `buttonNullClick()`-Funktion nicht mehr vorhanden ist.

Bei GUI-Programmierung kommt man um objektorientierte Programmierung (OOP) in Python nicht wirklich herum, und so löst man das dann in der Regel auch: das Bild an das Objekt binden das die GUI, beziehungsweise den GUI-Teil, modelliert.
thorsten160970
User
Beiträge: 3
Registriert: Montag 6. Februar 2017, 17:43
Wohnort: Berlin

Danke für Deine Antwort.
Nur verstehe ich das nicht so recht.

Das Bild liegt doch in einer Variable (logo = bild) und ist somit doch "gebunden"

Um das ganze zu verstehen ein neuer Versuch,, der daran scheitert das ich den Inhalt des Labels nicht aktuell bekomme... denke ich. :(

Code:

Code: Alles auswählen

from tkinter import *
from tkinter.filedialog import askopenfilename
from PIL import ImageTk, Image

# Ereignisbehandlung
def buttonNullClick():

# show askopenfilename dialog without the Tkinter window
# default is all file types
    file_name = askopenfilename()
    rose = Image.open(file_name)
    bild = ImageTk.PhotoImage(rose)
    logo = bild
#-------------------------------------------------------------------------------
    w = Label(root, 
          compound = TOP,
          text=Text, 
          image = logo)
    w.pack()

#-------------------------------------------------------------------------------

root = Tk()
root.title('Schnaufis Fenster')
root.geometry('600x600')
logo = PhotoImage(file="c:/1.gif")

Text = """Ein Bild"""
w = Label(root, 
          compound = TOP,
          text=Text, 
          image=logo)
w.pack()
# Button
buttonNull = Button(master=root, text='Bild', bg='#FBD975', command=buttonNullClick)
buttonNull.place(x=5, y=5, width=50, height=30)

root.mainloop()
Was verstehe ich daran nicht ?!
Zuletzt geändert von Anonymous am Montag 6. Februar 2017, 20:22, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
La surexpression du chaperon a empГЄchГ© le sorafГ©nib sildГ©nafil ou le pazopanib sildГ©nafil l'insuline et le niveau de lipides via la prГ©vention de l'inflammation hГ©patique et l'amГ©lioration de la rГ©sistance Г  l'insuline.
BlackJack

@thorsten160970: Du hast das Problem nur auf einen anderen/weiteren Namen verschoben. Sowohl `bild` als auch `logo` existieren nach Abarbeitung der `buttonNullClick()`-Funktion nicht mehr. Im ersten Code war es nur `bild`. Man muss das Bild an etwas binden was die Funktionsabarbeitung ”überlebt” und das ist normalerweise ein Fall für OOP wo man das Bild dann an das Objekt bindet auf dem die Methoden aufgerufen wurde.

Auf Modulebene steht üblicherweise auch nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht in der Regel in einer Funktion die `main()` heisst und nur aufgerufen wird, wenn das Modul als Programm ausgeführt wird, aber nicht wenn es als Modul importiert wird. Das erreicht man mit folgendem Idiom:

Code: Alles auswählen

if __name__ == '__main__':
    main()
thorsten160970
User
Beiträge: 3
Registriert: Montag 6. Februar 2017, 17:43
Wohnort: Berlin

Danke Dir, werde mich dann mal mit funktionen befassen !
La surexpression du chaperon a empГЄchГ© le sorafГ©nib sildГ©nafil ou le pazopanib sildГ©nafil l'insuline et le niveau de lipides via la prГ©vention de l'inflammation hГ©patique et l'amГ©lioration de la rГ©sistance Г  l'insuline.
Der_Scripter
User
Beiträge: 26
Registriert: Sonntag 1. September 2019, 15:32

Hallo,
Habe das selbe Problem.

Code: Alles auswählen

from Tkinter import *

class fenster():
    def __init__(self):
        self.root = Tk()
        self.root.title("")
        self.root["background"]="#E6E6E6"
        self.root.iconbitmap(r"[i]Dateipfad[/i]")
        self.root.resizable(False, False)
        self.root.wm_geometry("%dx%d"  % (613,445))
        self.root.wm_geometry("+%d+%d" % (330,257))
        self.bild()
        self.root.mainloop()

    def bild(self):
        bild = PhotoImage(file="[i]GIFdatei[/i].gif")
        self.Label3 = Label(self.root, image=bild)
        self.Label3.place(x = 190, y = 130)

f = fenster()
Bei diesem Code funktioniert das ganze aber:

Code: Alles auswählen

from Tkinter import *
tk = Tk()
tk.title("Foto")
canvas = Canvas(tk, width=800, height=400)
canvas.pack()

foto = PhotoImage(file=("[i]GIFdatei[/i].gif"))
canvas.create_image(0,0,anchor=NW, image=foto)
tk.mainloop()
Hoffe mir kann jemand helfen.
Der_Scripter
Python ist Cool!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du das selbe Problem hast, kannst Du ja auch die selbe Lösung verwenden:
BlackJack hat geschrieben: Montag 6. Februar 2017, 20:29 Man muss das Bild an etwas binden was die Funktionsabarbeitung ”überlebt” und das ist normalerweise ein Fall für OOP wo man das Bild dann an das Objekt bindet auf dem die Methoden aufgerufen wurde.
Zum Code:
- Verwende Python3, statt Python2
- Keine *-Importe, tkinter wird üblicherweise als `import tkinter as tk` eingebunden und alle Namen über tk.xyz angesprochen.
- Klassen schreibt man nach Konvention mit Großem AnfangsBuchstaben.
- __init__ sollte eine Instanz initialisieren, und dann zurückkehren und nicht niemals zurückkehren. mainloop gehört da nicht rein.
- Methodennamen sollten Tätigkeiten ausdrücken, `bild` ist keine. Die Methode an sich ist auch unsinnig, da das, was da drinsteht nach __init__ gehört.
Der_Scripter
User
Beiträge: 26
Registriert: Sonntag 1. September 2019, 15:32

1. Wir haben in der Schule nur Python 2 und ich möchte nicht jedesmal die Syntax ändern.

Und die restlichen Fehler: Ok ich bin noch Anfänger. Habe auch nicht den ganzen sondern nur den relevanten Teil des Programms geschickt.
Deshalb auch die Funktion. Das Problem(das habe ich öfter wäre über eine elegante Lösung froh) ist, dass ich das Fenster ändern und wieder zurückändern will. Also destroy() ich alles und gestalte es neu. Dan nach kann ich __init__ nicht mehr aufrufen, weil sich sonst ein neues Fenster öffnet.

Habe das Bild jetzt in die __init__ getan, wo es auch angezeigt wird. Aber wenn ich jetzt das was (oben nicht aber bei mir schon) aufrufen will, wie erzeuge ich das Bild dann wieder. Oder sollte ich es zwischendurch unsichtbar machen?
Python ist Cool!
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt das Bild neu zu erzeugen, kannst und solltest du dir das Bild halt merken. Das ist wie schon mehrfach in diesem Thread angesprochen die Ursache fuer dein Problem. Das es jetzt in __init__ klappt liegt nur daran, dass das wegen des Aufrufs von mainloop nie verlassen wird.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Was meinst Du mit „ändern und wieder zurückändern”?
Wenn Du mehrere Ansichten hast, solltest Du über Frames nachdenken, die man auch wieder als Klassen modelieren könnte.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Der_Scripter: Dann sollte Deine Schule mal auf Python 3 aktualisieren, denn Python 2 wird nicht mehr lange unterstützt: https://pythonclock.org/

Und das gilt nicht nur für Python 2 selbst, sondern auch so einige Bibliotheken und Projekte die ab Januar den Support einstellen. Einige sind bereits für Python 2 schon jetzt nur noch im Bugfix-Modus für ältere Versionen, das heisst die aktuellen Versionen gibt es bereits nur noch für Python 3: https://python3statement.org/

Du könntest übergangsweise auch so programmieren, dass es unter Python 2 und Python 3 läuft. Das haben viele Projekte in der Übergangszeit gemacht, auch wenn es IMHO ein bisschen sehr spät ist damit jetzt anzufangen, zumindest bei neuen Projekten.

Das mit dem `destroy()`\en und immer wieder neu aufbauen von Fensterinhalten klingt sehr ungewöhnlich. Dann verändert sich ja auch dauernd die Fenstergrösse. Es sei denn man macht solchen Unsinn wie `place()` zu verwenden… Oh warte…
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Der_Scripter
User
Beiträge: 26
Registriert: Sonntag 1. September 2019, 15:32

__blackjack__ hat geschrieben: Montag 2. September 2019, 16:45 @Der_Scripter: Dann sollte Deine Schule mal auf Python 3 aktualisieren, denn Python 2 wird nicht mehr lange unterstützt: https://pythonclock.org/

Und das gilt nicht nur für Python 2 selbst, sondern auch so einige Bibliotheken und Projekte die ab Januar den Support einstellen. Einige sind bereits für Python 2 schon jetzt nur noch im Bugfix-Modus für ältere Versionen, das heisst die aktuellen Versionen gibt es bereits nur noch für Python 3: https://python3statement.org/
Habe schon mit dem Systemadmin gesprochen, dass problem ist, dass die Aufgaben für die Schüler haben, die nur in Python 2 funktionieren.
Sirius3 hat geschrieben: Montag 2. September 2019, 16:43 Was meinst Du mit „ändern und wieder zurückändern”?
Wenn Du mehrere Ansichten hast, solltest Du über Frames nachdenken, die man auch wieder als Klassen modelieren könnte.
Habe mich noch nicht mit Frames beschäftigt (wie gesagt bin Anfänger). Ich meine z.B. dass man ein Hauptmenü hat dort kann man auf einen Button klicken der führt auf eine andere Seite und von da aus kann man durch einen zurück Button wieder ins Hauptmenü.
Vielleicht so wie die Dateien Index und so weiter in html, wenn du weißt was ich meine :D .
Python ist Cool!
Der_Scripter
User
Beiträge: 26
Registriert: Sonntag 1. September 2019, 15:32

Habe jetzt eine improvisierte Lösung: self.forget_place().
Aber wie kann ich jetzt das ganze wieder sichtbar machen?
Python ist Cool!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Der_Scripter hat geschrieben: Montag 2. September 2019, 17:03 Habe schon mit dem Systemadmin gesprochen, dass problem ist, dass die Aufgaben für die Schüler haben, die nur in Python 2 funktionieren.
Um so schlimmer, dass Aufgaben nicht regelmäßig aktualisiert werden.

Wenn ›place_forget‹ ein ›place‹ rückgängig macht, was wird dann wohl ›place_forget‹ rückgängig machen?
Der_Scripter
User
Beiträge: 26
Registriert: Sonntag 1. September 2019, 15:32

Hab ich auch schon raus gefunden >place<
Danke, klappt jetzt
Python ist Cool!
Antworten