Bildeinbinden, komische Fehlermeldung

Fragen zu Tkinter.
Antworten
jasmin.mrcr
User
Beiträge: 8
Registriert: Sonntag 25. Juni 2023, 19:25

Hallo ich brauche dringend Hilfe,

ich möchte mit tkinter ein Bild in der GUI einfügen, ich habe es schon mit gifs und normalen Bildern probiert.
In einem seperaten Skript funktioniert es auch, aber nicht in meinem großen skript wo ich es brauche.
Ich verstehe die Fehlermeldung dazu auch nicht ganz.
Kann ich auch wenn ein Knopf gedrückt wird ein anderes skript ausführen lassen?
Das ist der code wo ich auf das Bild zugreifen möchte und in einem anderen Skrip funktioniert es auch

Code: Alles auswählen

def sonder():
    sonder = Tk()
    sonder.title("Gameshow")  # Titel des Fensters oben
    sonder.geometry("1250x690")

    oben = ttk.Label(sonder, text="100 Punkte", font=("Times", 18, "italic"), padding=20)
    oben.pack(side="top")
    farbe = Label(sonder, bg="black")
    farbe.pack(side="top", fill="x")

    global img1
    img1 = PhotoImage(file="Dosenwerfen.jpg")
    b1 = Label(sonder, image=img1)
    b1.pack()

    sonder.mainloop()
Das ist die Fehlermeldung:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\jasmi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "F:\PyCharm Workspace\Gameshow\main.py", line 620, in sonder
    img1 = PhotoImage(file="Dosenwerfen.jpg")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\jasmi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 4130, in __init__
    Image.__init__(self, 'photo', name, cnf, master, **kw)
  File "C:\Users\jasmi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 4075, in __init__
    self.tk.call(('image', 'create', imgtype, name,) + options)
_tkinter.TclError: couldn't recognize data in image file "Dosenwerfen.jpg"
Kann mir da jemand helfen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Laut der allwissenden Muellhalde solltest du besser mit Pillow arbeiten, das kann die Formate verstehen, und liefert ein Bild, mit dem tkinter dann was anfangen kann: https://stackoverflow.com/questions/239 ... 5#23905585
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@jasmin.mrcr: Anmerkungen zum Quelltext: Man sollte in Funktionen nicht den Namen der Funktion lokal an etwas anderes binden. Das ist verwirrend.

Wobei weder die Funktion noch das Hauptfenster `sonder` heissen sollten. Funktionen (und Methoden) werden in der Regel nach der Tätigkeit benannt die sie durchführen, damit der Leser weiss was da gemacht wird, und um die Funktion/Methode leichter von eher passiven Werten unterscheiden zu können.

Der Quelltext lässt vermuten, dass da ein Sternchen-Import aus `tkinter` gemacht wurde. Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 140 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser vermitteln was der Wert dahinter im Programm bedeutet, nicht zum rätseln zwingen.

Man nummeriert keine Namen. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen/-werte verwenden, sondern eine Datenstruktur. Oft eine Liste.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Ob der Fenstertitel oben angezeigt wird weiss man auch gar nicht. Das ist Aufgabe der Fensterverwaltung.

Fenstergrössen ergeben sich aus dem Fensterinhalt und werden nicht absolut vorgegeben.

Bitte ``global`` gleich wieder vergessen. Das hat in einem sauberen Programm nichts zu suchen. Was eine Funktion/Methode benötigt wird als Argument übergeben und Ergebnisse als Rückgabewerte an den Aufrufer zurückgegeben. Wenn man sich Zustand über Aufrufe hinweg merken muss, braucht man objektorientierte Programmierung. Für jedes nicht-triviale GUI-Programm wird man Klassen schreiben müssen.

Ungetestet:

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk

from PIL import Image, ImageTk


def show_main_window():
    main_window = tk.Tk()
    main_window.title("Gameshow")

    ttk.Label(
        main_window,
        text="100 Punkte",
        font=("Times", 18, "italic"),
        padding=20,
    ).pack()
    tk.Label(main_window, bg="black").pack(fill=tk.X)
    image = ImageTk.PhotoImage(Image.open("Dosenwerfen.jpg"))
    tk.Label(main_window, image=image).pack()

    main_window.mainloop()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
