Most Recently Used (MRU) Menus

Many applications have a list of most recently used (or MRU) file names listed on the file menu. Choosing one of the file names from the menu is a short cut to opening the file. These menu buttons are updated every time you open or save a file. But it isn't obvious how to implement this functionality in Tk.

Here is some example code that uses the Tk menu's insert and delete functions to add command elements to the file menu which will open the files. You can specify a maximum number of entries on the MRU list. You will need to adapt this code to your own application. RWT

 #----------------------------------------------------------
 # create a toplevel menu
 #  to demonstrate MRU - most recently used file names.
 #----------------------------------------------------------

 package require Tk

 menu .menu
 . configure -menu .menu

 menu .menu.file -tearoff 0
 .menu add cascade -menu .menu.file -label File
 .menu.file add command -label New  -command fileNew
 .menu.file add command -label Open -command fileOpen
 .menu.file add command -label Save -command fileSave
 .menu.file add separator
 .menu.file add command -label Exit -command fileExit


 #----------------------------------------------------------
 #  Application procedures called by the menu entries
 #----------------------------------------------------------
 proc fileNew {} {}
 proc fileOpen {{filename ""}} {
    tk_messageBox -message "Opening file '$filename'"
 }
 proc fileSave {} {}
 proc fileExit {} {exit}


 #----------------------------------------------------------
 #  Here is a button and entry to add filenames to the
 #  recently used list
 #----------------------------------------------------------

 set b [button .b -text "Add" -command {addRecentFile $newFileName}]
 set e [entry .e -textvariable newFileName]

 grid $b $e


 #----------------------------------------------------------
 #  Save info about the most-recently used menu
 #  location and file names.
 #----------------------------------------------------------
 set recentFiles(widget) .menu.file
 set recentFiles(max) 4
 set recentFiles(count) 0





 #----------------------------------------------------------
 #
 #  addRecentFile
 #
 #  Adds the specified file to the "recent files"
 #  section of the file menu.
 #
 #  It is presumed that the last two elements on the
 #  menu are a separator and the "Exit" function.
 #  This routine inserts another separator the first
 #  time called, then inserts command entries displaying
 #  the file name with a command to open the file.
 #
 #  This routine requires a global array, recentFiles,
 #  which stores the name of the file menu widget,
 #  the number and maximum number of file names to
 #  display, and the index into the file menu at which
 #  new entries are added.
 #
 #  Arguments:
 #    filename   - name of file to be opened
 #  Results:
 #    Creates a new command entry on the file menu.
 #    If there are more than "max" entries, then the
 #    oldest menu command entry will be deleted.
 #
 #----------------------------------------------------------
 proc addRecentFile {filename} {
    global recentFiles
    set m $recentFiles(widget)

    #----------------------------------------------------------
    #  First time through, find the end of the menu and
    #  insert a separator.
    #----------------------------------------------------------
    if { $recentFiles(count) == 0 } {
        set recentFiles(index) [$m index end]
        $m insert $recentFiles(index) separator
    }

    #----------------------------------------------------------
    #  Make a nice label.  On MS Word, long file names get
    #  shortened to C:\...\somelongfilename... but you can
    #  do whatever you want.
    #----------------------------------------------------------
    set name [file nativename $filename]
    if { [string length $name] > 30 } {
        set labelText "...$name end-30 end]"
    } else {
        set labelText $name
    }

    #----------------------------------------------------------
    #  Add the new file
    #----------------------------------------------------------
    $m insert $recentFiles(index) \
        command -label $labelText -command [list fileOpen $filename]

    #----------------------------------------------------------
    # make sure we don't get too many
    #----------------------------------------------------------
    incr recentFiles(count)
    if { $recentFiles(count) > $recentFiles(max) } {
        set index [$recentFiles(widget) index end]
        $m delete [expr {$index - 2}]
    }
 }