The goal for this iteration is to complete the functioning of the File menu options of Open, Save, and Save As.
We regularly use the Open and Save dialogs. They are common across many programs. We know how these menu items behave. For instance, when you click on the Open menu, it opens up a dialog form that lets you traverse to the location of the file you want to open. When you select a particular file and click on Open, it opens up in your editor. Similarly, we have the Save dialog.
While we can implement these dialogs using standard Tkinter widgets, it turns out that they are so commonly used that a specific Tkinter module called tkFileDialog
has been included in the standard Python distribution. We will not try to reinvent the wheel and in the spirit of less coding, we will use the tkFileDialog
module to implement Open and Save functionality for our text editor as shown in the following screenshot:
To use the module, we simply import it into the current namespace as given in the code file of 2.06.py
:
import tkFileDialog
You can specify the following additional options for tkFileDialog
:
File dialog |
Configurable options |
Description |
---|---|---|
|
Asks for a filename to open, and then it returns the opened file | |
|
Asks for a filename to open but returns nothing | |
|
Asks for a filename to save as, and it returns the opened file | |
|
Asks for a filename to save as but returns nothing | |
parent, title, initialdir, must exist |
Asks for a directory, and it returns the filename |
tkDialogBox
(refer to code2.07.py
):import tkFileDialog import os def open_file(): global filename filename = tkFileDialog.askopenfilename(defaultextension=".txt",filetypes =[("All Files","*.*"),("Text Documents","*.txt")]) if filename == "": # If no file chosen. filename = None # Absence of file. else: root.title(os.path.basename(filename) + " - pyPad") # #Returning the basename of 'file' textPad.delete(1.0,END) fh = open(filename,"r") textPad.insert(1.0,fh.read()) fh.close()
We then modify the Open menu to add a command
callback to this newly-defined method:
filemenu.add_command(label="Open", accelerator='Ctrl+O', compound=LEFT, image=openicon, underline =0, command=open_file)
The description of the code is listed as follows:
tkfileDialog
and os
modules into the current namespace.open_file()
.save()
and save_as()
. Not specifying it as global would mean that it is only available within the function. So our save()
and save_as()
functions would not be able to check if a file is already open in the editor.tkFileDialog.askopenfilename
to fetch the filename of the opened file. If the user cancels opening the file or if no file is chosen, the filename returned is None
. In that case we do nothing.tkFileDialog
returns a valid filename, we isolate the filename using the os
module and add it as a title of our root window.fh
.command
callback to our File | Open menu item.This completes the coding of File | Open. If you now go and click on File | Open and select a text file and click on Open, the text area will be populated with the content of the text file.
Use of global variables is generally considered a bad programming practice because it is very difficult to understand a program that uses lots of global variables.
A global variable can be modified or accessed from many different places in the program, and it therefore becomes difficult to remember or work out every possible use of the variable.
A global variable is not subject to any access control, which may pose security hazards in certain situations, say when this program is to interact with a third party code.
However, when you work on programs in the procedural style like this one, global variables are sometimes unavoidable.
An alternative approach to programming involves writing code in a class structure (also called object-oriented programming ), where a variable can only be accessed by members of predefined classes. We will see a lot of examples of object-oriented programming in the next project.
If the text pad already contains a file, we do not prompt the user for a filename. We simply overwrite the contents of the existing file. If there is no filename associated with the current content of the text area, we prompt the user with a Save As dialog. Moreover, if the text area has an open file, and the user clicks on Save As, we still prompt them with a Save As dialog to allow them to write the contents to a different filename.
The code for Save and Save As is as follows (see the code in 2.07.py
):
#Defining save method def save(): global filename try: f = open(filename, 'w') letter = textPad.get(1.0, 'end') f.write(letter) f.close() except: save_as() #Defining save_as method def save_as(): try: # Getting a filename to save the file. f = tkFileDialog.asksaveasfilename(initialfile = 'Untitled.txt', defaultextension=".txt",filetypes=[("All Files","*.*"),("Text Documents","*.txt")]) fh = open(f, 'w') textoutput = textPad.get(1.0, END) fh.write(textoutput) fh.close() root.title(os.path.basename(f) + " - pyPad") except: pass filemenu.add_command(label="Save", accelerator='Ctrl+S', compound=LEFT, image=saveicon, underline=0, command=save) filemenu.add_command(label="Save as", accelerator='Shift+Ctrl+S', command=save_as)
The description of the code is listed as follows:
save
function first tries to locate if a file is open in the text area using a try
block. If a file is open, it simply overwrites the content of the file with the current content of the text area.save_as
function.save_as
function opens a dialog using tkFileDialog.asksaveasfilename
and tries to get the filename provided by the user for the given file. If it succeeds, it opens the new file in the write mode and writes the content of text into this new filename. After writing, it closes the current file handler and changes the title of the window to reflect the new filename.save_as
function makes use of the os
module. We, therefore, need to import the os
module into our namespace before we can use it to extract the current filename.save_as
operation, it simply ignores the process by using a pass
command.command
callback from our existing Save and Save As menu items to invoke these two functions.We are now done adding Save and Save As functionality to our code editor.
2.07.py
:def new_file():
root.title("Untitled")
global filename
filename = None
textPad.delete(1.0,END)
filemenu.add_command(label="New", accelerator='Ctrl+N', compound=LEFT, image=newicon, underline=0, command=new_file )
The description for this code is listed as follows:
new_file
function begins by changing the title
attribute of the root window to Untitled
.filename
to None
. This is important because our save
and save_As
functionality uses this global variable name to track whether or not the file exists or is new.command
callback to function from our File | New menu item.This completes our coding of File | New into our code editor.
In this iteration, we completed coding functionality for the New, Open, Save, and Save As submenus, present under the File menu, for our editor.
More importantly, we saw how to use the tkFileDialog
module to achieve certain commonly-used features in our program. We also saw how we could use indexing to achieve a wide variety of tasks for our programs.
18.226.34.25