www.mikrocontroller.net

Forum: PC-Programmierung Python 3: Was kommt zurück, wenn die Dateiauswahl abgebrochen wird?


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo

Wenn ich in Python 3 mit "name= askopenfilename()" (aus 
tkinter.filedialog)
eine Dateiauswahlbox aufrufe, sollte die mir einen Pfad auf die Datei 
als String zurückgeben. Das passiert auch so, und funktioniert.
Wenn ich nach Programmstart die Dateiauswahlbox zum ersten mal Aufrufe, 
und ohne eine Auswahl abbreche, kommt ein Leerstring zurück. Das 
passiert auch so, und funktioniert.

Soweit ok.

Wenn ich aber schon über die Dateiauswahlbox erfolgreich eine Datei 
geöffnet hatte, und nun erneut die Dateiauswahlbox aufrufe und ohne eine 
Auswahl abbreche, passiert was merkwürdiges:

print(name) gibt dann "()". Aber das ist kein String, wie in den obigen 
beiden Fällen, sondern ein Tupel.
Wenn ich den "Pfadstring" für eine Darstellung mit
"Pfad = ("Pfad: " + name)" aufbereiten möchte, kommt die Fehlermeldung,
das Python das Tupel nicht in einen String konvertieren kann.
Konvertiere ich aber name explizit per "stName = str(name)", liefert mir 
"Pfad = ("Pfad: " + stName)" den String: "Pfad: ()".

Wieso liefert mir Pfad = ("Pfad: " + stName) meistens einen String (wie 
erwartet) aber gelegentlich auch ein Tupel (was ich nicht erwarte) das 
aber so stringähnlich ist, das ich es problemlos konvertieren kann, 
ausser es steht in einem zusammengesetzten Ausdruck?

print(type(name)) zum testen eingefügt liefert übrigens in den ersten 
beiden Fällen <class 'str'> und in dem letzten fraglichen Fall <class 
'tuple'> für das was von "name= askopenfilename()" zurückkommt.

Betriebssystem hier ist Debian "squeeze".

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Nachtrag zu Beitrag #2728537:

Ich habe das Problem mit

name= askopenfilename()
name =str(name)

gelöst, indem ich name mit dem Hammer zum String umgeschmiedet habe.
Der Workaround funktioniert....

Trozdem verstehe ich nicht, was der Grund für das merkwürdige Verhalten 
ist....

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Das ist möglicherweise ein Bug (hab's aber nicht näher untersucht,
vielleicht ist es auch Absicht). Normalerweise liefert askopenfilename
ein String-Tuple oder einen Einzel-String zurück, je nachdem, ob die
Option multiple True ist oder nicht. Bei einem leeren Ergebnis kommt
die Funktion wohl etwas durcheinander.

Das sollte aber kein größeres Problem sein, wenn du die Abfrage des
Ergebnisses mit
  if name:
     ...

machst, da sowohl ein leerer String als auch ein leeres Tupel in einem
Booleschen Ausdruck als False gewertet wird.

Bernd Wiebus schrieb:
> Ich habe das Problem mit
>
> name= askopenfilename()
> name =str(name)
>
> gelöst, indem ich name mit dem Hammer zum String umgeschmiedet habe.
> Der Workaround funktioniert....

Sicher? Damit wird doch aus dem leeren Tupel der String '()'. Du kannst
also nicht mehr unterscheiden, ob der User Cancel gedrückt oder eine
Datei namens "()" ausgewählt hat.

Autor: Tom (Gast)
Datum:
Angehängte Dateien:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo,

ist mit Python 2.6 genauso (die Module heißen anders, das Verhalten ist 
gleich). Siehe Anhang. Das erwähnte 'if name' funktioniert aber 
definitiv besser als Stringgefummel.

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:
Angehängte Dateien:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Yalu X, hallo Tom.

Danke für Eure Antworten und Tipps.


> Sicher? Damit wird doch aus dem leeren Tupel der String '()'. Du kannst
> also nicht mehr unterscheiden, ob der User Cancel gedrückt oder eine
> Datei namens "()" ausgewählt hat.

Ok. Hast Recht, dann funktioniert es auch für den Fall, das einer seine 
Datei "()" nennt.....

> ist mit Python 2.6 genauso (die Module heißen anders, das Verhalten ist
> gleich).

Danke. Wenn Bug, scheint er wohl so uninteressant, das sich keiner 
weiter darum gekümmert hat.

