Select several directories with tkinter - python

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"?

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()

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):
For more, see tkinter.tix and Tk Tix docs

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?

Related

root = tkinter.Tk() or root = Tk()?

I have two scripts that both work:
import tkinter
root = tkinter.Tk()
root.configure(bg='blue')
root.mainloop()
and
from tkinter import *
root = Tk()
text = Text(root)
text.insert(INSERT, "Hello world!")
text.pack()
root.mainloop()
I want to combine the two scripts to print the text on a blue background, but moving anything from one script to another seems to break it.
I can't figure out if it's about root = tkinter.Tk() vs root = Tk(), or import tkinter vs from tkinter import *, or something entirely different. I can't find a successful combination.
I'm using Ubuntu and Python 3.6.9.
Because you use two different styles when importing tkinter, you will need to modify the code from one file when moving to the other. The code in your first example is the preferred way to do it because PEP8 discourages wildcard imports.
When when you copy the code from the second example, you'll need to add tkinter. to every tkinter command (tkinter.Tk(), tkinter.Text(root), tk.INSERT, etc.
Personally I find import tkinter as tk to be a slight improvement. I find tk.Tk() to be a little easier to type and read than tkinter.Tk().
You should know that:
from tkinter import *
will import all the attribute in the tkinter.But if you also define some variable in your script.It will be covered by your new variable.So we don't recommend you to use that.(If you used both from tkinter.ttk import * and from tkinter import *.Some default widgets of tkinter will be covered by ttk widgets.)
Just like Mr.Bryan said,I'd like to use import tkinter as tk,too.

Tkinter OptionMenu error

I'm having some issues getting my OptionMenu to work the first issue is that it wont work on it's on i have to use some placeholder label to get it to work. so in the below example it works if i use TaxYear as the master but not if i use TaxYearLi.
The second issue is that for some reason w.set("2018/2019") is not working i get an error that I'm passing a string not a stringvar
Edit: OK I've fixed the StringVar issue and setting a default value need to deffine root as Tk.Tk() if someone also could explain why this needs to be done that would be helpful.
import Tkinter as Tk
root = Tk.Tk()
w = Tk.StringVar
w.set("2018/2019")
TaxYear = Tk.Label(text="Select tax year")
TaxYear.grid(row=1, column=0)
TaxYearLi = Tk.OptionMenu(TaxYearLi, w, "2018/2019")
TaxYearLi.grid(row=1,column=1)
Tk.mainloop()
If you need to declare a variable (root in your case) as TK() is because Tk() is a class in Tkinter code which basicly create the window by asking it to your OS.
so you need to create a variable (some call it root others master, others parents) who's gona be your root/master/parent window and evry widget need to be on this variable.
Now about your OptionMenu, as i mentioned you need to put all your widgets on the main window (root in your case)
import Tkinter as Tk
root = Tk.Tk()
w = Tk.StringVar #in Python3 i need to put StringVar() i don't know about 2.x
w.set("2018/2019")
TaxYear = Tk.Label(text="Select tax year")
TaxYear.grid(row=1, column=0)
TaxYearLi = Tk.OptionMenu(root, w, "2018/2019") #needs to be on the root window
TaxYearLi.grid(row=1,column=1)
root.mainloop()

Removing/forgetting widgets on tkinter

I'm new to the Tkinter module (and quite new to python) I can't for the life of me figure out how to use the remove or forget methods to hide widgets in a grid. I can't seem to find relevant examples online and the tutorial documents have given me everything but the syntax. Below is the code I've been using to try and figure it out. Apologies if this overly trivial...
from tkinter import *
from tkinter import ttk
def delete():
#where I would like to delete the label 'label'
window = Tk()
window.title("Window")
window.configure(background='#e4e5ff')
label = ttk.Label(window, text='text').grid(column=1, row=0)
ttk.Button(window, text='text',command = delete).grid(column=2,row=0)
window.mainloop()
To do that you will have to use 2 lines to define and layout the widget (which is good practice anyway).
from tkinter import *
from tkinter import ttk
def delete():
label.grid_forget()
window = Tk()
window.title("Window")
window.configure(background='#e4e5ff')
label = ttk.Label(window, text='text')
label.grid(column=1, row=0)
btn = ttk.Button(window, text='text',command = delete)
btn.grid(column=2,row=0)
window.mainloop()
However, I suspect this is an XY problem. Are you trying to delete it in order to replace it with another Label? If so, you need to update the current label, not delete it and replace it.
def delete():
label.config(text='new_text')