jasmin.mrcr
User
Beiträge: 8
Registriert: Sonntag 25. Juni 2023, 19:25

__blackjack__ hat geschrieben: Montag 26. Juni 2023, 12:23 @jasmin.mrcr: Anmerkungen zum Quelltext: Man sollte in Funktionen nicht den Namen der Funktion lokal an etwas anderes binden. Das ist verwirrend.

Wobei weder die Funktion noch das Hauptfenster `sonder` heissen sollten. Funktionen (und Methoden) werden in der Regel nach der Tätigkeit benannt die sie durchführen, damit der Leser weiss was da gemacht wird, und um die Funktion/Methode leichter von eher passiven Werten unterscheiden zu können.

Der Quelltext lässt vermuten, dass da ein Sternchen-Import aus `tkinter` gemacht wurde. Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 140 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser vermitteln was der Wert dahinter im Programm bedeutet, nicht zum rätseln zwingen.

Man nummeriert keine Namen. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen/-werte verwenden, sondern eine Datenstruktur. Oft eine Liste.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Ob der Fenstertitel oben angezeigt wird weiss man auch gar nicht. Das ist Aufgabe der Fensterverwaltung.

Fenstergrössen ergeben sich aus dem Fensterinhalt und werden nicht absolut vorgegeben.

Bitte ``global`` gleich wieder vergessen. Das hat in einem sauberen Programm nichts zu suchen. Was eine Funktion/Methode benötigt wird als Argument übergeben und Ergebnisse als Rückgabewerte an den Aufrufer zurückgegeben. Wenn man sich Zustand über Aufrufe hinweg merken muss, braucht man objektorientierte Programmierung. Für jedes nicht-triviale GUI-Programm wird man Klassen schreiben müssen.

Ungetestet:

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk

from PIL import Image, ImageTk


def show_main_window():
    main_window = tk.Tk()
    main_window.title("Gameshow")

    ttk.Label(
        main_window,
        text="100 Punkte",
        font=("Times", 18, "italic"),
        padding=20,
    ).pack()
    tk.Label(main_window, bg="black").pack(fill=tk.X)
    image = ImageTk.PhotoImage(Image.open("Dosenwerfen.jpg"))
    tk.Label(main_window, image=image).pack()

    main_window.mainloop()
