Error when "Cancel" while opening a file in PyQt4 - python

I have a simple PyQt4 GUI where I have the user open a txt file that will display in the GUI's QPlainTextEdit widget.
Here's the pseudo code:
class mainWindow(QtGui.QWidget):
def __init__(self):
super(mainWindow, self).__init__()
self.layout = QtGui.QVBoxLayout()
self.plain = QtGui.QPlainTextEdit()
self.openButton = QtGui.QPushButton("OPEN")
self.layout.addWidget(self.plain)
self.layout.addWidget(self.openButton)
self.openButton.clicked.connect(self.openFile)
def openFile(self):
openFileName = QtGui.QFileDialog.getOpenFileName(None, "Open File","/some/dir/","TXT(*.txt);;AllFiles(*.*)")
openFile = open(openFileName,'r').read()
self.plainTextEdit.appendPlainText(openFile)
So I click the "OPEN" button and the QFileDialog pops up, but if I hit the "CANCEL" button within the QFileDialog, I get this error:
IOError: [Errno 2] No such file or directory: PyQt4.QtCore.QString(u'')
I know as the programmer that this error can be easily ignored and does not impact the code's operation whatsoever, but the users do not know that. Is there a way to eliminate this error from printing in terminal?

Yes: simply check the return value from getOpenFileName. This method returns an empty QString if the user clicks Cancel. As empty QStrings are considered false, you can check to see if the user chose a file instead of clicking Cancel by putting the last two lines of your openFile method in an if openFileName: statement:
def openFile(self):
openFileName = QtGui.QFileDialog.getOpenFileName(None, "Open File","/some/dir/","TXT(*.txt);;AllFiles(*.*)")
if openFileName:
openFile = open(openFileName,'r').read()
self.plainTextEdit.appendPlainText(openFile)

as one above said, you should debug and check what kind of answer "openFilename" returns.
in Pyqt5, when you press cancel or 'x' to close the window, it returns a tuple
so to get around the issue:
openFileName = QFileDialog.getOpenFileName(self)
if openFileName != ('', ''):
with open(openFileName [0], 'r') as f:
file_text = f.read()
self.text.setText(file_text)

Related

How to remember tkinter window position in python 3?

I have a tkinter gui and I would like it to retain the original window position and size upon relaunching.
Here is an answer that illustrates how to set a specific position and dimensions, but not a word about remembering the settings: How to specify where a Tkinter window opens?
Highly appreciate any help.
The only way to remember settings from session to session is to write them into a file. So, get the root window geometry (it's a string) and write it into a file. If you want the function to be executed automatically as a hook, bind it to the "<Configure>" event:
def save_size(event):
with open("myapp.conf", "w") as conf:
conf.write(root.geometry()) # Assuming root is the root window
root.bind("<Configure>",save_size)
You can later read the geometry from the file and restore it.
#Here I save the x and y position of the window to a file "myapp.conf"
#Here I see if the file exists.
if os.path.isfile("myapp.conf"):
#Here I read the X and Y positon of the window from when I last closed it.
with open("myapp.conf", "r") as conf:
root.geometry(conf.read())
else:
#Default window position.
root.geometry('610x270+0+0')
def on_close():
#custom close options, here's one example:
#close = messagebox.askokcancel("Close", "Would you like to close the program?")
#if close:
#Here I write the X Y position of the window to a file "myapp.conf"
with open("myapp.conf", "w") as conf:
conf.write(root.geometry())
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_close)
It took me pretty much time to get my head around actual implementation of this. So I wanted to share my final code. Based on DyZ suggestion.
I didn't use <Configure> event as suggested because only saving before quit is enough for me.
class Window(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# ...
# bla bla bla
# My GUI codes came here
# ...
# Try to load last saved window data
self.statusbar['text']="reading ini file..."
ini_file_path = "mapedit.ini"
try:
# if the file is there
# get geometry from file
ini_file = open(ini_file_path,'r')
self.geometry(ini_file.read())
self.statusbar['text']= "ini file read"
ini_file.close()
except:
# if the file is not there, create the file and use default
# then use default geometry.
self.statusbar['text']="ini file not found. New file created."
ini_file = open(ini_file_path, 'w')
ini_file.close()
self.geometry("640x400+100+200")
def client_exit(self):
self.save_geo()
self.destroy()
def save_geo(self):
# save current geometry to the ini file
try:
with open("mapedit.ini", 'w') as ini_file:
ini_file.write(self.geometry())
self.statusbar['text']="geo sv"
ini_file.close()
except:
statusbar['text']="ini file not found"
'''
This is where I created GUI instance
'''
if __name__ == "__main__":
win = Window()
# attach deletion handler to 'client_exit' method
win.protocol("WM_DELETE_WINDOW", win.client_exit)
win.mainloop()

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()
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).

Save TextInput on button press - kivy/python

