Select several directories with tkinter
Asked Answered
S

4

5

I have to perform an operation on several directories.

TKinter offers a dialog for opening one file (askopenfilename), and several files (askopenfilenames), but is lacking a dialog for several directories.

What is the quickest way to get to a feasible solution for "askdirectories"?

Sham answered 31/8, 2016 at 8:32 Comment(0)
C
6

Unfortunately, tkinter doesn't natively support this. A nice looking alternative is tkfilebrowser. Code based on Luke's answer using tkfilebrowser is below:

import tkfilebrowser
from tkinter import *

root = Tk()
root.geometry('200x200')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)

dirs = []

def get_directories():
    dirs.append(tkfilebrowser.askopendirnames())
    return dirs

b1 = Button(root, text='select directories...', command=get_directories)
b1.pack()

root.mainloop()
Crematory answered 20/3, 2020 at 5:17 Comment(0)
B
2

The only way for doing this in pure tkinter (except building the directory selector widget by hand) is requesting user for each dir in separate dialog. You could save previously used location, so user won't need to navigate there each time, by using code of below:

from tkinter import filedialog
dirselect = filedialog.Directory()
dirs = []
while True:
    d = dirselect.show()
    if not d: break
    dirs.append(d)

Another solution is to use tkinter.tix extension (now part of standard lib, but may require to install Tk's Tix on some platforms). Primarly, you'll need the tkinter.tix.DirList widget. It look as follows (a bit old img):

img

For more, see tkinter.tix and Tk Tix docs

Brunabrunch answered 31/8, 2016 at 10:13 Comment(2)
Nice solution, but I do not want to install any new extensions if possible, would have to do it for a lot of computers... Might have to programm that myself with tkinter.Sham
@Sham thx. Or you may simply freeze your executables or make distutils packageBrunabrunch
A
1

You should be able to use tkFileDialog.askdirectory. Take a look at the docs here :)

EDIT

Perhaps something like this?

from Tkinter import *
import tkFileDialog

root = Tk()
root.geometry('200x200')
root.grid_rowconfigure(0, weight = 1)
root.grid_columnconfigure(0, weight = 1)

dirs = []
def get_directories():
    dirs.append(tkFileDialog.askdirectory())
    return dirs

b1 = Button(root, text='select directories...', command = get_directories)
b1.pack()


root.mainloop()

Any thoughts?

Any answered 31/8, 2016 at 9:27 Comment(2)
Apologies, upon closer inspection there doesnt seem to be an in built method for more than one directory.... The only way round this would be to append each directory to a global / instance variable each time you click 'ok' on the filedialog box... Unfortunatley this means having to accept and re-do for each directory :/ Im assuming you were looking for more or a ctrl + click vibe....Any
You are right about me being a ctrl+ click type of person ;-)Sham
P
0

I've been on the hunt for something like this myself. However, I don't just need directories returned, but a mix of directories and (normal) files. None of the suggestions above would give me that. Besides, the tix solution, when testing, gave me "deprecation" warning and, according to the documentation only returns single directory names.

Installing the tkfilebrowser seemed much too much effort just for testing as, according to the documentation, I wouldn't get a mix of files and directories either.

So, I've written a small (relatively) function, using just modules that should be available in any recent (3.x) Python build environment. Below is a prototype, not very pretty, but it does the trick. As you'll notice I've used the standard tkFileDialog function to get a single directory name returned, when trying to go up from the root directory under Windows, to have access to other drives.

import os
import platform
from tkinter import *
from tkinter import ttk, filedialog as fd

def askopennames(initialDir='.'):
    if not initialDir: return ('',[])
    curdir = [initialDir]
    returnList = []
    top = Toplevel()
    top.columnconfigure(0, weight=1)
    pbtn = Button(top, text="print selection")
    
    def build_tree(dir):
        updir = os.path.join(os.path.abspath(dir), '..')

        def go_updir(): 
            p = os.path.abspath(updir) 
            dnp = os.path.dirname(updir)
            retdir = fd.askdirectory(initialdir=dnp) \
                if os.path.samefile(p, dnp) and \
                  platform.system() == 'Windows' else p
            curdir[0] = retdir if retdir else dnp
            build_tree(curdir[0])

        tree = ttk.Treeview(top, height=17)
        tree.columnconfigure(0, weight=1)
        tree.heading('#0', text=updir, anchor='w', command=go_updir)
        for c in os.listdir(dir):
            iid = tree.insert('', 'end', text=c, open=False)
            if os.path.isdir(os.path.join(dir,c)): tree.insert(iid, "end")
        tree.grid(row=0, sticky='ew')
        pbtn.grid(row=1, sticky='nsew')

        def get_selection():
            returnList.extend([tree.item(s)['text'] \
                for s in tree.selection() if tree.item(s)['text']])
            top.destroy()

        pbtn['command'] = get_selection

        def rebuild_tree(e):
            folder = tree.item(tree.focus())['text']
            curdir[0] = os.path.join(dir, folder)
            tree.destroy()
            build_tree(curdir[0])

        tree.bind('<<TreeviewOpen>>', rebuild_tree)

    build_tree(curdir[0])
    top.wait_window()
    return (curdir[0], returnList)
  

root = Tk()
def getDirPath(): print(askopennames('.'))
Button(root, text="ok", font=("Helvetica", "13"),
       command=getDirPath).grid(ipadx=100)

root.mainloop()
Pascoe answered 2/8, 2023 at 7:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.