4

I am using Tkinter for building a GUI for a python script. I need a button which opens up a dialog box which allows me to select both files and directories. Till now, I've come across

tkFileDialog.askdirectory(parent=root, title=dirtext1)

which allows just to select directories in the dialog box and,

tkFileDialog.askopenfilename(parent=root, title=filetext)

which allows me to just select files. As of now, I access these dialog boxes using separate buttons, each of which calls one of these functions. Is there anyway to select either a file or a folder using a single dialog box?

Dhruv Mullick
  • 551
  • 9
  • 25
  • 1
    You want to call `askdirectory()` and `askopenfilename()` in sequence when the button is pressed? – Stop harming Monica Mar 25 '16 at 17:01
  • No, I want there to be a common dialog box for selecting either files or folders. (Edited the question to make this clear) – Dhruv Mullick Mar 25 '16 at 17:02
  • While their is no built in way to really do this in tkinter, you could ask the user to select a file using `tkinter.askopenfilename()` and then use `os.path.dirname()` on the file selected to get the directory the file was selected from, effectively returning both a file and also a directory, all from the same dialog. – R. Kap Mar 25 '16 at 17:07
  • Ah. That would be workaround, though it doesn't seem good from the user's point of view. – Dhruv Mullick Mar 25 '16 at 17:09
  • I don't think you can, each task requires a different behaviour. If the user selects a directory and press the 'OK' or 'Open' button or double click, should the dialog show the contents of the directory or just return it? – Stop harming Monica Mar 25 '16 at 17:11
  • Well, there really is not any direct way to accomplish this using tkinter. There are either built in dialog boxes for either files or folders, but there is none for both. – R. Kap Mar 25 '16 at 17:13
  • @Goyo, a double click would show the contents of the directory, but an 'Ok' would return the path of the directory. – Dhruv Mullick Mar 25 '16 at 17:14
  • I'm afraid you would need to implement that behaviour yourself and there aren't many reusable components that you could use. The answers in this question can give you a hint: http://stackoverflow.com/questions/14686543/python-tkinter-adding-widgets-to-file-dialogs – Stop harming Monica Mar 25 '16 at 17:26

2 Answers2

9

I don't think so. There is no built-in class to do it easily

Investigation

If you look at the tkFileDialog module's source code, both the Open and the Directory classes inherit from _Dialog, located in tkCommonDialog.

Good so far; these classes are simple and only extend two methods. _fixresult is a hook that filters based on your options (promising), and _fixoptions adds the right tcl parameters (like initial directory).

But when we get to the Dialog class (parent of _Dialog), we see that it calls a tcl command by a given name. The names built-in are "tk_getOpenFile" and "tk_chooseDirectory". We don't have a lot of python-level freedom of the command after this. If we go to see what other tcl scripts are avaliable, we are disappointed.

Looks like your options are

  • ttk::getOpenFile
  • ttk::getSaveFile
  • ttk::chooseDirectory
  • ttk::getAppendFile

Conclusion

Rats! Luckily, it should be quite easy for you to make your own dialog using listboxes, entry fields, button, (and other tk-builtins), and the os module.

Simple Alternative

From your comments, it looks like a viable simple work-around might be to use

directory = os.path.dirname(os.path.realpath(tkFileDialog.askopenfilename()))

They'll have to select a file, but the "Open" button will "return a path", in the sense that the path is computed from the file location

But I really want it!

If for some reason you really want this behaviour but don't want to remake the widget, you can call tcl scripts directly. It may be possible to copy the code from getOpenFile and provide more loose arguments that allow for selecting a more generic object. This isn't my speciality and seems like a really bad idea, but here is how you call tcl directly and here is where you can learn more about the underlying commands.

Community
  • 1
  • 1
en_Knight
  • 5,301
  • 2
  • 26
  • 46
0

I've had a similar issue. In the end, I used askopenfilenames() (plural) and split the path from the files. Then with a radiobutton, ask the user to choose if they want to process all the files in the directory, or just those they selected.

filetypes = [('All files', '*.*'), ('CSV files', '*.csv'),]
data_list = askopenfilenames(title='Select folder', filetypes=filetypes)
data_dir = data_list[0].rsplit('/', 1)[0]

I mention it because askopenfilenames() doesn't get suggested much, but is closer to selecting a folder, as can ctrl+A all files.

Yobmod
  • 395
  • 3
  • 5
  • 18