Re: Tkinter file selection dialog

anthony baxter (anthony.baxter@aaii.oz.au)
Mon, 30 Jan 1995 22:41:30 +1100

This is a multipart MIME message.

--boundary=_0
Content-Type: text/plain; charset="us-ascii"
--------

Paul Shannon wrote:
> Looking through the tkinter demos, I was surprised to find no
> composite widget for selecting files -- something like the Motif
> FileSelectionDialog.

Here's one I wrote a while ago - it was probably my first playing with
tkinter, I re-implemented an existing fileselector of mine from
another language. It's not pretty, but it was one of those 'hey, it
works, I couldnt be bothered getting back to re-implementing it'

This was derived from one I originally wrote in Wafe, but it doesnt
have all the features my Wafe one had (yet) - in particular, I want
file name completion to be back in it. It works well enough for my
purposes... YMMV

To use:

import myFS # or whatever you call the file.
def cbfn(filename):
print 'you selected :',filename
fs=myFS.FileSelector('load a file')
fs.notify=cbfn # if you dont set this, the default function of 'print' is used

PS: Anyone who uses this as a Guide To How To Program With Python & Tk will
be hunted down by a pack of Trondheim Hammer Dancers.

Anthony

--boundary=_0
Content-Type: text/plain; charset="us-ascii"
Content-Description: myFS.py

# File Selector.
# Derived from wafe fs. Not really a 'finished product', more
# an evolving one.
# anthony@aaii.oz.au

from Tkinter import *

class FileSelector:
def notifydefault(self,path):
print 'selected: ' + path
notify=notifydefault
def __init__(self,title=None):
import posix,posixpath
self.tlwin = Toplevel(None,{'class':'fs'})
self.tlwin.title(title)
self.root = Frame(self.tlwin,{Pack:{'expand':'1','fill':'both'}})
self.root.pack()
self.root1=Frame(self.root,{Pack: {'side':'top','fill':'both'} } )
self.root1.pack()
self.pwdlabel=Label(self.root1,{'font':'fixed',
'relief':'raised','text':'current dir'})
self.pwdlabel.pack()
self.pwdmenu=Menu(self.root1)

self.root2=Frame(self.root,{'bd':'2','relief':'ridge',
Pack: {'side':'top','expand':'1','fill':'both'} } )
self.root2.pack()
self.entry=Entry(self.root2,{'background':'gray90','font':'fixed',
'width':'40','relief':'ridge','bd':'3',
Pack:{'side':'top','fill':'x'}})
self.entry.pack()
self.dirbar=Scrollbar(self.root2,
{Pack: {'expand':'1','side':'right','fill':'y'} })
self.dirbar.pack()
self.dirbox=Listbox(self.root2,
{"geometry":"40x10","font":"fixed","relief":"raised","bd":"4",
"setgrid":"true",
Pack: {'fill':'both','side':'left','expand':'1'} } )
self.dirbox.pack()
self.dirbox['yscrollcommand'] = ( self.dirbar, 'set')
self.dirbar['command'] = ( self.dirbox, 'yview')
self.dirbox.tk_listboxSingleSelect()

self.root4=Frame(self.root,{Pack: {'side':'bottom','fill':'both'} } )
self.root4.pack()
self.root4a=Frame(self.root4,{'relief':'sunken',Pack: {'side':'left'} })
self.okbutton = Button(self.root4a,{'text':' Ok ','relief':'raised',
Pack: {'side':'left','padx':'2'} } )
self.okbutton.pack()
self.okbutton['command']=self.selected
self.cancelbutton = Button(self.root4,
{'text':' Cancel ','relief':'raised',
'command':self.nukePopup,
Pack: {'side':'left','padx':'2'} } )
self.cancelbutton.pack()
self.filterbutton = Button(self.root4,
{'text':' Filter ','relief':'raised','state':'disabled',
Pack: {'side':'left','padx':'2'} } )
self.filterbutton.pack()
self.optionbutton = Button(self.root4,{'text':' Options ',
'relief':'raised',
Pack: {'side':'right','padx':'2'} } )
self.optionbutton.pack()
self.optionmenu=Menu(self.root4)
self.statlabel=Label(self.root,{'foreground':'black',
Pack: {'side':'bottom','fill':'both'} })
self.statlabel.pack()
self.errorlabel=Label(self.root,{'foreground':'red',
Pack: {'side':'bottom','fill':'both'} })
self.errorlabel.pack()

