Seite 1 von 1

Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 09:08
von PotterParsel
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

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 10:28
von __blackjack__
@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()

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 12:50
von PotterParsel
__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?

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 14:27
von Sirius3
Bitte poste die komplette Fehlermeldung inklusive Traceback, statt nur den Fehler zu umschreiben.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 14:39
von PotterParsel
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

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 14:53
von __deets__
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.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 15:05
von __blackjack__
@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.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 15:14
von PotterParsel
__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?

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Montag 5. September 2022, 15:45
von __deets__
Na du benutzt nicht Blackjacks Code.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 09:22
von PotterParsel
__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.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 09:37
von __blackjack__
@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. 🙂

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 10:02
von PotterParsel
__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);

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 10:14
von __deets__
Das ist der Footer von __blackjack__, und ein Programmiererwitz.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 10:41
von PotterParsel
__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?

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 10:50
von Sirius3
Naja, wie bei jeder Datei, die man im Binärmodus öffnen möchte, mit mode="rb"

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 11:03
von PotterParsel
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.

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 11:16
von Dennis89
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:

Re: Python smbclient Bild im TKinter Label anzeigen

Verfasst: Dienstag 6. September 2022, 12:48
von __blackjack__
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);