> Siehe Anhang. Das erwähnte 'if name' funktioniert aber
> definitiv besser als Stringgefummel.

Mein erster Reflex war, zu sagen, wenn einer seine Datei "()" nennt, ist 
er selber schuld....auf der anderen Seite bin ich selber schräg genug 
drauf, um genau sowas zu machen....es hat auch seinen Grund, warum mir 
das merkwürdige Verhalten beim Abbrechen der Dateiauswahlbox aufgefallen 
ist. ;O)

Ich werde das also umschreiben.
Als Anhang übrigens das Programm (PyGerbAnalyse_A6.py), soweit es bisher 
geschrieben ist.....
Ich bin dabei, das, was ich vor gut 1 1/2 Jahren in Gambas geschrieben 
habe, in Python umzuschreiben......viel können kann es aber noch nicht.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Statt name in einen String umzuwandeln, wie hier
     name= askopenfilename()
     name = str(name)
     GerberAnalyse.stPfad = name
     if name =="":
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()
     if name =="()":
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()

kannst du ihn auch direkt mit dem Tupel vergleichen:
     name= askopenfilename()
     GerberAnalyse.stPfad = name
     if name =="":
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()
     if name ==():
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()

Damit ist auch der Dateiname "()" erlaubt.

Da sich beide If-Anweisungen nur in der Bedingung unterscheiden, kannst
du sie auch zusammenfassen:
     name= askopenfilename()
     GerberAnalyse.stPfad = name
     if name =="" or name ==():
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()

Etwas pythonischer sieht die Bedingung so aus:
     name= askopenfilename()
     GerberAnalyse.stPfad = name
     if name in ["", ()]:
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()

Oder eben gleich so:
     name= askopenfilename()
     GerberAnalyse.stPfad = name
     if not name:
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)
          return()

Wenn du den Code in anderer Reihenfolge hinschreibst, bekommst du auch
noch das hässliche "not" vor name weg:
     name= askopenfilename()
     GerberAnalyse.stPfad = name
     if name:
          GerberAnalyse.iZeilenzahl = 0
          ...
     else:
          Pfadanzeige["text"] = "Pfad: Leer"
          Listanzeige1.delete(0, END)
          Listanzeige2.delete(0, END)


Nur so am Rande :)

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Yalu X.


> Statt name in einen String umzuwandeln, wie hier
~~~~~~~~~~~~
~~~~~~~~~~~~
>
>
>
> Nur so am Rande :)

Ich habs jetzt so gemacht:
# Funktion Dateiauswahl Gerberfile
def Dateiwahl():
     name= askopenfilename()
     if name: #Nur Wahr, wenn Pfad gewählt wurde. Sonst Leerstring/Tupel
          GerberAnalyse.stPfad = name
          GerberAnalyse.iZeilenzahl = 0
          Pfad = ("Pfad: " + name)
          Pfadanzeige["text"] = Pfad
          Listanzeige1.delete(0, END) #Neue Datei, altes Listing...Clear 
          Listanzeige2.delete(0, END) #Neue Datei, alte Analyse...Clear
          GerberList1 = open(GerberAnalyse.stPfad, mode="rt")
          while True:
               Lesezeile = GerberList1.readline()
               if len(Lesezeile) ==0:
                    break # EOF wenn lesezeile nicht mehr kommt.
               Listanzeige1.insert(END, Lesezeile) #Neues Listimng
               Listanzeige1.yview(END) #Anzeige zum Ende
          GerberList1.close()
          return()

Bei Cancel passiert jetzt "garnichts" mehr, was ja auch die eigentliche 
Intention von Cancel ist....
Der komplette Block wird dann übersprungen und das Unterprogramm 
verlassen, ohne das was geändert wird.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Autor: Daniel -------- (root)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
hi,

vorab: ich habe nicht alles gelesen, aber ein Tupel könnte
sinnvoll sein, soweit man mit dem Dialog mehrere Dateien auswählen
lassen können wollte ..

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Daniel.

>
> vorab: ich habe nicht alles gelesen, aber ein Tupel könnte
> sinnvoll sein, soweit man mit dem Dialog mehrere Dateien auswählen
> lassen können wollte ..

Richtig, so ist das wohl auch gedacht. Nur war diese Option nicht 
gewählt worden.
Wenn ich nnur die Option für eine einzige Datei wähle, erwarte ich einen 
String oder halt auch einen Leerstring bei cancel.
Wenn ich die Option multiple wähle, erwarte ich halt auch ein Tupel bzw. 
Leertupel bei cancel.

Aber hier hatte ich die Option multiple nicht gewählt, und bekam zuerst 
einen Leerstring bei cancel, aber später dann ein Leertupel bei cancel.
Ich konnte immer nur eine Datei wählen, und diese einzelne Datei wurde 
auch erwartungsgemäß richtig als einzelner String übergeben.

Und das machte mich halt ratlos.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

http://www.dl0dg.de

Autor: Läubi .. (laeubi) (Moderator) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ggf mußt du auch die Option für Einzelauswahl jedesmal neu setzen? 
Manche 'API' wandert auf verschlungenen Pfaden... Schon allein die 
Annahme leerer String = nix ausgewählt ist blöde wenn man auf einmal ein 
Filesystem hat wo der leere String eben gültig ist (warum auch immer).

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Läubi.


> Ggf mußt du auch die Option für Einzelauswahl jedesmal neu setzen?

???? Das ist eine Funktion, die jedesmal neu angesprungen wird, wenn der 
Dateiauswahlbutton gedrückt wird.....theoretisch erwarte ich in dem 
Falle auch immer gleiches Verhalten.


Wie meinest Du das denn?



> Manche 'API' wandert auf verschlungenen Pfaden... Schon allein die
> Annahme leerer String = nix ausgewählt ist blöde wenn man auf einmal ein
> Filesystem hat wo der leere String eben gültig ist (warum auch immer).

In dem Falle kann "Abbruch/cancel" NICHT über den Pfadstring übergeben 
werden, weil in letzter Konsequenz jeder gültige String auch eine 
gültige Datei sein könnte. Es gäbe daher keinen Platz für einen Abbruch 
im String und es müsste für den Zweck eine extra Variable existieren.

Andersherum.....es währe ein "verbotener" Dateinahme unter Milliarden 
von erlaubten. Vermutlich könnte ich damit leben. Vor allem, wenn es um 
Gerberdatensätze geht. ;O)

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

http://www.dl0dg.de

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Nachtrag:


> Andersherum.....es währe ein "verbotener" Dateinahme unter Milliarden
> von erlaubten. Vermutlich könnte ich damit leben. Vor allem, wenn es um
> Gerberdatensätze geht. ;O)


Ich könnte auch z.B. bei jedem Cancel eine Warnung an den User ausgeben, 
daß, falls er in Wirklichkeit eine Datei mit einem Leerstring als Name 
oder Pfad gewählt hätte, speziell diese Datei wegen ihres Namens nicht 
gelesen werden kann und er sie darum bitteschön umbenennen möge. ,O)

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
ttp://www.dl0dg.de

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Bernd Wiebus schrieb:
> Ich könnte auch z.B. bei jedem Cancel eine Warnung an den User ausgeben,
> daß, falls er in Wirklichkeit eine Datei mit einem Leerstring als Name
> oder Pfad gewählt hätte, speziell diese Datei wegen ihres Namens nicht
> gelesen werden kann und er sie darum bitteschön umbenennen möge. ,O)

Gibt es eigentlich ein OS, in dem der Leerstring als Dateiname erlaubt
ist? In Unix geht ja fast alles, was ein krankes Hirn sich auszudenken
in der Lage ist, aber leere Dateinamen sind auch hier nicht möglich :)

Autor: Läubi .. (laeubi) (Moderator) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Bernd Wiebus schrieb:
> ???? Das ist eine Funktion, die jedesmal neu angesprungen wird
Ich kenne nun die Implementierung nicht, hatte deine Beschreibung aber 
so verstanden, dass irgendwo [pre]setSingleSelection(true)[pre] aufrufen 
muss.

Bernd Wiebus schrieb:
> In dem Falle kann "Abbruch/cancel" NICHT über den
> Pfadstring übergeben  werden,
Kennt Python kein 'null' oder Objekte?

Yalu X. schrieb:
> Gibt es eigentlich ein OS, in dem der Leerstring als
> Dateiname erlaubt ist?
Keine Ahnung... zumindest wenn du im Web surfst wird der leere Pfad auf 
eine Menge von index files von den meisten Webserver gemappt.

Das war jetzt nicht so ernst gemeint, sonder war auch nur eine 
hypothetische Anmerkung, in Java kann man so einem Filedialog ein 
eigenes FileSystemView mitgeben in welchem man sich theoretisch nach 
belieben austoben kann :-)
Dort wird cancel/ausgewählte Date(en) aber auch über ein Zustandsobjekt 
behandelt.