tkinter: user defines folder name throug entry

I am new to tkinter, and i have been trying to have an entry input create and name a folder in the directory. I can create a folder, but i can not get the entry variable to name the folder. I have been stuck on this for a few days now and would appreciate any example code you can make available for me. Thank you.
WOW!!! I've been trying to figure this out for 4 days now.... it just came to me... So simple. I'll share.
from Tkinter import *
import os,sys, shutil
master = Tk()
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
def pt():
final_path = os.path.join('./' + str(v.get()))
os.mkdir(final_path)
b = Button(master, text="get", width=10, command=pt)
b.pack()
mainloop()
Since you have not shared your solution, and this is a Q/A site, I will do my best to answer the question for further visitors :)
I think you are over-complicating the business here, since this can be done like this as well:
from Tkinter import *
import os,sys, shutil
master = Tk()
def b_command():
final_path = os.path.join('./' + str(e.get()))
os.mkdir(final_path)
e = Entry(master)
e.pack()
b = Button(master, text="get", command=b_command)
This is nothing different, but setting up a "TextVariable" and using .get() on it is not practical because it might cause slowdowns, and in your case, prevent the code from being executed correctly.
I am curious of your solution though. Be sure to share it as soon as possible :)
Regards.
EDIT: Fixed the Button syntax.

ttk: how to make a frame look like a labelframe?

Python ttk gui creating is easy and has mostly native look and feel (win7). I am having a slight problem, though:
I would like to have a frame that looks like ttk.LabelFrame but without label. Just omitting the text option will leave an ugly gap.
Also I can not get the ttk.Frame border to look like LabelFrame. Is there an elegant way of doing this? Bonus karma if this works on all/most windows versions above xp.
Maybe it works with styles but the style LabelFrame properties seem mostly empty (style.element_options("border.relief")). Maybe I am looking in the wrong place.
edit:
try: # python 3
from tkinter import * # from ... import * is bad
from tkinter.ttk import *
except:
from Tkinter import *
from ttk import *
t = Tcl().eval
print("tcl version: " + str(t("info patchlevel")))
print("TkVersion: " + str(TkVersion))
root = Tk()
lF = LabelFrame(root, text=None)
lF.grid()
b = Button(lF, text='gonzo')
b.grid()
f = Frame(root, relief="groove") #GROOVE)
f.grid()
b2 = Button(f, text='gonzo')
b2.grid()
f2 = Frame(root, relief=GROOVE, borderwidth=2)
f2.grid()
b3 = Button(f2, text='gonzo')
b3.grid()
mainloop()
output on win7 with freshly downloaded python 3.2.3:
tcl version: 8.5.9
TkVersion: 8.5
There is python 2.6.6 installed on this machine, too (same problem). Each installation seems to be using the correct tk/tcl, though.
OK, seems like one solution to getting the LabelFrame without the gap is to use an empty widget in place of the text. So, modifying the first part of your example slightly:
# don't do the 'from tkinter import *' thing to avoid namespace clashes
import tkinter # assuming Python 3 for simplicity's sake
import tkinter.ttk as ttk
root = tkinter.Tk()
f = tkinter.Frame(relief='flat')
lF = ttk.LabelFrame(root, labelwidget=f, borderwidth=4)
lF.grid()
b = ttk.Button(lF, text='gonzo')
b.grid()
root.mainloop()
Seems to work for me with the regular Win7 theme.

Categories