I have a class with a button "Save game", which opens a popup with textinput widget and a button with which I would like to save the users text input. I tried this but it doesn't work.
If I print out the filename after "modifying" it, it prints out the filename that I defined beforehand: .txt, not Game1.txt or something like this.
class Something(Widget):
filename = ".txt"
# code for game
def save(self,*args):
def on_text(instance, value):
return value
name = TextInput(text="")
name.bind(text=on_text)
self.filename = "{}.txt".format(name.text)
b = BoxLayout()
save_button = Button(text="Save file")
b.add_widget(save_button)
b.add_widget(name)
popup = Popup(title="Enter the name:", content=b)
save_button.bind(on_release=popup.dismiss)
name.bind(on_text_validate=popup.on_dismiss) # I wanted to save it when the user closes the popup
popup.open()
Where am I doing it wrong? (I know this won't actually save it, I just want to create the name here, I have a different class method for saving it)
I'm looking at a similar problem: when the user types text into a text input box, but does not hit return before hitting the 'exit' button, the changes are lost.
You might want to see if this is your error as well.

How to hide a Gtk+ FileChooserDialog in Python 3.4?

I have a program set up so that it displays a FileChooserDialog all by itself (no main Gtk window, just the dialog).
The problem I'm having is that the dialog doesn't disappear, even after the user has selected the file and the program has seemingly continued executing.
Here's a snippet that showcases this issue:
from gi.repository import Gtk
class FileChooser():
def __init__(self):
global path
dia = Gtk.FileChooserDialog("Please choose a file", None,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
self.add_filters(dia)
response = dia.run()
if response == Gtk.ResponseType.OK:
print("Open clicked")
print("File selected: " + dia.get_filename())
path = dia.get_filename()
elif response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
dia.destroy()
def add_filters(self, dia):
filter_any = Gtk.FileFilter()
filter_any.set_name("Any files")
filter_any.add_pattern("*")
dia.add_filter(filter_any)
dialog = FileChooser()
print(path)
input()
quit()
The dialog only disappears when the program exits with the quit() function call.
I've also tried dia.hide(), but that doesn't work either - the dialog is still visible while code continues running.
What would the proper way to make the dialog disappear?
EDIT: I've since learned that it's discouraged to make a Gtk dialog without a parent window. However, I don't want to deal with having to have the user close a window that has nothing in it and simply stands as the parent for the dialog.
Is there a way to make an invisible parent window and then quit the Gtk main loop when the dialog disappears?
You can set up a window first by doing:
def __init__ (self):
[.. snip ..]
w = Gtk.Window ()
dia = Gtk.FileChooserDialog("Please choose a file", w,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
also, set a default value for path in case the user cancels:
path = ''
Then, at the end of your script:
print (path)
while Gtk.events_pending ():
Gtk.main_iteration ()
print ("done")
to collect and handle all events.

How can I make this 2 functions work in python?

I am learning Python. Why do I get the error Exception in Tkinter callback?
I'm trying to Browse the file from the button "Browse" and zip the file in "Compress" button. I don't know what is wrong with my code? Please help!
from Tkinter import *
import tkFileDialog
import gzip
class SecureBox(Frame):
def browse(self):
return tkFileDialog.askopenfilename()
def compressFile(self):
f_in = open(self.browse, 'rb')
f_out = gzip.open('compressFile.gz', 'wb')
f_out.writelines(f_in)
f_out.close()
f_in.close()
def createWidgets(self):
# Pick a file from user
self.compress = Button(self)
self.compress["text"] = "1. Browse"
self.compress["command"] = self.browse
self.compress["fg"] = "blue"
self.compress.pack({"side": "top"})
# Pick a file from user and compress the file
self.compress = Button(self)
self.compress["text"] = "2. Compress"
self.compress["command"] = self.compressFile
self.compress["fg"] = "blue"
self.compress.pack({"side": "top"})
# Adding this function to get the widget show up
def __init__(self, master):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
root = Tk()
root.title ("Secure Box")
root.geometry("500x350")
sb = SecureBox(root)
# start the program
sb.mainloop()
root.destroy()
Save the filename as a class attribute, and use that to open the file:
def browse(self):
self.filename = tkFileDialog.askopenfilename()
def compressFile(self):
f_in = open(self.filename, 'rb')
...
Explanation:
Basically, when you're doing open(self.browse, 'rb') you're passing a function reference to open instead of a filename. This won't work, since open cannot open a function, it can open files. You could use open(self.browse(), 'rb') since self.browse() returns a filename, but that would render your Browse button useless, since the file dialog would then be opened when you click the Compress button.
When saving the filename as a class attribute and using that to open the file as I propose above, you also don't need the return in the browse function. In Tkinter, a button callback is called without any arguments and no return arguments are saved, so returning anything doesn't do anything. If you choose to do remove the browse button altogether and use the open(self.browse(), 'rb') method, you do need to return the filename (but it doesn't need to be a class attribute).

Categories

Resources