Python smbclient Bild im TKinter Label anzeigen

Fragen zu Tkinter.
Antworten
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

Hallo zusammen,

ich habe auf meinen Fileserver Bilder, welche ich gerne in einem Label anzeigen lassen will. Leider bekomme ich immer wieder die Fehlermeldung, dass der Pfad nicht existiert, obwohl dies der Fall ist.

Gibt es noch eine andere Möglichkeit Bilder von einem Fileserver zuladen und dies dann in einem Label anzuzeigen?

Oder kann mir jemand sagen, was ich an meinen Code verändern muss, damit es funktioniert?

file = smbclient.open_file("\\Server/"+picture,username=username,password=password)

root = tk.Tk()
root.configure(background='black')
sheight = root.winfo_screenheight()
swidth = root.winfo_screenwidth()

root.minsize(width=swidth, height=sheight)
root.maxsize(width=swidth, height=sheight)

l = tk.Label()
l.place(x=0, y=0, width=swidth, height=sheight, anchor="center")

image: Image = Image.open(file.name)
img2 = ImageTk.PhotoImage(image)
l.config(image=img2)
root.mainloop()


Vielen Dank
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PotterParsel: Nein, den Pfad gibt es nicht. `Image.open()` sucht den in Deinem System und wenn dort nicht unter dem Pfad das SMB-Share eingebunden ist und das System überhaupt solche Dateinamen/-pfade versteht, dann gibt es die Datei dort nicht. Wenn es die dort gäbe, wäre es auch unsinnig `smbclient` zu verwenden, weil man dann ja auch einfach so, ohne diese Bibliothek darauf zugreifen könnte.

`Image.open()` kann man ein Dateiobjekt übergeben. Das muss im Binärmodus geöffnet worden sein und `seek()`, `tell()`, und `read()` unterstützen.

Dateien die man öffnet, sollte man auch explizit wieder schliessen. Am besten in dem man die ``with``-Anweisung verwendet. Wird auch in der Dokumentation von `smbclient.open_file()` empfohlen.

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. Wenn man `screen_` meint, sollte man nicht nur `s` schreiben, und `l` ist nicht nur absolut nichtssagend, sondern kann in vielen Schriftarten, auch noch einfach mit 1 verwechselt werden. Namen nummeriert man auch nicht. Dann will man sich entweder bessere Namen ausdenken, oder gar keine Einzelname und -werte verwenden, sondern eine Datenstruktur. Oft eine Liste. Oder vielleicht auch nicht jedes kleine Zwischenergebnis an einen eigenen Namen binden.

Die Fenstergrösse so festzulegen ist nicht wirklich sinnvoll. Das sieht eher so aus, als sollte das Fenster „full screen“ dargestellt werden.

Man sollte sich bei Anzeigeelementen nicht darauf verlassen, dass `master` implizit das Hauptfenster ist, wenn man da nichts angibt.

Wenn man Tk-Argumente hat, die eine besondere Bedeutung haben und deshalb als Konstante im `tkinter`-Modul definiert sind, sollte man diese Konstante benutzen, statt eine literale Zeichenkette mit dem Wert.

Das Bild hätte man vor dem erstellen des `Label` laden können und sich den extra `config`-Aufruf sparen können.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk

import smbclient
from PIL import Image, ImageTk


def main():
    ...

    root = tk.Tk()
    root.configure(background="black")
    root.attributes("-fullscreen", True)

    with smbclient.open_file(
        fR"\Server/{picture}", username=username, password=password
    ) as file:
        image = ImageTk.PhotoImage(Image.open(file))
    
    tk.Label(root, image=image).place(x=0, y=0, anchor=tk.CENTER)

    root.mainloop()


if __name__ == "__main__":
    main()

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

__blackjack__ hat geschrieben: Montag 5. September 2022, 10:28 @PotterParsel: Nein, den Pfad gibt es nicht. `Image.open()` sucht den in Deinem System und wenn dort nicht unter dem Pfad das SMB-Share eingebunden ist und das System überhaupt solche Dateinamen/-pfade versteht, dann gibt es die Datei dort nicht. Wenn es die dort gäbe, wäre es auch unsinnig `smbclient` zu verwenden, weil man dann ja auch einfach so, ohne diese Bibliothek darauf zugreifen könnte.

`Image.open()` kann man ein Dateiobjekt übergeben. Das muss im Binärmodus geöffnet worden sein und `seek()`, `tell()`, und `read()` unterstützen.

Dateien die man öffnet, sollte man auch explizit wieder schliessen. Am besten in dem man die ``with``-Anweisung verwendet. Wird auch in der Dokumentation von `smbclient.open_file()` empfohlen.

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. Wenn man `screen_` meint, sollte man nicht nur `s` schreiben, und `l` ist nicht nur absolut nichtssagend, sondern kann in vielen Schriftarten, auch noch einfach mit 1 verwechselt werden. Namen nummeriert man auch nicht. Dann will man sich entweder bessere Namen ausdenken, oder gar keine Einzelname und -werte verwenden, sondern eine Datenstruktur. Oft eine Liste. Oder vielleicht auch nicht jedes kleine Zwischenergebnis an einen eigenen Namen binden.

Die Fenstergrösse so festzulegen ist nicht wirklich sinnvoll. Das sieht eher so aus, als sollte das Fenster „full screen“ dargestellt werden.

Man sollte sich bei Anzeigeelementen nicht darauf verlassen, dass `master` implizit das Hauptfenster ist, wenn man da nichts angibt.

Wenn man Tk-Argumente hat, die eine besondere Bedeutung haben und deshalb als Konstante im `tkinter`-Modul definiert sind, sollte man diese Konstante benutzen, statt eine literale Zeichenkette mit dem Wert.

Das Bild hätte man vor dem erstellen des `Label` laden können und sich den extra `config`-Aufruf sparen können.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk

import smbclient
from PIL import Image, ImageTk


def main():
    ...

    root = tk.Tk()
    root.configure(background="black")
    root.attributes("-fullscreen", True)

    with smbclient.open_file(
        fR"\Server/{picture}", username=username, password=password
    ) as file:
        image = ImageTk.PhotoImage(Image.open(file))
    
    tk.Label(root, image=image).place(x=0, y=0, anchor=tk.CENTER)

    root.mainloop()


if __name__ == "__main__":
    main()

Danke für deine Hilfestellung. Du hast mit deinen Punkten recht, sauberer Code sieht anders aus.

Leider bekomme ich auch mit deinen Code die gleiche Fehlermeldung. Hättest du spontan noch eine andere Idee oder Methode um das zu realisieren?
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

Bitte poste die komplette Fehlermeldung inklusive Traceback, statt nur den Fehler zu umschreiben.
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

Sirius3 hat geschrieben: Montag 5. September 2022, 14:27 Bitte poste die komplette Fehlermeldung inklusive Traceback, statt nur den Fehler zu umschreiben.
ich bekomme Folgende Fehlermeldung:

Code: Alles auswählen

File "/home/pi/Desktop/test.py", line 26, in main
    image = ImageTk.PhotoImage(Image.open(file.name))
  File "/home/pi/.local/lib/python3.9/site-packages/PIL/Image.py", line 3092, in open
    fp = builtins.open(filename, "rb")
FileNotFoundError: [Errno 2] No such file or directory: \\Servername/Ordner/Bild.jpg
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na wenn es mal geht und mal nicht, dann kann das ja nicht an deinem Code liegen. Sondern an einer variierenden Verfuegbarkeit der Netzwerkresource. Das ist ein Windows-Problem. Wenn du das nicht dauerhaft garantieren kannst, dass es die Datei gibt, dann kann man nur mit einem Workaround arbeiten. ZB koennte man in diesem Fall eine gecachte Version des Bildes aus einem lokalen Verzeichnis anbieten, und mit einem Timer periodisch pruefen, ob es wieder Verbindung gibt - um dann das Bild zu updaten.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PotterParsel: Der gezeigte `FileNotFoundError` passt nicht zu meinem Code weil ich dort keinen Dateinamen übergebe. Genau das ist ja der Punkt. Den hast Du da wieder auf den falschen Code zurück geändert.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

