Make a dictionary using tkinter, GUI - python

I want to make a dictionary by using a GUI, I was thinking of making two entries, one for the object and the other for the key. And I want to make a button that execute the information and add it to the empty dictionary.
from tkinter import *
fL = {}
def commando(fL):
fL.update({x:int(y)})
root = Tk()
root.title("Spam Words")
label_1 = Label(root, text="Say a word: ", bg="#333333", fg="white")
label_2 = Label(root, text="Give it a value, 1-10:", bg="#333333", fg="white")
entry_1 = Entry(root, textvariable=x)
entry_2 = Entry(root, textvariable=y)
label_1.grid(row=1)
label_2.grid(row=3)
entry_1.grid(row=2, column=0)
entry_2.grid(row=4, column=0)
but = Button(root, text="Execute", bg="#333333", fg="white", command=commando)
but.grid(row=5, column=0)
root.mainloop()
I want to use that dictionary later in my main program. You see if it would be a function, I would just go in IDLE and do..
def forbiddenOrd():
fL = {}
uppdate = True
while uppdate:
x = input('Object')
y = input('Key')
if x == 'Klar':
break
else:
fL.update({x:int(y)})
return fL
And then just use the function further on in my program
Any suggestions?
I appreciate it. Thank you

You are close to achieving what you want. There are a few modifications that need to be made. First, lets start with the entry boxes entry_1 and entry_2. Using a text variable like you did is a good approach; however I did not see them defined, so here they are:
x = StringVar()
y = StringVar()
Next, we need to change how you call the commando function and what parameters you pass though it. I want to pass the x and y values though, but I can't do this by just using something like command=commando(x.get(), y.get()), I need to use lambda as follows:
but = Button(root, text="Execute", bg="#333333", fg="white", command=lambda :commando(x.get(), y.get()))
Now why did I pass the values x and y as x.get() and y.get()? In order to get the values from a tkinter variable such as x and y, we need to use .get().
Finally, let's fix the commando function. You cannot use it as you did with fL being the parameter. This is because any parameter you set there becomes a private variable to that function even if it appears elsewhere in you code. In other words, defining a function as def commando(fL): will prevent the fL dictionary outside the function from being assessed within commando. How do you fix this? Use different parameters. Since we are passing x and y into the function, let's use those as parameter names. This is how our function looks now:
def commando(x, y):
fL.update({x:int(y)})
This will create new items in your dictionary. Here is the completed code:
from tkinter import *
fL = {}
def commando(x, y):
fL.update({x:int(y)}) # Please note that these x and y vars are private to this function. They are not the x and y vars as defined below.
print(fL)
root = Tk()
root.title("Spam Words")
x = StringVar() # Creating the variables that will get the user's input.
y = StringVar()
label_1 = Label(root, text="Say a word: ", bg="#333333", fg="white")
label_2 = Label(root, text="Give it a value, 1-10:", bg="#333333", fg="white")
entry_1 = Entry(root, textvariable=x)
entry_2 = Entry(root, textvariable=y)
label_1.grid(row=1)
label_2.grid(row=3)
entry_1.grid(row=2, column=0)
entry_2.grid(row=4, column=0)
but = Button(root, text="Execute", bg="#333333", fg="white", command=lambda :commando(x.get(), y.get())) # Note the use of lambda and the x and y variables.
but.grid(row=5, column=0)
root.mainloop()

Related

retrieve selected value from a binded combobox in tkinter