Danke für die vielen Tipps, ich habe mir das auch erst in den letzten Wochen beigebracht.
Der Code von dir funktioniert in einem einzelnen skript, aber eins zu eins in meinem längeren nicht (hab nicht alles mitgeschickt weil das über 1000 zeilen code sind, sonder immer nur das wo die Fehlermeldungen auftauchen)
Ich habe es auch alles wieder geändert mit tk. davor das müsste passen dazu zeigt er mir auch kein Fehler an

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\jasmi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "F:\PyCharm Workspace\Gameshow\main.py", line 638, in show_main_window
    tk.Label(main_window, image=image).pack()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\jasmi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 3214, in __init__
    Widget.__init__(self, master, 'label', cnf, kw)
  File "C:\Users\jasmi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 2628, in __init__
    self.tk.call(
_tkinter.TclError: image "pyimage1" doesn't exist
Das ist die Fehlermeldung noch und ich hab genau das von dir genutzt
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn es in dem längeren Skript nicht funktioniert, dann müßtest Du das längere Skript so zusammenstreichen, bis Du es hier posten kannst, und es immer noch den Fehler zeigt.

Wenn ich meine Kristallkugel richtig verstehe, dann hast Du mehr als eine tk.Tk-Instanz, davon darf es aber nur eine geben, weitere Fenster macht man mit tk.Toplevel.
jasmin.mrcr
User
Beiträge: 8
Registriert: Sonntag 25. Juni 2023, 19:25

Sirius3 hat geschrieben: Dienstag 27. Juni 2023, 11:00 Wenn es in dem längeren Skript nicht funktioniert, dann müßtest Du das längere Skript so zusammenstreichen, bis Du es hier posten kannst, und es immer noch den Fehler zeigt.

Wenn ich meine Kristallkugel richtig verstehe, dann hast Du mehr als eine tk.Tk-Instanz, davon darf es aber nur eine geben, weitere Fenster macht man mit tk.Toplevel.
Wie meinst du das mit mehreren tk.Tk-Instanzen? mehrere Fenster?
Ja ich habe ein Fenster mit mehreren Buttons für eine Gameshow mit Kategorien und verschiedenen Punkten und beim klicken öffnet sich dann jeweils ein neues Fenster mit einer Aufgabe.
und das mit dem Bild ist ein Minispiel und ich wollte das so anschaulich darstellen.
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

steht in deinem Code, mit dem du die weiteren Fenster beschreibst sowas wie "fenster = tk.Tk()"?
Wenn ja dann hast du eine weitere Instanz von "tk.Tk()" angelegt.
Das wird hier im Forum öfters besprochen, da müssten sich einige Beispiele mit "Toplevel" finden lassen.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
jasmin.mrcr
User
Beiträge: 8
Registriert: Sonntag 25. Juni 2023, 19:25

Dennis89 hat geschrieben: Dienstag 27. Juni 2023, 11:43 Hallo,

steht in deinem Code, mit dem du die weiteren Fenster beschreibst sowas wie "fenster = tk.Tk()"?
Wenn ja dann hast du eine weitere Instanz von "tk.Tk()" angelegt.
Das wird hier im Forum öfters besprochen, da müssten sich einige Beispiele mit "Toplevel" finden lassen.

Grüße
Dennis
okay dankeschön
ja das habe ich, die anderen Fenster funktionieren aber ohne Probleme, wie kann ich das umgehen?
gibt es eine Funktion die ein anderes Skript ablaufen lässt?
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

du wirst nicht drum herum kommen hier ein Minimalbeispiel zu posten, dass den Fehler zeigt.
So kann man nur sagen, dass du deine weiteren Fenster mit "toplevel" erstellen musst. Das folgende Mini-Beispiel wirst du vermutlich nicht auf deinen Code anwenden können, aber es zeigt ein Hauptfenster und bei Bedarf ein weiteres mit Toplevel.

Noch ein Hinweis, wenn etwas arg mehr hinter deinem Programm streckt, wie mein Mini-Beispiel (Das ich übrigens mal hier über die Suche gefunden habe), dann wirst du für dein GUI eine Klasse benötigen und kommst mit einfachen Funktionen nicht mehr aus.

Code: Alles auswählen

from functools import partial
import tkinter as tk


def open_window(root):
    tk.Toplevel(root)


def main():
    root = tk.Tk()
    tk.Button(root, text="Open new window", command=partial(open_window, root)).pack()
    root.mainloop()


if __name__ == "__main__":
    main()
Wobei du die Toplevel-Instanz im richtigen Code an einen Namen binden musst, damit du damit arbeiten kannst.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@jasmin.mrcr: Die funktionieren nicht ohne Probleme. Dir sind die Probleme nur noch nicht aufgefallen. Die Lösung ist `tkinter.Tk` für das Hauptfenster zu nehmen und `tkinter.Toplevel` für weitere Fenster.

Wobei mein Bauchgefühl sagt, dass es wahrscheinlich gar keine weiteren Fenster geben soll, und hier ”bildschirmfüllende” Fenster verwendet werden, um das Hauptfenster mit anderen Informationen zu verdecken. Also in der Hoffnung, dass das mit den Pixelabmessungen funktioniert. Das tut es aber nicht wirklich. Dafür würde man eigentlich Dialoge verwenden die nicht alles verdecken, aber modal sind, also Eingaben im Hauptfenster verhindern. Für Dialoge gibt es eine Basisklasse in der Standardbibliothek. Oder man stellt das alles im Hauptfenster dar. Beispielsweise in dem man mehrere Frames mit den verschiedenen Inhalten alle in die gleiche `grid()`-Zelle packt und dann mit der `lift()`-Methode dafür sorgt, dass der passende Frame ”oben” liegt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
jasmin.mrcr
User
Beiträge: 8
Registriert: Sonntag 25. Juni 2023, 19:25

Danke an euch allen!!
es funktioniert jetzt alles mit dem Hauptfenster tk-Instanzen und alle weitere Toplevel - Instanzen zu verwenden :)
das mit den füllenden Dialogen werde ich auf jeden fall auch nochmal ausprobieren, hört sich auch sehr sinnvoll an.
Antworten