__blackjack__ hat geschrieben: Montag 5. September 2022, 15:05 @PotterParsel: Der gezeigte `FileNotFoundError` passt nicht zu meinem Code weil ich dort keinen Dateinamen übergebe. Genau das ist ja der Punkt. Den hast Du da wieder auf den falschen Code zurück geändert.
Kannst du mir das genauer erklären?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na du benutzt nicht Blackjacks Code.
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

__deets__ hat geschrieben: Montag 5. September 2022, 15:45 Na du benutzt nicht Blackjacks Code.
wenn ich file.name weglasse bekomme ich die folgende Fehlermeldung:

raise UnidentifiedImageError(PIL.UnidentifiedImageError: cannot identify image file <_io.TextIOWrapper name='\\Server/Bild1.png' encoding='ISO-8859-15'>

deswegen habe ich das .name gelassen.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PotterParsel: Ui, im Beitragstext wusste ich es noch, im Code habe ich es dann wieder vergessen: Die Datei muss im Binärmodus geöffnet werden. Mit Textdateien kann PIL an der Stelle nichts anfangen. Ähm, war natürlich Absicht, um zu schauen ob Du aufpasst. 🙂

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

__blackjack__ hat geschrieben: Dienstag 6. September 2022, 09:37 @PotterParsel: Ui, im Beitragstext wusste ich es noch, im Code habe ich es dann wieder vergessen: Die Datei muss im Binärmodus geöffnet werden. Mit Textdateien kann PIL an der Stelle nichts anfangen. Ähm, war natürlich Absicht, um zu schauen ob Du aufpasst. 🙂
Achso das gehörte dazu . 🙂

muss ich noch eine Bibliothek installieren oder so? Der Raspberry Pi erkennt das Asleep und Inc nicht.

Code: Alles auswählen

Sheep := 0;
WHILE NOT Asleep DO Inc(Sheep);
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist der Footer von __blackjack__, und ein Programmiererwitz.
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

__deets__ hat geschrieben: Dienstag 6. September 2022, 10:14 Das ist der Footer von __blackjack__, und ein Programmiererwitz.
Kannst du mir den Witz erklären, ich verstehe den nicht.

Hast du eine Lösung wie ich die Datei im Binärmodus öffnen kann?
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

Naja, wie bei jeder Datei, die man im Binärmodus öffnen möchte, mit mode="rb"
PotterParsel
User
Beiträge: 20
Registriert: Montag 5. September 2022, 08:58

Sirius3 hat geschrieben: Dienstag 6. September 2022, 10:50 Naja, wie bei jeder Datei, die man im Binärmodus öffnen möchte, mit mode="rb"
Danke.
Benutzeravatar
Dennis89
User
Beiträge: 1376
Registriert: Freitag 11. Dezember 2020, 15:13

PotterParsel hat geschrieben: Dienstag 6. September 2022, 10:41 Kannst du mir den Witz erklären, ich verstehe den nicht.
Er zählt Schafe bis er eingeschlafen ist.
Ich dachte Programmierer würden eher Bit's zählen, aber vielleicht ist die Signatur auch nach dem 5 Bit entstanden :mrgreen:
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Naja so ein richtiger Witz ist es ja auch nicht. Ich hatte das mal irgendwo als Beispielcode in Python und fand es zum schmunzeln, wobei das in OOP-Sprachen wo man das Objekt mit einer Schreibweise von „self“ referenziert noch ein bisschen eingängiger zu lesen ist. Und das hatte ich in verschiedene Programmiersprachen übersetzt und in meine Signatursammlung gesteckt. In Python wäre das:

Code: Alles auswählen

while not self.asleep():
    sheep += 1
Wobei man das bei Object Pascal im Gegensatz zum klassischen Pascal was in der Signatur steht, auch machen kann:

Code: Alles auswählen

sheep := 0;
while not Self.Asleep do Inc(sheep);

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
Antworten