I am trying to retrieve the selected value from a binded combobox.
In the below code, I have binded the combobox named “LSF_Combo” to another combobox “Queue _Combo” . I am trying to retrieve the selected value from the “Queue_Combo”, using Queue_Combo.get() method, but I am not able to do so, since its scope is limited within LSF_fields_Enable(event) inner function. I am able to retrieve the selected value of LSF_Combo using LSF_Combo.get() method.
Please let me know if anyone has suggestions for retrieving the selected value from the “Queue_Combo” combobox and furhter nested comboboxes "MT_Combo: and "Merge_Combo", so that I should be able to access and assign these to a variable outside the "LSF_Fields_Enable" function scope.
For example, If i had selected 'priority' from "Queue_Combo" and had selected "MT" from "MT_Combo", i should be able to assign these strings to variables outisde LSF_Fields_Enable(event) function. From the 'def run_program()' variable 'b' should have sting equals to 'priority' (since i have selected this) and variable 'c' should have string equals to 'MT'.
from tkinter import *
import tkinter as tk
from tkinter import ttk
root = Tk()
root.geometry("800x450")
def Gui_main():
Queue_Combo_list = ['normal', 'priority', 'devices', 'grid']
Queue_Combo = ttk.Combobox(root, values=Queue_Combo_list, width=10, state="readonly")
Merge_Combo_list = ['LST_SET_ML', 'LST_SET_EQU']
Merge_Combo = ttk.Combobox(root, values=Merge_Combo_list, width=12)
MT_Combo_list = ['MT', 'MTFLEX']
MT_Combo = ttk.Combobox(root, values=MT_Combo_list, width=10)
def LSF_Fields_Enable(event):
# global Queue_Combo, VCO_Combo, OS_Combo
VCO_1 = None
if LSF_Combo.get() == 'LSF':
# # section for Queue Type
Queue_Combo_label = tk.Label(root, text="Queue: ").grid(row=2, column=1, padx=5,sticky=W)
Queue_Combo.set("normal")
Queue_Combo.grid(row=2, column=1, padx=55, pady=5, sticky=W)
def MT_MT_flex(choice):
def Manage_run_mode(choice):
# if Merge_Combo.get() == 'LSF_SET_EQU' or 'LSF_SET_MAN':
if Merge_Combo.get() != 'LSF_SET_ML':
label = tk.Label(root, text="CPU No:").grid(row=4, column=3, padx=10,sticky=tk.W)
CPU_radio_button = tk.IntVar()
R1 = Radiobutton(root, text="2", variable=CPU_radio_button, value=1).place(x=50, y=520)
if MT_Combo.get() == 'MT':
# # section for choosing a file version
Merge_Combo_label = tk.Label(root, text="Merge: ").grid(row=6, column=2, padx=10,sticky=W)
Merge_Combo.set("LST_SET_ML")
Merge_Combo.grid(row=6, column=2, padx=65, pady=15, sticky=tk.E)
Merge_Combo.bind('<<ComboboxSelected>>',Manage_run_mode)
MT_Combo_label = tk.Label(root, text="MT/MTflex: ").grid(row=2, column=3, padx=10,sticky=W)
MT_Combo.set("MT")
MT_Combo.grid(row=2, column=4, padx=5, pady=5, sticky=tk.E)
MT_Combo.bind('<<ComboboxSelected>>',MT_MT_flex)
# LSF_Fields_Enable()
LSF_Combo_label = tk.Label(root, text="Fill: ").grid(row=2, column=0, sticky=W)
LSF_Combo_list = ['LSF', 'LOCAL']
LSF_Combo = ttk.Combobox(root, values=LSF_Combo_list, width=10, state="readonly", background='white')
LSF_Combo.set('LSF')
LSF_Combo.grid(row=2, column=0, padx=25, pady=5, sticky=W)
LSF_Combo.bind('<<ComboboxSelected>>', LSF_Fields_Enable)
Queue_Combo.bind('<<ComboboxSelected>>', lambda _: print(Queue_Combo.get()))
MT_Combo.bind('<<ComboboxSelected>>', lambda _: print(MT_Combo.get()))
Merge_Combo.bind('<<ComboboxSelected>>', lambda _: print(Merge_Combo.get()))
# a = LSF_Combo.bind("<Return", LSF_Fields_Enable)
def run_program():
a = LSF_Combo.get()
print(a)
b = Queue_Combo.get()
print(b)
c = MT_Combo.get()
d = Merge_Combo.get()
close = Button(root, text ='close', command= root.destroy).grid(row=10, column=2, pady=60, sticky=E)
check_combo_get =Button (root, text ='check_combo_get', command = run_program).grid(row=10, column=1, padx=15,pady=60, sticky=E)
root.mainloop()
if __name__ == "__main__":
Gui_main()
There is not an easy way to fix this problem in your setup.
But the solution is easy, if you just go ahead and restructure your code a little:
Define the combobox outside the LSF_Fields_Enable function and also asign its values at startup.
Queue_Combo_list = ['normal', 'priority', 'devices', 'grid']
Queue_Combo = ttk.Combobox(root, values=Queue_Combo_list, width=10, state="readonly")
Now bind the ComboboxSelected Event to whatever function you want to have (in this example a simple print).
Queue_Combo.bind('<<ComboboxSelected>>', lambda _: print(Queue_Combo.get()))
And there you go!
Now the print function is executed every time the selection changes for the queue-combobox.
Hope this helps :)
EDIT:
In the updated Code below I reformated your code to make it more readable and to achieve what you wanted to have.
The Value of the ComboBoxes are now assigned to variables ("Queue_Combo_variable", "LSF_Combo_variable").
You can access their values using:
Queue_Combo_variable.get()
I tried my best to comment the entire to be as understandable as possible. Let me now if this is how you imagined it to be!
NEW CODE:
from tkinter import ttk, Tk, Label, Button, StringVar
from tkinter.constants import W, E
def Gui_main():
# Create tkinter (window) instance
root = Tk()
root.geometry("300x250")
# Define LSF_Combox (Combobox)
LSF_Combo_variable = StringVar()
LSF_Combo_label = Label(root, text="Fill: ") # Label
LSF_Combo_label.grid(row=2, column=0, sticky=W)
LSF_Combo_list = ['LSF', 'LOCAL']
LSF_Combo = ttk.Combobox(root, values=LSF_Combo_list, textvariable=LSF_Combo_variable, width=10, state="readonly", background='white')
LSF_Combo.set('LSF')
LSF_Combo.grid(row=2, column=0, padx=25, pady=5, sticky=W) # and place it on the screen
# Define Queue_Combo (Combobox)
Queue_Combo_variable = StringVar()
Queue_Combo_label = Label(root, text="Queue: ") # Label
Queue_Combo_list = ['normal', 'priority', 'devices', 'grid']
Queue_Combo = ttk.Combobox(root, values=Queue_Combo_list, textvariable=Queue_Combo_variable, width=10, state="readonly")
# ==> The Queue_Combo_variable now always stores the value which is currently selected in the queue_combo (box)
#################################################################################################################################
#### ==> Through the following code the specfied function (LSF_Combo_changed) is always called, once the variable value changes #
#################################################################################################################################
LSF_Combo_variable.trace_add("write", lambda _0, _1, _2: LSF_Combo_changed())
Queue_Combo_variable.trace_add("write", lambda _0, _1, _2: print(Queue_Combo_variable.get()))
# If you don't understand, what all of this does, it doesn't matter just now, that you can change the print function to be the function you want to call instead!
# This function is now executed every time when the LSF_Combo (box) is changed (=> "Something has been selected in the left combobox")
def LSF_Combo_changed():
# If "LSF" has been selected, show the Queue_Combo Box
if LSF_Combo.get() == 'LSF':
Queue_Combo.set("normal")
Queue_Combo.grid(row=2, column=1, padx=55, pady=5, sticky=W)
Queue_Combo_label.grid(row=2, column=1, padx=10,sticky=W)
return Queue_Combo.get()
else: # If that hasn't been selected, "forget" the position of the Queue_Combo Box & Label ("Hide them")
Queue_Combo.grid_forget()
Queue_Combo_label.grid_forget()
return None
# Close Button
close_button = Button(root, text ='close', command= root.destroy)
close_button.grid(row=10, pady=60, sticky=E)
# Show window (tkinter instance)
root.mainloop()
if __name__ == "__main__":
Gui_main()

