My Tkinter function doesn't display buttons (and its not image related!) - python

I am building a language select GUI: The following are the two functions that are called when the primary language is selected:
def set_language(language):
global selected_language
selected_language = language
print(f"Selected language: {selected_language}")
header.destroy()
LeftFrame.destroy()
create_buttons()
def create_buttons():
global doctor_button, center
center = tk.Label(root)
center.grid()
doctor_button = tk.Button(root,
text="doctor",
highlightbackground="#f2f2f2",
highlightcolor="#dddddd",
command=lambda: main(selected_language,"doctor"))
center.grid(row=1, column=1, padx=20, pady=20)
I am calling the function set_language from another button. My initial call is the following:
root = tk.Tk()
choose_languages()
root.mainloop()
However the buttons are not displayed, and it has nothing to do with images not being displayed. I am currently not using classes. This is not a duplicate question!

Related

Tkinter SyntaxError: keyword argument repeated: state (how to make a button one time clickable?)

from tkinter import *
def Click():
label = Label(root, text="You clicked it")
label.pack()
root = Tk()
label2 = Label(root, text="You can only click one time")
Button = Button(root, text="Click me", padx=20, pady=20, state=NORMAL,
command=Click,state=DISABLED)
Button.pack()
label2.pack()
root.mainloop()
Because I use state 2 times I am getting this error:
SyntaxError: keyword argument repeated: state
How can I fix this error and make a button that can be clicked one time?
This should do what you want. The idea is to update the button's state from within the click handler function.
FYI, star imports can cause trouble and are best avoided, so I've done that here. I've also changed some variable names to use lowercase, since capitalized names are typically reserved for class objects in Python (things like Label and Tk, for instance!)
import tkinter as tk
def click():
label = tk.Label(root, text="You clicked it")
label.pack()
button.config(state=tk.DISABLED) # disable the button here
root = tk.Tk()
label2 = tk.Label(root, text="You can only click one time")
button = tk.Button(root, text="Click me", padx=20, pady=20, command=click)
button.pack()
label2.pack()
root.mainloop()
Bonus Round - if you want to update the existing label (label2, that is) instead of creating a new label, you can also accomplish this with config
def click():
label2.config(text="You clicked it") # update the existing label
button.config(state=tk.DISABLED) # disable the button here

How to get value from dependent combobox tkinter python?

I'm able to select both the combo box successfully but to print the second dropdown box value, I got lost. Could somebody explain how to print the Table value from the 2nd drop down box.
Note: The two drop downs are dependabale.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("ETL")
Environment = ["UAT","ITEST","PROD"]
Tables = [["USER_UAT","IP_UAT"],
["USER_ITEST","IP_ITEST"],
["USER_PROD","IP_PROD"]]
envi= ttk.Combobox(root,width =37, value=(Environment))
envi.grid(row=3,column=1,columnspan=2, padx=10, pady=2, sticky='w')
def callback(eventObject):
abc = eventObject.widget.get()
en = envi.get()
index=Environment.index(en)
tab.config(values=Tables[index])
tab=ttk.Combobox(root, width=37)
tab.grid(row=4,column=1,columnspan=2, padx=10, pady=2, sticky='w')
tab.bind('<Button-1>', callback)
root.mainloop()
The most straightforward way is to add a separate event binding for each combobox. I changed the bindings from <Button-1> to <<ComboBoxSelect>> as this prevents the events from being fired every time a combobox is clicked - instead, events will only fire when a selection is actually made.
I also added some code to set the combobox default values as well as to update the value of the second combobobox whenever a selection is made in the first combobox.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title('ETL')
environment = ['UAT', 'ITEST', 'PROD']
tables = [
['USER_UAT', 'IP_UAT'],
['USER_ITEST', 'IP_ITEST'],
['USER_PROD', 'IP_PROD'],
]
def populate_table_combobox(event):
index = environment.index(env_combo.get())
table_combo.config(values=tables[index])
table_combo.current(0) # update the 'table' selection when 'env' changes
def get_table_combo_value(event):
print(table_combo.get()) # YOUR CODE HERE!
env_combo = ttk.Combobox(root, width=37, value=environment)
env_combo.current(0) # set default value
env_combo.grid(row=3, column=1, columnspan=2, padx=10, pady=2, sticky='w')
table_combo = ttk.Combobox(root, width=37, values=tables[0])
table_combo.current(0) # set default value
table_combo.grid(row=4, column=1, columnspan=2, padx=10, pady=2, sticky='w')
env_combo.bind('<<ComboBoxSelected>>', populate_table_combobox)
table_combo.bind('<<ComboBoxSelected>>', get_table_combo_value)
root.mainloop()

Tkinter Python, get() does not save any entry text. How should I fix it?