# some bindings
self.dirbox.bind('<Double-1>',self.selected)
self.dirbox.bind('<1>',self.do_chosen_one)
self.optionbutton.bind('<1>',self.popup_optionmenu)
self.optionmenu.bind('<ButtonRelease-1>', self.popdown_optionmenu)
self.pwdlabel.bind('<1>',self.popup_pwdmenu)
self.pwdmenu.bind('<ButtonRelease-1>', self.popdown_pwdmenu)
self.entry.bind('<Key-Down>', self.key_move)
self.entry.bind('<Key-Up>', self.key_move)
self.entry.bind('<Key-space>', self.choose_selected)
self.entry.bind('<Key-Return>', self.selected)

# and final initialisation...
self.entry.focus_set()
self.init_optionmenu()
self.set_wd()

def nukePopup(self):
self.tlwin.withdraw()
del self

def __str__(self):
return str(self.root)

def key_move(self,e=None):
if (e.keysym=="Down"):
self.move_selected(1)
else:
if(e.keysym=="Up"):
self.move_selected(-1)

def move_selected(self,num):
cur=self.dirbox.curselection()
if(cur):
# barf...
new=eval(cur[0]+"+"+repr(num))
self.dirbox.select_clear()
self.dirbox.select_from(new)
self.dirbox.yview(new)
else:
self.dirbox.select_from(0)
self.dirbox.yview(0)

def choose_selected(self,e=None):
try:
item=self.dirbox.get(self.dirbox.curselection())
self.set_entry(item)
except:
None

def set_entry(self,text=None):
self.entry.delete('0','end')
if (text):
self.entry.insert('0',text)

def selected(self,e=None):
import posixpath
item=self.entry.get()
if (posixpath.isdir(item)):
self.set_wd(None,item)
else:
self.notify(item)
self.nukePopup()

def do_chosen_one(self,e):
new=self.dirbox.nearest(e.y)
self.dirbox.select_clear()
self.dirbox.select_from(new)
item=self.dirbox.get(self.dirbox.curselection())
self.set_entry(item)

def popup_pwdmenu(self,e):
x,y = e.x_root,e.y_root
self.pwdmenu.post(x - 10, y - 10)
self.pwdmenu.grab_set()

def popdown_pwdmenu(self,e=None):
self.pwdmenu.grab_release()
self.pwdmenu.unpost()
self.pwdmenu.invoke('active')

def init_optionmenu(self):
self.optionmenu.add('command',{ 'label':'Options' })
self.optionmenu.add('separator',{})
self.optionmenu.add('checkbutton',{ 'label':'Follow symlinks',
'state':'disabled'})
self.optionmenu.add('checkbutton',{ 'label':'Mark file types',
'state':'disabled'})
self.optionmenu.add('checkbutton',{ 'label':'Count files',
'state':'active'})
self.optionmenu.add('command',{ 'label':'Version'})
self.optionmenu.activate(4)

def popup_optionmenu(self,e):
x,y = e.x_root,e.y_root
self.optionmenu.post(x - 10, y - 10)
self.optionmenu.grab_set()

def popdown_optionmenu(self,e=None):
self.optionmenu.grab_release()
self.optionmenu.unpost()
self.optionmenu.invoke('active')

def count_wd(self,entries):
import posixpath
entries.remove("..")
i=0
for it in entries:
if(posixpath.isdir(it)):
i=i+1
return "%d directories, %d files." % ( i,(len(entries)-i) )

def set_wd(self,e=None,dir=None):
import posix,posixpath
if (dir == None):
dir=posix.getcwd()
else:
posix.chdir(dir)
dir=posix.getcwd()
self.pwdlabel['text']=dir

self.dirbox.delete('0','end')
ents=posix.listdir(dir)
ents.remove(".")
ents.sort()
for it in ents:
self.dirbox.insert("end",it)
# call this now, as it trashes .. too early otherwise
self.statlabel['text']=self.count_wd(ents)

#print "new dir is %s" % dir
self.pwdmenu.delete(0,"last")
self.set_entry()
while(1):
(new,cur)=posixpath.split(dir)
self.pwdmenu.add('command',{'label':cur+'/',
'command': lambda w=dir,m=self:m.set_wd(None,w) })
if (dir == "/"):
break
dir=new

--boundary=_0--