How to enable a disabled Button after filling Entry widgets?

I have 2 Entrys and one button. I want to make that button's state disabled until the two Entrys are filled in. How can I achieve that?
howManyStocksLabel = Label(root, text = "How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row = 1, column = 0)
howManyStocksEntry = Entry(root, borderwidth = 3)
howManyStocksEntry.grid(row = 1, column = 1)
riskLabel = Label(root, text = "Enter risk %")
riskLabel.grid(row = 2, column = 0, sticky = 'w')
riskEntry = Entry(root, borderwidth = 3)
riskEntry.grid(row = 2, column = 1)
nextButton = Button(root, text = "Next!", width = 20, height = 2,state = DISABLED,
fg = 'green', bg = 'white',
command= lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row = 4, column = 1)
I tried to check whether the entries are filled in or not by:
if(riskEntry.get() != ""):
....................
but it just doesn't work.
You need to check if the value is there after the user inputs it. Also, you can use tk.StringVar() as a text variable and trace it.
Here is an example:
import tkinter as tk
def check_entry(*args):
if r1.get() and r2.get():
b1.config(state='normal')
else:
b1.config(state='disabled')
root = tk.Tk()
r1 = tk.StringVar(master=root)
r2 = tk.StringVar(master=root)
e1 = tk.Entry(root, textvariable=r1)
e1.pack()
e2 = tk.Entry(root, textvariable=r2)
e2.pack()
b1 = tk.Button(root, text='Click Me!', state='disabled')
b1.pack()
r1.trace('w', check_entry)
r2.trace('w', check_entry)
root.mainloop()
You will need to use a binding on your entry widgets to check whether the user has entered anything into the entry or not.
This code will fire the check_entry function every time the user types in one of the entry boxes:
riskEntry.bind('<KeyRelease>', check_entry)
howManyStocksEntry.bind('<KeyRelease>', check_entry)
Then your check_entry function might look like this:
def check_entry(event): #event is required for all functions that use a binding
if riskEntry.get() and howManyStocksEntry.get():
nextButton.config(state=NORMAL)
else:
nextButton.config(state=DISABLED)
One way to do it would be to utilize the ability to "validate" their contents that Entry widgets support — see adding validation to an Entry widget — but make it check the contents of multiple Entry widgets and change the state of a Button accordingly.
Below shows how to do this via a helper class that encapsulates most of the messy details needed to make doing it relatively painless. Any number of Entry widgets can be "watched", so it scales well to handle forms consisting of many more than merely two entries.
from functools import partial
import tkinter as tk
from tkinter.constants import *
class ButtonEnabler:
""" Enable/disable a Button depending on whether all specified Entry widgets
are non-empty (i.e. contain at least one character).
"""
def __init__(self, button, *entries):
self.button = button
self.entries = entries
for entry in self.entries:
func = root.register(partial(self.check_entries, entry))
entry.config(validate="key", validatecommand=(func, '%P'))
def check_entries(self, this_entry, new_value):
other_entries = (entry for entry in self.entries if entry is not this_entry)
all_others_filled = all(entry.get() for entry in other_entries)
combined = bool(new_value) and all_others_filled
self.button.config(state=NORMAL if combined else DISABLED)
return True
root = tk.Tk()
howManyStocksLabel = tk.Label(root, text="How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row=1, column=0)
howManyStocksEntry = tk.Entry(root, borderwidth=3)
howManyStocksEntry.grid(row=1, column=1)
riskLabel = tk.Label(root, text="Enter risk %")
riskLabel.grid(row=2, column=0, sticky='w')
riskEntry = tk.Entry(root, borderwidth=3)
riskEntry.grid(row=2, column=1)
nextButton = tk.Button(root, text="Next!", width=20, height=2, state=DISABLED,
fg='green', bg='white', disabledforeground='light grey',
command=lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row=4, column=1)
enabler = ButtonEnabler(nextButton, howManyStocksEntry, riskEntry)
root.mainloop()

How to correctly define variables in Python?

Im writing a program so i can practise my spanish grammer. I come from the world of PLC programming and wanted to delve into Python to get 2 birds stoned at once. Below is the code, it however gives me an error on the syntax as its missing the var RandomVerbNumber in the on_change def. I have tried defining it outside of the def structures, but it will always make RandomVerbNumber have an incorrect value.
I have tried looking into classes and the init function. But that's not very clear to me yet.
import gspread
import random
import tkinter as tk
gc = gspread.service_account(filename = 'credentials.json')
SpanishVerbs = gc.open('Spanish Verbs')
worksheet = SpanishVerbs.worksheet("EnglishSpanishList")
EnglishList = worksheet.col_values(1)
SpanishList = worksheet.col_values(2)
AmountOfRows = len(worksheet.col_values(1))
def on_next(event):
RandomVerbNumber = random.randint(0,AmountOfRows)
EnglishVerbLabel.config(text = EnglishList[RandomVerbNumber])
print(EnglishList[RandomVerbNumber]," = ",SpanishList[RandomVerbNumber])
def on_change(event):
if SpanishEntry.get() == SpanishList[RandomVerbNumber]:
ResultLabel.config(text = "Correct")
else:
ResultLabel.config(text = "Incorrect")
SpanishEntry.delete(0, tk.END)
root = tk.Tk()
QuestionLabel = tk.Label(root, text = "Spanish Verb for:")
EnglishVerbLabel = tk.Label(root)
ResultLabel = tk.Label(root)
SpanishEntry = tk.Entry(root)
root.bind("<Return>", on_change)
buttonNext = tk.Button(root, text="Next", fg="black")
buttonNext.bind("<Button-1>", on_next)
QuestionLabel.grid(row=0, sticky=tk.E)
EnglishVerbLabel.grid(row=0, column=1)
SpanishEntry.grid(row=1, columnspan=2)
buttonNext.grid(row=2, columnspan=2)
ResultLabel.grid(row=3, columnspan=2)
root.mainloop()
RandomVerbNumber is not defined in the function on_change. Why do you think it would be defined?
There does exist a variabel RandomVerbNumber in another function, but that's outside of the scope of on_change. Variables only exists within their scope.
You can pass a randomised array defined in main as an argument into both methods, holding the index values of the words and pop the index value in the on_next method. Your edited code is below, my edits are marked with NOTE tags.
This method works because python lists are passed by reference.
import gspread
import random
import tkinter as tk
gc = gspread.service_account(filename = 'credentials.json')
SpanishVerbs = gc.open('Spanish Verbs')
worksheet = SpanishVerbs.worksheet("EnglishSpanishList")
EnglishList = worksheet.col_values(1)
SpanishList = worksheet.col_values(2)
AmountOfRows = len(worksheet.col_values(1))
#NOTE:
randomisedList = random.sample(range(AmountOfRows), AmountOfRows)
#NOTE: event argument removed
def on_next(list):
EnglishVerbLabel.config(text = EnglishList[RandomVerbNumber])
print(EnglishList[RandomVerbNumber]," = ",SpanishList[RandomVerbNumber])
list.pop()
#NOTE: event argument removed
def on_change(list):
#NOTE:
if SpanishEntry.get() == SpanishList[list[-1]]:
ResultLabel.config(text = "Correct")
else:
ResultLabel.config(text = "Incorrect")
SpanishEntry.delete(0, tk.END)
root = tk.Tk()
QuestionLabel = tk.Label(root, text = "Spanish Verb for:")
EnglishVerbLabel = tk.Label(root)
ResultLabel = tk.Label(root)
SpanishEntry = tk.Entry(root)
#NOTE:
root.bind("<Return>", lambda event, list=randomisedList: on_change(list))
buttonNext = tk.Button(root, text="Next", fg="black")
#NOTE:
buttonNext.bind("<Button-1>", lambda event, list=randomisedList: on_next(list))
QuestionLabel.grid(row=0, sticky=tk.E)
EnglishVerbLabel.grid(row=0, column=1)
SpanishEntry.grid(row=1, columnspan=2)
buttonNext.grid(row=2, columnspan=2)
ResultLabel.grid(row=3, columnspan=2)
root.mainloop()

How do I get the values assigned to the Correct and Total numbers to update when the user inputs their answer?

I have a Python file that when run, opens a window for simple addition practice. It asks the user for their input, and if the total is correct will output "Right!" and "Oops!" for incorrect. Below all of this is a counter that keeps track of the correct number out of the total. However, at the moment, those numbers both remain zero when user enters their input. What kind of changes would need to be made under the ClicktheButton1 function in order to get this program properly functioning? Thanks.
The output would end up looking like "2 out 4 correct" in the window, updating after each new problem is solved.
from tkinter import *
import random as rn
window = Tk()
window.geometry('350x350')
window.title("C200")
x = rn.randint(0,100)
y = rn.randint(0,100)
correct, incorrect = 0,0
myLabel = Label(window, text="{0}+{1}=".format(x,y), font=("Arial Bold", 15))
myLabel.grid(column=0, row=0)
myLable2 = Label(window, text = "",font=("Arial Bold", 15))
myLable2.grid(column=0, row=5)
mylabel3 = Label(window,text = "0 out of 0 correct",font=("Arial Bold", 15))
mylabel3.grid(column=0, row=10)
mytxt = Entry(window, width=12)
mytxt.grid(column=1,row=0)
def ClicktheButton1():
global x
global y
global correct
global incorrect
myguess = int(mytxt.get())
if x + y == myguess:
myLable2.configure(text = "Right!")
correct += 1
else:
myLable2.configure(text = "Oops!")
incorrect += 1
x = rn.randint(0,100)
y = rn.randint(0,100)
mytxt.focus()
mytxt.delete(0,END)
myLabel.configure(text = "{0}+{1}=".format(x,y))
btn1 = Button(window, text="check", command = ClicktheButton1)
btn1.grid(column=0, row=7)
def ClicktheButton2():
window.destroy()
btn1 = Button(window, text="Quit", command = ClicktheButton2)
btn1.grid(column=400, row=400)
window.mainloop()
You have to change text in mylabel3 in the same why as you change text in myLabel - and even in the same place. I don't know why you have problem with this.
myLabel.configure(text = "{0}+{1}=".format(x,y))
mylabel3.configure(text="{0} of {1} correct".format(correct, correct+incorrect))

Label widget problems

I am having problems in my Tkinter project. I am trying to create a simple addition calculator that only computes two numbers and. I am having trouble creating the addition function. I want to create a label that displays the variable 'finalans' which is basically the value of the sum of the two digits that the user inputs in the Entry Box Widgets.
def Addition():
top = Toplevel()
top.geometry("500x500")
global finalans
#First Entry
e = Entry(top)
e.pack()
e.focus_set()
#Function for finding answer
def Answer():
firstval = int(e.get())
secondval = int(m.get())
finalans = firstval + secondval
#Final Answer
answer = Label(top, textvariable=finalans)
answer.pack()
h = Label(top, text="First Numeric Value")
h.pack()
#Second Entry
m = Entry(top)
m.pack()
m.focus_set()
z = Label(top, text="Second Numeric Value")
z.pack()
add2 = Button(top, text="Submit", width=10, command=Answer)
add2.pack()
mainloop()
When I try to run the program and display the answer using the Label widget the label does not display anything at all. There isn't even an error code or anything in the console. How do I make the Label Widget display the variable?
First finalans have to be StringVar().
Second use finalans.set(string) to change it.
And you could create answer label only once.
def Addition():
top = Toplevel()
top.geometry("500x500")
global finalans
finalans = StringVar()
#First Entry
e = Entry(top)
e.pack()
e.focus_set()
#Function for finding answer
def Answer():
firstval = int(e.get())
secondval = int(m.get())
finalans.set( str(firstval + secondval) )
h = Label(top, text="First Numeric Value")
h.pack()
#Second Entry
m = Entry(top)
m.pack()
m.focus_set()
z = Label(top, text="Second Numeric Value")
z.pack()
add2 = Button(top, text="Submit", width=10, command=Answer)
add2.pack()
#Final Answer
answer = Label(top, textvariable=finalans)
answer.pack()
mainloop()
Addition()

Categories