I'm using Tkinter for the GUI for my project (if you type ingredients you want into a textbox, it will return recipes using API.. and so on). I'm trying to save the user input into a variable so that I can use it later. However, the get() function seems like not catching anything. I've read a different post but not sure what I'm doing it wrong. Here is my code:
import tkinter as tk
import tkinter.font as font
# globally declare the expression variable
expression = ""
def getSentence():
global expression
# clear the entry fields
deleteEntryFields()
# ask a question
field2.insert(0, 'What do you want to eat? You can express and we will find something for you!')
expression = v.get()
return expression
def getIngredients():
pass
def searchWithSentence(sentence):
pass
def searchIngredients(ingredients):
pass
################################################################################
# This is where I'm testing if the user input is saved to a variable expression.
def enter():
field1.insert(0, str(expression))
print(expression)
################################################################################
def clear():
global expression
expression = ""
def deleteEntryFields():
field1.delete(0, 'end')
field2.delete(0, 'end')
# Driver code
if __name__ == "__main__":
# create a GUI window
master = tk.Tk()
v = tk.StringVar()
field1 = tk.Entry(master, textvariable=v)
field2 = tk.Entry(master)
field1.insert(0, 'Please type here')
field2.insert(0, 'Results will be shown here.')
field1.place(x=20, y=20, width=730, height=50)
field2.place(x=20, y=80, width=730, height=500)
# set the background colour of GUI window
master.configure(background="lemon chiffon")
# set the title of GUI window
master.title("Recipe Finder")
# set the configuration of GUI window
master.geometry("1050x600")
# set font
myFont = font.Font(family='Verdana', size=9, weight='bold')
# Buttons
button1 = tk.Button(master, text=' What do you feel like eating? ', fg='black', bg='salmon',
command=getSentence, height=5, width=30)
button1.place(x=770, y=100)
button1['font'] = myFont
button2 = tk.Button(master, text=' Type the ingredients you have! ', fg='black', bg='orange',
command=getIngredients, height=5, width=30)
button2.place(x=770, y=200)
button2['font'] = myFont
Clear = tk.Button(master, text=' CLEAR ', fg='black', bg='white',
command=clear, height=5, width=30)
Clear.place(x=770, y=300)
Clear['font'] = myFont
Enter = tk.Button(master, text=' ENTER ', fg='black', bg='white',
command=enter, height=5, width=30)
Enter.place(x=770, y=400)
Enter['font'] = myFont
# start the GUI
master.mainloop()
Previously I was not using StringVar(), but when I did some research, it says it can be one of the ways to get the get() function worked. But nothing happened... How can I effectively get user input and save it to global variable?
Any advice will be appreciated!
You are using the Entry itself to contain an explanation what to type?
To make that work you could bind a callback that clears the entry to the <FocusIn> event.
This will make sure that the entry field is empty when the user wants to type something.
And to be consistent, you would have to restore that text on a <FocusOut> event in the case that the user didn't fill in anything.
While this is used in places where screen space is extremely limited, it doesn't feel like good UI design.
A more common method is to put a Label with a description before the Entry.

Python tkinter 8.5 - How do you change focus from main window to a pop up window?

I'm new to tkinter and have a rather simple question. I would like to change focus from the first window, root, to the txt window after it pops up. I would also like the "OK" button to be focused as well. Of course, the idea is for the user to just be able to hit enter when they see this error. I'm terribly confused after various attempts with focus(), focus_set(), and takefocus. I'm not finding the documentation for this particularly helpful.
Below is my code:
from tkinter import *
from tkinter import ttk
def close(self):
self.destroy()
def browse(*args):
fileName = filedialog.askopenfilename()
guiInputFile_entry.insert(0, fileName)
return fileName
def formatInput(*args):
if guiInputFile.get()[-4:] != ".txt": #checks for correct file extension (.txt)
txt = Tk()
txt.title("Error")
txtFrame = ttk.Frame(txt, padding="30 30 30 30")
txtFrame.grid(column=0, row=0, sticky=(N,W,E,S))
txtFrame.columnconfigure(0, weight=1)
txtFrame.rowconfigure(0, weight=1)
ttk.Label(txtFrame, text = "Please enter a .txt file.\n").grid(column=2, row=1)
okButton = ttk.Button(txtFrame, text = "OK", command = lambda: close(txt)).grid(column=2, row=2)
return
root = Tk()
root.title("Cost Load Formatter")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N,W,E,S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
guiInputFile = StringVar()
guiInputFile_entry = ttk.Entry(mainframe, width=100, textvariable=guiInputFile)
guiInputFile_entry.grid(column=1, row=2, stick=(W,E))
ttk.Label(mainframe, text="Please enter the full filepath of the .txt file you wish to format:").grid(column=1, row=1)
browseButton = ttk.Button(mainframe, text="Browse...", underline=0, command=browse).grid(column=2, row=2, sticky=W)
formatButton = ttk.Button(mainframe, text="Format", underline=0, command= lambda: formatInput(guiInputFile)).grid(column=1, row=3)
for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)
guiInputFile_entry.focus()
root.mainloop()
Thank you for any light you can shed.
You're on the right track.
Firstly, you should only ever have one instance of Tk at a time. Tk is the object that controls the tkinter application, it just so happens that it also shows a window. Whenever you want a second window (third, fourth, etc.) you should use Toplevel. You can use it as you have used Tk, just pass it root:
txt = Toplevel(root)
It is just missing things like mainloop.
Secondly grid and pack do not return anything. So for example:
okButton = ttk.Button(txtFrame, text = "OK", command = lambda: close(txt)).grid(column=2, row=2)
Should be:
okButton = ttk.Button(txtFrame, text = "OK", command = lambda: close(txt))
okButton.grid(column=2, row=2)
But you should have been getting an error if that was causing you problems.
So to answer your main question, as you do with the Entry at the bottom you just call focus on the appropriate widget. focus_set does exactly the same, in fact if you look in Tkinter.py you will find focus_set is the name of the method, and focus is just an alias.
This will give the widget focus when the application has focus. If the application is not in focus there are ways to force it into the focus, but it is considered impolite and you should let the window manager control that.
Instead of making a seperate Tk Window, you could use the built in tkmessagebox. This will give the window and OK button focus right out of the box.
Something like this:
tkMessageBox.showinfo("Warning","Please enter a .txt file.")
http://www.tutorialspoint.com/python/tk_messagebox.htm
Also, note I wrote this in Python 2.7, the syntax may be slightly different for Python 3, but the functionality should be the same.

Why is Tkinter Entry's get function returning nothing?

I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()

Categories

Resources