Jonah Fleming
Jonah Fleming

Reputation: 1185

Why doesn't save() write to file first time?

I am making an text editor and I am working on the save/save-as buttons and have found something that I first thought worked but then found a problem with. The save and save as buttons in the menu don't save the text in the text widget to the file but just creates one. I have put in both functions self.f1.write(text) but only after a few clicks does the text actually save. It is not a time thing because I waited about five minutes and it still didn't work. I have a Mac on Yosemite.

Why doesn't it work?

Here is the script:

#modules
from Tkinter import *
from Tkinter import TclError
import tkFont
import tkMessageBox
import tkFileDialog


class Main(object):
    def __init__(self, root):
        root.title("PyText")
        #menu for the file cascade
        self.m1=Menu(root)

        self.appmenu = Menu(self.m1, name="apple", tearoff=0)
        self.m1.add_cascade(menu=self.appmenu)
        self.appmenu.add_command(label="About PyText")
        self.appmenu.add_separator()

        self.fm=Menu(self.m1, tearoff=0)
        self.fm.add_command(label="New", command=self.saveas)
        self.fm.add_command(label="Open", accelerator="Cmd+O", command=self.open)
        #these two don't work first time...
        self.fm.add_command(label="Save", accelerator="Cmd+S", command=self.save)
        self.fm.add_command(label="Save As", command=self.saveas)

        self.fm.add_separator()

        self.fm.add_command(label="Exit", command=root.quit)

        self.m1.add_cascade(label="File", menu=self.fm)

        root.config(menu=self.m1)

        #Main text widget
        self.t1=Text(root)
        self.t1.config(width=90, height=40, undo=True, highlightbackground="black", cursor="ibeam")
        self.t1.grid(row=1)


    # Here is the problem.
    # this command creates the file but does not
    # save the text to the file.
    def saveas(self):
        text = self.t1.get(0.0, END)
        self.savelocation=tkFileDialog.asksaveasfilename()
        self.file=open(self.savelocation, "w+")
        self.file.write(text)

    # this also has
    # the same problem. Once save as has
    # been called, it does not save when pressed
    # in first click but after a few clicks it
    # finaly saves.
    def save(self):
        try:
            text = self.t1.get(0.0, END)
            self.f1=open(self.file, "w+")
            self.f1.write(text)
        except IOError:
            text = self.t1.get(0.0, END)
            self.f1=open(self.savelocation, "w+")
            self.f1.write(text)
        except Exception:
            tkMessageBox.showinfo("Error", "Please save-as first.")
            raise

    #works fine!
    def open(self):
        self.file=tkFileDialog.askopenfilename()
        self.OpenFile=file(self.file) # get a file handle
        self.ReadFile= self.OpenFile.read() # read the file to variable
        self.OpenFile.close() # close file handle
        self.t1.delete(0.0, END)
        self.t1.insert(END, self.ReadFile)

root = Tk()
app = Main(root)
root.mainloop()

Upvotes: 0

Views: 1532

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 386010

Your code is saving data. However, you aren't closing the file and python buffers output, so the file on disk may not actually have any data until something causes the file to be closed (such as exiting the program normally).

The simple solution is to make sure you close the file after writing to it, and the easiest way to do that is by using open with the with statement.

def save(self):
    try:
        with open(self.file, "w+") as f1:
            texts = self.t1.get("1.0", "end-1c")
            f1.write(text)
    ...

In the above code, when the with block finishes, the file is guaranteed to be closed and the context flushed to disk.

Note: your use of the index 0.0 is incorrect. The index must be a string, and the first character is "1.0" not "0.0". Also, Tkinter always adds an extra newline to the text widget. If you want exactly what the user entered you need to get all but the very last character, which is what "end-1c" means (end, minus one character).

Upvotes: 2

Related Questions