Nach jedem Speichern zusätzliche Leerzeile in Textdatei

Fragen zu Tkinter.
Antworten
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Hallo,

In meinem Übungsbuch habe ich eine Übung durchgearbeitet, in der ein Text, aus einer Datei, geöffnet und in einem Textfeld angezeigt wird.

Danach habe ich das ganze nochmal ohne Buch gemacht und mir gedacht, wenn ich schon was öffne, dann möchte ich es auch ändern und speichern können. Mit Hilfe der Python Standard Library habe ich das auch soweit hinbekommen. Bis auf eine kleinigkeit, die ich nicht verstehe:

Jedes mal wenn ich meine Textdatei speicher, wird am Ende eine neue Leerzeile eingefügt und ich weiß weder warum, noch wie ich es verhindern kann.

Code: Alles auswählen

import sys
import tkinter as tk
import tkinter.scrolledtext as tks

# Programm beenden
def ende():
    sys.exit(0)

# Datei öffnen
def xopen():
    textfeld.delete(1.0, "end")
    datei = open("testtext2.txt")
    zeile = datei.readline()
    while zeile:
        textfeld.insert("end", zeile)
        zeile = datei.readline()
    datei.close()

# Datei speichern
def xsave():
    datei = open("testtext2.txt", "w")
    text = textfeld.get(1.0, "end")
    datei.writelines(text)
    datei.close()

main = tk.Tk()

# Textfeld
textfeld = tks.ScrolledText(main, width = 100, height = 30)
textfeld.pack()

# Button öffnen
bopen = tk.Button(main, text = "Öffnen", command = xopen)
bopen.pack()

# Button schliessen
bsave = tk.Button(main, text = "Speichern", command = xsave)
bsave.pack()

# Button Ende
bende = tk.Button(main, text = "Ende", command = ende)
bende.pack()

main.mainloop()
Ich bin für jede Hilfe dankbar.

Gruß

Nils
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ein paar Sachen vorne weg.

1. Dateien immer mit dem "with" keyword öffnen, gilt ab Python 2.6.

2. Du machts dir das auslesen und füttern des Textfeldes zu Umständlich, und wenn du es Zeilenweise fütterst geht sogar der Puffer des Scrolledtext-Widgets verloren.

3. sys.exit(0) - ist imho eine schlecht Wahl.
Bei einer GUI willst du eigentlich nicht den Interpreter, sondern die GUI schließen, also hier main.destroy() nehmen.

4. Das Problem warum immer eine Leerzeile dazu kommt ist die "insert"-Methode, da diese wie print immer eine leerzeile hizufügt.
Lösung, wäre zB. das du das letzte Zeichen einfach nicht mit in die Textdatei schreibst, dafür wäre die String Methode ".strip()" angebracht.

5. Für eine main-Funktion nutzt man in Python eine kleine Abfrage, solange du aber noch nicht mit Modulen Arbeitest, ist deins OK.
Ich habe deinen Script mal nach den Punkten geändert und auch 5. mit eingefügt, sieh ihn dir einfach mal genau an.

Code: Alles auswählen

import tkinter as tk
import tkinter.scrolledtext as tks

# Programm beenden
def ende():
    main.destroy()

# Datei öffnen
def xopen():
    textfeld.delete(1.0, "end")
    with open("testtext2.txt") as datei:
        textfeld.insert("end", datei.read())

# Datei speichern
def xsave():
    with open("testtext2.txt", "w") as datei:
        text = textfeld.get(1.0, "end").strip()
        datei.write(text)

if __name__ == "__main__":
    main = tk.Tk()

    # Textfeld
    textfeld = tks.ScrolledText(main, width=100, height=30)
    textfeld.pack()

    # Button öffnen
    bopen = tk.Button(main, text="Öffnen", command=xopen)
    bopen.pack()

    # Button schliessen
    bsave = tk.Button(main, text="Speichern", command=xsave)
    bsave.pack()

    # Button Ende
    bende = tk.Button(main, text="Ende", command=ende)
    bende.pack()

    main.mainloop()
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Xynon1 hat geschrieben:Lösung, wäre zB. das du das letzte Zeichen einfach nicht mit in die Textdatei schreibst, dafür wäre die String Methode ".strip()" angebracht.
So wie gezeigt hilft es jedoch nicht - die Leerzeile entsteht nicht beim Schreiben, sondern beim Lesen der Datei. Im übrigen würde ich strip() zumindest durch rstrip() ersetzen, sonst schnippelt man sich möglicherweise mehr weg, als man möchte, evtl. besser noch rstrip("\n"):

Code: Alles auswählen

# Datei öffnen
def xopen():
    textfeld.delete(1.0, "end")
    with open("testtext2.txt") as datei:
        textfeld.insert("end", datei.read().rstrip("\n"))

# Datei speichern
def xsave():
    with open("testtext2.txt", "w") as datei:
        text = textfeld.get(1.0, "end")
        datei.write(text)
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@numerix
Stimmt :oops:

Ulkiger weise hat man in der print ausgabe beim speichern dennoch ein "\n" drin, auch wenn dieses nicht mitgeschrieben wird ?!
Könntest du mir das vieleicht erläutern, denn da bin ich ebend drüber gestolpert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

push
Würde mich immer noch interessieren, warum sich das so verhält.

Zudem habe ich jetzt ein ähnliches Problem, beheben lässt sich das über die strip-Methode ganz einfach, nur warum ?
Also ich habe ein einfaches "Escape"-KeyEvent über das TextWidget gelegt, welches den gerade geschriebenen Inhalt löscht und den alten der vor dem Editieren drin stand wieder reinschreibt.

Code: Alles auswählen

def escape(self, event):
        self.text.delete(0.0, "end")
        self.text.insert("end", self._value.rstrip("\n"))
Aber selbst wenn self._value leer also "" ist wird ein "\n" angehängt, wenn ich das strip schreibe dann nicht mehr. Und ein strip dürfte doch auf "" keine Wirkung haben, oder ?

Wie erkennt also die insert-Methode, das dort kein "\n" rangehangen werden soll ?
Ich Blick es einfach nicht, wäre schön wenn mir das mal jemand erklären könnte.
Danke schonmal im vorraus.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten