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.
Related
I have a program in python which in which I use Listboxes, buttons and labels. So today I came conflicting with a problem. I wanted to make my listbox appear when a button is clicked and disappear when the same button is clicked again. How can I achieve this? I tried using the winfo_ismapped() method but didnt seem to work. I think I might have done something crazy. If so, please point it out and give me a corrected answer. Else please tell me a better way to do it.
My Code:
import tkinter as tk
from tkinter import *
root = tk.Tk()
root.geometry('500x500')
def showMenu():
overlay = Listbox(root, bg="green", height=22, width=58)
if overlay.winfo_ismapped() == 0:
overlay.place(x=0,y=35)
else:
overlay.placeforget()
button = tk.Button(root,text="place/remove", command=showMenu)
button.place(x=0,y=0)
root.mainloop()
Actually it comes when I press the button but hide after I press it again.
In the same way I have another issue with these labels too.
CODE:
import tkinter as tk
root = tk.Tk()
def placeFun():
successtext = tk.Label(root, text="Success", anchor='nw', bg="#212121", fg="#ff3300",font=("Consolas", 15, "bold"))
if successtext.winfo_ismapped() == 0:
successtext.place(x=0,y=50)
else:
succestext.forget()
button = tk.Button(root, text='place/rem', width=25, command=placeFun)
button.place(x=0,y=0)
root.mainloop()
Please Note: I want a professional way to handle this, I said it because, I know a way in which we use variables like:
globalvartimes = 0
def somefunc():
if times % 2 == 0:
show the listbox
global times
times += 2
else:
remove the listbox
times += 1
*This shows the listbox when times is even and remove it when it's odd.
These makes the code look non-professional and long.
The problem is every time showMenu() is called another Listbox is created. To fix that, create the Listbox outside of the function (so it's a global).
(I also noticed you misspelled the name of place_forget() method.)
import tkinter as tk
from tkinter import *
root = tk.Tk()
root.geometry('500x500')
def showMenu():
if overlay.winfo_ismapped(): # Placed?
overlay.place_forget()
else:
overlay.place(x=0,y=35)
overlay = Listbox(root, bg="green", height=22, width=58)
button = tk.Button(root,text="place/remove", command=showMenu)
button.place(x=0,y=0)
root.mainloop()
This looks like it is what is wrong with your Label example, too.
Note: If you want to write "professional" code, I suggest you read (and start following) the
PEP 8 - Style Guide for Python Code.
Beginner programmer here, working on making a basic GUI as part of a tutorial I was following online, but none of them say how to get a Text box to update using the output of the other parts of your code.
I tried multiple other answers on the site, including one using StringVar's, which got me nowhere, another using a decorator, and the rest seemed way out of my depth.
Here's my code:
import tkinter as tk
import time
#Creating Root
root = tk.Tk()
#GUI TEMPLATE
frame =tk.Frame(root,
height = 100,
width = 400)
frame.pack()
v = StringVar()
colour = ["red","blue","green","white","yellow"]
labels = range(5)
#change number to change how many labels
for i in range(5):
l= tk.Label(root,
text = colour[i],
bg = colour[i])
l.place(x = 10 +i*70, y = 10, width=60, height=25)
T1 = tk.Text(root, height=2, width=40)
words = "Don't name your files after module names!"
T1.insert(tk.END, textvariable=v)
T1.place(x = 10, y= 40)
S = tk.Scrollbar(root)
S.config(command=T1.yview)
S.place(x = 340, y=40)
T1.config(yscrollcommand=S.set)
root.mainloop()
v.set("Something Else!")
Now, what it should output is a row of coloured labels, which works fine, and a text box with a scroll bar, which should instantly update to read 'Something Else!', which does not work fine.
Instead I get the following error:
NameError: name 'StringVar' is not defined
I know what this error means, it's just I've hit a wall when it comes to finding a solution that works for me, and doesn't need a doctorate to understand.
What I'm asking for is if someone can give me a solution that would work for this, and hopefully explain it!
Thanks in advance.
EDIT:
So after fixing the syntax error, and then finding out what I'm trying to do doesn't work, how would I go about this?
Could I use a label instead? Or is there another, better way?
Thanks again!
StringVar should accessed via tk:
v = tk.StringVar()
On another note, tk.Text.insert does not take a textvariable parameter, so the following won't work:
T1.insert(tk.END, textvariable=v)
# ^^^^^^^^^^^^??
From the docs:
Unlike for example the entry widget, text widgets don't support a
"textvariable" configuration option
Also see How can I connect a StringVar to a Text widget in Python/Tkinter? as to why this won't work.
I was experimenting with learning threading with Tkinter and have made something work to insert and update text in a Tkinter text box in Python3 which may be of help.
I found that by deleting the text I could then insert new text. Untill I deleted the existing text the instruction to insert text seamed to be ignored.
{ foo = input("Give me input: " )
self.T.delete("1.0", END) #Clear the text window so we can write.
self.T.insert(END,foo) #Write the new text.}
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?
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.
I am making a Tkinter GUI to do nothing except call images - and of course, I have struggled to find decent tkinter documentation all along.
There is a line of my code which cannot seem to do as asked - I want to call up all the values in a dictionary and individually print and pull an image by the same name for each one before the next value is called up. I have tried dict.itervalues() and dict.values() and can't seem to figure anything out altogether...
Anyway, here is the snippet:
for key in ansDict.iterkeys(): #using the iterkeys function... kind of
x=key
root = tk.Tk() # root window created (is this in the right place?)
root.title('C H E M I S T R Y A B C\'s')
frameAns=tk.Frame(root)
frameAns.grid(row=0, column=0, sticky=tk.NW)
for i in range(len(ansDict[x])):
print '-->' + ansDict[x][i]
for value in ansDict.itervalues(): #This is the most important part
for i in range(len(value)): #pulls value list from dictionary named ansDict
picRef1 = Image.open(value[i] + '.jpg') #calls image file by the same name using PIL
photo1 = ImageTk.PhotoImage(picRef1, master=root)
button1 = tk.Button(frameAns, compound=tk.TOP, image=photo1, text=str(value[i]) + '\nClose me!', bg='white') #pulls up button onto which the image is pasted
button1.grid(sticky=tk.NW, padx=2, pady=2) #places button on grid
button1.image=photo1
root.mainloop()
Finally, at the end, it pulls up one or two images and then I get the following error:
TclError: can't invoke "image" command: application has been destroyed
and I can't figure out what is wrong. I can't move the image command, and somehow I need to "save" it so it isn't destroyed. I know there are other code errors here, but I think that if I figure out the TclError that I am getting that I can set everything else straight.
If there is an easier way to do all this please do tell!
I have looked around for a good solution to this but have yet to find the proper solution. Looking at the Tkinter.py class it looks like the Image del value is:
def __del__(self):
if self.name:
try:
self.tk.call('image', 'delete', self.name)
except TclError:
# May happen if the root was destroyed
pass
This means if you wanted to do a BRUTAL hack you could setup a PhotoImage as described in jtp's link.
photo = tk.PhotoImage(file="C:/myimage.gif")
widget["image"] = photo
widget.image = photo
Then you could just before the program exited do the following hack:
photo.name = None
This would prevent it from trying to clean itself up in the PhotoImage delete and prevent the exception from being called in the del method. I do not really recommend you do this unless your back is up against the wall, and you have no alternative.
I will continue to look into this and if I find a better solution will edit this post with a better one (hopefully someone will give the correct solution before then).
Here is one possibility, although it is structured differently than your example. It stacks the four 100 pixel square images on top of one another. I believe you need to keep a separate reference to each Image object, so I tucked them away in the images dictionary.
from Tkinter import *
import os
from PIL import Image, ImageTk
image_names = { '1':'one','2':'two','3':'three','4':'four' }
images = {}
root = Tk()
root.title("HELLO")
frm = Frame(root)
for v in image_names.itervalues():
images[v] = {}
images[v]['i'] = Image.open("%s%s.jpg" % (os.path.dirname(__file__), v))
images[v]['pi'] = ImageTk.PhotoImage(images[v]['i'])
images[v]['b'] = Button(frm, image=images[v]['pi'])
images[v]['b'].pack()
frm.pack()
mainloop()
Here is a good link discussing the PhotoImage class.
http://effbot.org/tkinterbook/photoimage.htm
It seems that you did not get the idea of Event-driven programming. You should create whole GUI once, fill it with widgets, setup the events and then enter infinite loop. The GUI should call callback functions based on your event to function binding. So those parts of your program should definitely be called just once: root = tk.Tk(), root.mainloop().
Edit: Added Event-driven programming "idea example".
from Tkinter import *
master = Tk()
def callback():
print "click!"
b = Button(master, text="OK", command=callback)
b.pack()
mainloop()