Yalu X. schrieb:
> aber leere Dateinamen sind auch hier nicht möglich

Konnte man unter MacOS nicht irgendwie Dateien nur aus Leerzeichen 
angeben?

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Läubi .. schrieb:
> Konnte man unter MacOS nicht irgendwie Dateien nur aus Leerzeichen
> angeben?

Das geht in Unix auch. Auch Tabs, Linefeeds, Carriage-Returns,
Backspaces und anderes Ungeziefer dürfen verwendet werden. Nur ein
richtig leerer Name (also mit 0 Zeichen Länge) geht halt nicht.

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Yalu.

> Gibt es eigentlich ein OS, in dem der Leerstring als Dateiname erlaubt
> ist? In Unix geht ja fast alles, was ein krankes Hirn sich auszudenken
> in der Lage ist, aber leere Dateinamen sind auch hier nicht möglich :)

Wenn Du schon so anfängst, müsstest Du auch berücksichtigen, das 
irgendjemand mal ein Operationssystem schreiben könnte, in dem ein 
Leerstring
als Dateiname möglich und sogar sinnvoll ist. ;O)

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Läubi.

> Bernd Wiebus schrieb:
>> ???? Das ist eine Funktion, die jedesmal neu angesprungen wird
> Ich kenne nun die Implementierung nicht, hatte deine Beschreibung aber
> so verstanden, dass irgendwo [pre]setSingleSelection(true)[pre] aufrufen
> muss.

...Du bringst mich auf eine Idee. Genau das habe ich explizit NICHT 
gemacht. Aber vieleicht sollte ich das ja mal machen.

Ich werde es ausprobieren.

>
> Bernd Wiebus schrieb:
>> In dem Falle kann "Abbruch/cancel" NICHT über den
>> Pfadstring übergeben  werden,
> Kennt Python kein 'null' oder Objekte?

So wie ich das aber Verstanden habe, ist "Null" ein spezieller Typ und 
eben kein String mehr.

Vieleicht sollte ich mir das noch einmal genau durchlesen.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Autor: Bernd Wiebus (berndwiebus) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ich habe es ausprobiert.
# Funktion Dateiauswahl Gerberfile
def Dateiwahl():
     name= askopenfilename(multiple = False) #Hier wird ausdrücklich auf EIN File festgenagelt.
     GerberAnalyse.stPfad = name
     GerberAnalyse.iZeilenzahl = 0
     Pfad = ("Pfad: " + name)
     Pfadanzeige["text"] = Pfad
     Listanzeige1.delete(0, END) #Neue Datei, altes Listing...Clear 
     Listanzeige2.delete(0, END) #Neue Datei, alte Analyse...Clear
     GerberList1 = open(GerberAnalyse.stPfad, mode="rt")
     while True:
          Lesezeile = GerberList1.readline()
          if len(Lesezeile) ==0:
               break # EOF wenn lesezeile nicht mehr kommt.
          Listanzeige1.insert(END, Lesezeile) #Neues Listimng
          Listanzeige1.yview(END) #Anzeige zum Ende
     GerberList1.close()
     return()


Einmal "Datei wählen" direkt nach dem Start aufgerufen und cecancelt.
Dann eine lesbare Datei aufgerufen.
Dann nochmalEinmal "Datei wählen" aufgerufen und cecancelt.

Fehlermeldungen in der Shell:
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.1/tkinter/__init__.py", line 1402, in __call__
    return self.func(*args)
  File "/home/wiebus/python/PyGerbAnalyse_A8-2.py", line 841, in Dateiwahl
    GerberList1 = open(GerberAnalyse.stPfad, mode="rt")
IOError: [Errno 2] No such file or directory: ''
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.1/tkinter/__init__.py", line 1402, in __call__
    return self.func(*args)
  File "/home/wiebus/python/PyGerbAnalyse_A8-2.py", line 837, in Dateiwahl
    Pfad = ("Pfad: " + name)
TypeError: Can't convert 'tuple' object to str implicitly

"IOError: [Errno 2] No such file or directory: '' "ist das erste 
canceln. Hier kommt der Leerstring zurück, und
"TypeError: Can't convert 'tuple' object to str implicitly " ist das 
zweite canceln, wo dann das Leertupel zurückkommt.

Das explizite Angeben, das nur ein File geöffnet werden soll, hat also 
keinen Einfluss auf dieses Verhalten.


Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net