Working with forms and dialogs

The goal for this iteration is to complete the functioning of the File menu options of Open, Save, and Save As.

Prepare for Lift Off

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:

Prepare for Lift Off

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

askopenfile(mode='r', **options)

parent, title, message, defaultextension, filetypes, initialdir, initialfile, and multiple

Asks for a filename to open, and then it returns the opened file

askopenfilename(**options)

parent, title, message, defaultextension, filetypes, initialdir, initialfile, and multiple

Asks for a filename to open but returns nothing

asksaveasfile(mode='w', **options)

parent, title, message, defaultextension, filetypes, initialdir, initialfile, and multiple

Asks for a filename to save as, and it returns the opened file

asksaveasfilename(**options)

parent, title, message, defaultextension, filetypes, initialdir, initialfile, and multiple

Asks for a filename to save as but returns nothing

askdirectory(**options)

parent, title, initialdir, must exist

Asks for a directory, and it returns the filename

Engage Thrusters

  1. Let us now develop our Open function using 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:

    • We import the tkfileDialog and os modules into the current namespace.
    • We define our function open_file().
    • We declare a variable in the global scope to keep track of the filename of the opened file. This is required to keep track of whether or not a file has been opened. We need this variable in the global scope, as we want this variable to be available to other methods such as 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.
    • We use 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.
    • If, however, tkFileDialog returns a valid filename, we isolate the filename using the os module and add it as a title of our root window.
    • If the Text widget already contains some previous text, we delete it all.
    • We then open the given file in read mode and insert all its content into the text area.
    • After this we close the file handle fh.
    • Finally, we add a 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.

    Note

    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.

  2. Next we will see how to save a file. There are two components for saving a file:
    • Save File
    • Save As

    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:

    • The 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.
    • If there is no filename associated with the text area, it simply passes the work to our save_as function.
    • The 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.
    • To obtain the new filename, our 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.
    • If the user does not specify a filename or if the user cancels the save_as operation, it simply ignores the process by using a pass command.
    • Finally, we add a 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.

  3. While we are at it, let's complete our functionality of File | New. The code is simple. For this see the code in 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:

    • The new_file function begins by changing the title attribute of the root window to Untitled.
    • It then sets the value of the global variable 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.
    • Our function then deletes all the content of the Text widget, creating a fresh document in its place.
    • Finally, we add a command callback to function from our File | New menu item.

    This completes our coding of File | New into our code editor.

Objective Complete – Mini Briefing

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.96.105