I'm writing a simple unit converter where the user can pick which units they want to convert from two options. I'm using radio-buttons for the choice, but can't seem to get the value of the chosen one to work in the conditions at the bottom of the program.
I tried several solutions suggested here on stack overflow, but none of them worked. At one point, I got the selected() to print the value of the button, but it still didn't work in the condition. Am I missing something obvious here?
Please, note, the converter is not finished yet, there is still some more polishing to do after this issue is solved.
from tkinter import *
window = Tk()
window.title("Unit converter")
window.minsize(width=300, height=300)
window.config(padx=50, pady=50)
def lbs_kgs():
user_input = float(unit_A1.get())
result = round((user_input / 2.2046), 2)
unit_B1.config(text= f"{result}")
def mil_km():
user_input = float(unit_A1.get())
result = round((user_input * 1.6), 2)
unit_B1.config(text= result)
def selected():
return radio_state.get()
intro_label = Label(text = "What units would you like to convert?")
intro_label.grid(column=0, row=0, columnspan=4, pady=10)
radio_state = StringVar()
radiobutton1 = Radiobutton(text="Pounds to kilograms", value="pk", variable=radio_state, command=selected)
radiobutton2 = Radiobutton(text="Miles to kilometers", value="mk", variable=radio_state, command=selected)
radiobutton1.grid(column=0, row=1, columnspan=4)
radiobutton2.grid(column=0, row=2, columnspan=4)
instructions_label = Label(text = "Enter the number:")
instructions_label.grid(column=0, row=3, columnspan=4, pady=10)
unit_A1 = Entry(width=5)
unit_A1.grid(column=1, row=4, sticky="e")
unit_A1_label = Label(text = "unit A1")
unit_A1_label.grid(column=2, row=4, sticky="w")
equal_label = Label(text = "is equal to")
equal_label.grid(column=1, row=5, sticky="e")
unit_B1 = Label(text = "0")
unit_B1.grid(column=2, row=5, sticky="w")
unit_B1_label = Label(text = "result unit")
unit_B1_label.grid(column=3, row=5, sticky="w")
button = Button(text="Calculate")
button.grid(column=0, row=6, columnspan=4, pady=10)
if selected() == "pk":
button.config(command=lbs_kgs)
elif selected() == "mk":
button.config(command=mil_km)
window.mainloop()
Move the if/else check into the selected function so the conditions can be checked each time the selection changes
def selected():
selection = radio_state.get()
if selection == "pk":
button.config(command=lbs_kgs)
elif selection == "mk":
button.config(command=mil_km)
In line 29 should be radio_state = StringVar(window, '1'). Without this when executed both radiobutton are on, but that not right.
def selected():
if (selection := radio_state.get()) == "pk":
button.config(command=lbs_kgs)
elif selection == "mk":
button.config(command=mil_km)
Output:
Output pound to Kilograms:
Output Miles to Kilometers:
Related
I'm building a GUI which opens at specific moments and retrieves some questionnaire data. There are specific types of questionnaire windows, so I decided to make a class for it. When using it, I stumble upon the following error:
TypeEror: CreateSlider() missing 1 required positional Argument: 'SlideAsk'
This is my first attempt at using a class like this so I am not certain if I did something fundamentally wrong or that its a minor issue. Other fixes proposed on the forum did not seem to work.
class Questionnaire:
global startrow,startcol
startrow = 1
startcol = 0
def __init__(self,width,height,IntroMessage,RadioAsk,Choose,SlideAsk):
global startrow,startcol
width = width
height = height
IntroMessage = IntroMessage
RadioAsk = RadioAsk
Choose = Choose
SlideAsk = SlideAsk
self = CTkToplevel()
self.geometry(f"{width}x{height}")
self.title("Questionnaire")
self.frame = CTkFrame(master=self)
self.frame.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
#try:
Intro = CTkLabel(self.frame, text= IntroMessage)
Intro.grid(row=startrow, column=startcol, columnspan=1, pady=20, padx=20, sticky="w")
startrow +=1
#except:
#pass
#try:
CreateSlider(SlideAsk)
#except:
#pass
#try:
CreateRadio(RadioAsk,Choose,startrow,startcol)
#except:
#pass
def CreateRadio(self,title,Choose):
label_Type = CTkLabel(master=self.frame,text=title)
label_Type.grid(row=startrow, column=startcol, columnspan=1, pady=0, padx=20, sticky="w")
startrow +=1
answer = StringVar()
answer.set(Choose[len(Choose)])
for text, mode in Choose:
RB = Radiobutton(self.frame, text=text, variable = answer, value = mode)
RB.grid(pady=5,padx=10,sticky="w")
startrow +=1
def CreateSlider(self,SlideAsk):
for q in SlideAsk:
label_Question = CTkLabel(master=self.frame,text= q)
label_Question.grid(row=startrow, column=0, columnspan=1, pady=10, padx=10, sticky="w")
startrow+=1
slider_Question = CTkSlider(master=self.frame,from_=1,to=5,number_of_steps=4)
slider_Question.grid(row=startrow, column=0, columnspan=2, pady=10, padx=20, sticky="w")
def Open_Break():
Questionnaire(width = 400,
height = 600,
IntroMessage = "Please, answer the questions below",
RadioAsk = "First question",
Choose = [
("Opt1","One"),
("Opt2","Two"),
("Opt3","Three"),
("Opt4","Four")],
SlideAsk = [
"This is the first question.",
"This is the second question.",
"This is the third question."])
I am new to tkinter Python module and creating a very simple UI with tkinter.
Its basically a optical card which will first ask for card number. User can enter "Card1 or Card2". For Card1 there is one more edit which ask for KM range like 10KM, 40KM, 80KM and user can enter the value specified and it gives the optimal value and acceptable value.
Code is working fine. Only problem is with clearing the information using clear button for Card1. I am not able to clear the complete information for Card1 which includes clearing the edit box and outout.
Below is the code
from tkinter import *
from tkinter import ttk
import tkinter
frm = Tk()
frm.geometry('600x400')
frm.title("Optical Power Specs")
bg = "#94FB9E"
fnt = 'tahoma 15 bold'
frm.config(bg=bg)
frm.resizable(False, False)
#frm.iconbitmap('f.gif')
frame = Frame(frm, bg=bg)
frame2 = Frame(frm, bg=bg)
frame4 = Frame(frm, bg=bg)
def f():
global lbl104080
global frame3
global txt104080
if str(txt1.get()) == 'Card1':
print("entered ehre")
frame3 = Frame(frm, bg=bg)
frame3.grid(row=3, column=0)
txt104080 = Entry(frame3, textvariable=sv104080)
lbl104080 = Label(frame3, text="Enter 10KM or 40KM or 80KM ", font='None 10', background=bg, padx=0)
lbl104080.grid(row=1, column=0, pady=30)
txt104080.grid(row=1, column=1)
if str(txt104080.get()) == '10KM':
lblr['text'] = ("""
Optimal Value = -10 To -10 dBm
Acceptable Value = -10 To -10 dBm
""")
elif str(txt104080.get()) == '40KM':
lblr['text'] = ("""
Optimal Value = -40 To -40 dBm
Acceptable Value = -40 To 40 dBm
""")
elif str(txt1.get()) == 'Card2':
lblr['text'] = ("""
Optimal Value = -2 To -2 dBm
Acceptable Value = -2 To -2 dBm
""")
elif str(txt1.get()) == 'A1236':
lblr['text'] = ("""
Optimal Value = -100 To -20 dBm
Acceptable Value = -3 To 1 dBm
""")
def clea():
# global lbl104080
#lbl104080['text'] = ('')
txt104080['text'] = ('')
lbl104080.destroy()
frame3.grid_forget()
frame3.destroy()
#frame3.destroy()
lblr['text'] = ('')
sv104080 = StringVar()
opt = ttk.Label(frm, text='Optical Power Specs', font=fnt, background=bg)
Ent = ttk.Label(frame, text='Enter BOM Code OR Card Name', font='None 10', background=bg)
btnok = ttk.Button(frame2, text='OK', command=f)
btncancel = ttk.Button(frame2, text='Clear', command=clea)
lblr = ttk.Label(frame4, font='None 10', background=bg)
svname_bom = StringVar()
txt1 = Entry(frame, textvariable=svname_bom)
opt.grid(row=0, column=0, pady=5, padx=200)
frame.grid(row=1, column=0)
Ent.grid(row=0, column=0, padx=10, pady=20)
txt1.grid(row=0, column=1)
frame2.grid(row=2, column=0)
btnok.grid(row=0, column=0, padx=10, pady=20)
btncancel.grid(row=0, column=1, pady=20)
frame4.grid(row=4, column=0)
lblr.grid(row=2, column=0, pady=50, padx=100)
frm.mainloop()
Please help me to solve this issue
You probably want txt1.delete(0, 'end') that will delete all text from main entry text
def clea():
#lbl104080['text'] = ('')
txt104080['text'] = ('')
txt1.delete(0, 'end')
lbl104080.destroy()
frame3.grid_forget()
frame3.destroy()
#frame3.destroy()
lblr['text'] = ('')
I got some trouble with finding the matching if-statement to check if only one entry equals 0 of 3.
Here's the code:
def thanx(self):
if len(self.e.get()) == 0:
messagebox.showerror("Error", "Please enter affordable infos")
self.boo = False
else:
messagebox.showinfo("Submition done", "Thank you")
self.boo = True
It is only checking if my variable e equals 0, but i actually got 2 more entries. I know i could check every single one individually, however there has to be an easier way of doing this.
Im using "tkinter" btw, but this shouldnt be too much important.
I tried it with or but this isn't working or I'm doing it wrong.
(Also tried to solve this with lambda, but again just errors...)
Maybe someone can help me there...
Edit:
I might have explained this a bit confusing, I'll add the rest of the code here that you can understand this better:
from tkinter import Tk, Label, Entry, Button, W
from tkinter import messagebox
class MyForm:
def thanx(self):
if len(self.e.get()) == 0:
messagebox.showerror("Error", "Please enter affordable infos")
self.boo = False
else:
messagebox.showinfo("Submition done", "Thank you")
self.boo = True
def callback(self):
#print("Name: %s\nPassword: %s\nEmail: %s" % (self.e.get(), self.e2.get(),self.e3.get()))
if self.boo:
f = open("PrivatData.txt", "w+")
f.write("Name: %s\nPassword: %s\nEmail: %s" % (self.e.get(), self.e2.get(),self.e3.get()))
def __init__(self):
self.root = Tk()
self.root.title("Your privat details")
Label(self.root, text="Your Name").grid(row = 0, padx = 12, pady=5)
Label(self.root, text="Password").grid(row=1, padx=12, pady=5)
Label(self.root, text="Email").grid(row=2, padx=12, pady=5)
self.e = Entry(self.root)
self.e2 = Entry(self.root)
self.e3= Entry(self.root)
self.e.grid(row=0,column=1,columnspan=2)
self.e2.grid(row=1, column=1, columnspan=2)
self.e3.grid(row=2, column=1, columnspan=2)
self.e.focus_set()
self.show= Button(self.root, text="Submit", command=lambda:[self.thanx(),self.callback()])
self.quit = Button(self.root,text="Quit", command = self.root.quit)
self.show.grid(row=3, column=1, pady=4)
self.quit.grid(row=3, column=2, sticky = W, pady=4)
self.root.geometry("230x140")
self.root.configure(background= "#65499c")
self.root.mainloop()
if __name__ == "__main__":
app= MyForm()
Use any:
if any((len(self.e.get().strip())==0,len(self.e2.get().strip())==0,len(self.e2.get().strip())==0)):
do stuff to say that user did not input all fields
else:
do stuff to say that user inputted all fields
So full code:
from tkinter import Tk, Label, Entry, Button, W
from tkinter import messagebox
class MyForm:
def thanx(self):
if any((len(self.e.get().strip())==0,len(self.e2.get().strip())==0,len(self.e2.get().strip())==0)):
messagebox.showerror("Error", "Please enter affordable infos")
self.boo = False
else:
messagebox.showinfo("Submition done", "Thank you")
self.boo = True
def callback(self):
#print("Name: %s\nPassword: %s\nEmail: %s" % (self.e.get(), self.e2.get(),self.e3.get()))
if self.boo:
f = open("PrivatData.txt", "w+")
f.write("Name: %s\nPassword: %s\nEmail: %s" % (self.e.get(), self.e2.get(),self.e3.get()))
def __init__(self):
self.root = Tk()
self.root.title("Your privat details")
Label(self.root, text="Your Name").grid(row = 0, padx = 12, pady=5)
Label(self.root, text="Password").grid(row=1, padx=12, pady=5)
Label(self.root, text="Email").grid(row=2, padx=12, pady=5)
self.e = Entry(self.root)
self.e2 = Entry(self.root)
self.e3= Entry(self.root)
self.e.grid(row=0,column=1,columnspan=2)
self.e2.grid(row=1, column=1, columnspan=2)
self.e3.grid(row=2, column=1, columnspan=2)
self.e.focus_set()
self.show= Button(self.root, text="Submit", command=lambda:[self.thanx(),self.callback()])
self.quit = Button(self.root,text="Quit", command = self.root.quit)
self.show.grid(row=3, column=1, pady=4)
self.quit.grid(row=3, column=2, sticky = W, pady=4)
self.root.geometry("230x140")
self.root.configure(background= "#65499c")
self.root.mainloop()
if __name__ == "__main__":
app= MyForm()
I am assuming that at the moment you are checking if some string element equals 0.
For example
e = 'abc'
len(e) == 3 # True
l = []
len(l) == 0 # True
If you want to check if your string variable is 0 then simply:
if not self.e.get():
messagebox.showerror("Error")
self.boo = False
You may try this:
if len(self.e.get()) == 0 or len(self.e2.get()) == 0 or len(self.e3.get()) == 0:
messagebox.showerror("Error", "Please enter affordable infos")
self.boo = False
else:
messagebox.showinfo("Submition done", "Thank you")
self.boo = True
Since you have 3 variables, there's no way to check them all 'in batch' unless you build a data structure containing them and then check some conditions on that data structure. However, it does not give any advantage. If you add a new variable, say e4, you still have to add it manually to the the data structure.
To ensure that all three textboxes are not empty in one if statement, you can use the following:
if "" in [self.e.get().strip(), self.e2.get().strip(), self.e3.get().strip()]:
messagebox.showerror("Error", "Please enter affordable infos")
self.boo = False
else:
messagebox.showinfo("Submition done", "Thank you")
self.boo = True
This is a short and neat way to write what you are trying to do. This works because entry widgets will return "" if they are empty, and self.e.get().strip() makes the text returned empty (.strip() removes all whitespace at both the start and the end of the string) if it is just whitespace (" ", \t, n, etc...).
It is better to check the contents of the string rather than the length of it, because a box with just whitespace in it will not return 0, as shown below.
>>> len(" ")
1
>>> len("")
0
>>> len("\t")
1
I am trying to make my first GUI script based on the answers of 2 questions. I'll show an example of the non GUI script
while True:
ammount = input("What is your debt")
if ammount.isdigit() == True:
break
else:
print("Please try typing in a number")
while True:
month = input("In which month did the debt originate?")
if month not in ["January", "February"]:
print("Try again")
else:
break
The point of this script is that it is scalable with all the questions one may add, I want to understand it in the same way in Tkinter. I'll show what I've tried:
from tkinter import *
def click():
while True:
entered_text = text_entry.get()
if entered_text .isdigit() == False:
error = Label(window, text="Try again", bg = "black", fg="red", font="none 11").grid(row = 3, column = 2, sticky= W).pack()
else:
break
return True
window = Tk()
window.title("Tax calculator")
window.configure(background="black")
monto = Label(window, text="¿What is your debt?", bg="black", fg="white", font="none 12 bold")
monto.grid(row = 1, column = 0, sticky= W)
text_entry = Entry(window, width = 20, bg="white")
text_entry.grid(row = 2, column=2, sticky=W)
output = Button(window, text = "Enter", width = 6, command = click)
output.grid(row = 3, column = 0, sticky = W)
The thing is, I can't add a Label() method in the if/else of the click() method, because I would like to ask a new question once the condition is met. I can't also can't get True from click once the condition is met, because the input comes from Button() method. Thanks in advance
You don't actually need any loops here, a simple if statement would be enough to do the trick. Also, there is no need to recreate the label every time, you can just configure() its text. And, note that indexing starts from 0 - so, in your grid, actual first row (and column) needs to be numbered 0, not 1. Besides that, I suggest you get rid of import *, since you don't know what names that imports. It can replace names you imported earlier, and it makes it very difficult to see where names in your program are supposed to come from. You might want to read what PEP8 says about spaces around keyword arguments, as well:
import tkinter as tk
def click():
entered_text = text_entry.get()
if not entered_text.isdigit():
status_label.configure(text='Please try again')
text_entry.delete(0, tk.END)
else:
status_label.configure(text='Your tax is ' + entered_text)
text_entry.delete(0, tk.END)
root = tk.Tk()
root.title('Tax calculator')
root.configure(background='black')
monto = tk.Label(root, text='¿What is your debt?', bg='black', fg='white', font='none 12 bold')
monto.grid(row=0, column=0, padx=10, pady=(10,0))
text_entry = tk.Entry(root, width=20, bg='white')
text_entry.grid(row=1, column=0, pady=(10,0))
status_label = tk.Label(root, text='', bg='black', fg='red', font='none 11')
status_label.grid(row=2, column=0)
button = tk.Button(root, text='Enter', width=17, command=click)
button.grid(row=3, column=0, pady=(0,7))
root.mainloop()
I forgot to mention, if your application gets bigger, you might be better off using a class.
from tkinter import *
root = Tk()
root.title("Tip & Bill Calculator")
totaltxt = Label(root, text="Total", font=("Helvitca", 16))
tiptxt = Label(root, text="Tip (%)", font=("Helvitca", 16))
peopletxt = Label(root, text="people", font=("Helvitca", 16))
totaltxt.grid(row=0, sticky=E)
tiptxt.grid(row=1, sticky=E)
peopletxt.grid(row=2, sticky=E)
totalentry = Entry(root)
tipentry = Entry(root)
peopleentry = Entry(root)
totalentry.grid(row=0, column=2)
tipentry.grid(row=1, column=2)
peopleentry.grid(row=2, column=2)
ans = Label(root, text = "ANS")
ans.grid(row=4)
def answer(event):
data1 = totalentry.get()
data2 = tipentry.get()
data3 = peopleentry.get()
if tipentry.get() == 0:
ans.configure(str((data1/data3)), text="per person")
return
elif data1 == 0:
ans.configure(text="Specify the total")
return
elif data3 == 0 or data3 ==1:
ans.configure(str(data1*(data2/100+1)))
return
elif data1 == 0 and data2 == 0 and data3 ==0:
ans.configure(text = "Specify the values")
return
else:
ans.configure(str((data1*(data2/100+1)/data3)), text="per person")
return
bf = Frame(root)
bf.grid(row=3, columnspan=3)
calc = Button(bf, text ="Calculate", fg = "black", command = answer)
calc.bind("<Button-1>", answer)
calc.grid(row=3, column=2)
root.mainloop()
I'm trying to make a tip and bill calculator with a simple design just to learn and experiment. However, I encountered a horrible problem that kept haunting for days, I usually struggle with functions in python and I'm trying to bind a function to a calculate button, which I managed to make it appear. However, I can't manage to get it to work. After some messing around I ended with this error, when I click the calculate button.
This is the error after I click the calculate button:
TypeError: answer() missing 1 required positional argument: 'event'
Commands bound to a button do not get an argument, as the nature of the event is already known. Delete 'event'.
You also bind the answer function to an event. The result is that answer is called both without and with an event argument. Get rid of the bind call.
Follow hint given by Bryan. Stop passing a digit string to .configure as a positional parameter. tk will try to interpret is as dictionary. Instead, add the number string to the rest of the label string.
Like rows, columns start from 0.
The frame is not needed.
The following revision works.
from tkinter import *
root = Tk()
root.title("Tip & Bill Calculator")
totaltxt = Label(root, text="Total", font=("Helvitca", 16))
tiptxt = Label(root, text="Tip (%)", font=("Helvitca", 16))
peopletxt = Label(root, text="people", font=("Helvitca", 16))
totaltxt.grid(row=0, column=0, sticky=E)
tiptxt.grid(row=1, column=0, sticky=E)
peopletxt.grid(row=2, column=0, sticky=E)
totalentry = Entry(root)
tipentry = Entry(root)
peopleentry = Entry(root)
totalentry.grid(row=0, column=1)
tipentry.grid(row=1, column=1)
peopleentry.grid(row=2, column=1)
ans = Label(root, text = "ANS")
ans.grid(row=4, column=0, columnspan=2, sticky=W)
def answer():
total = totalentry.get()
tip = tipentry.get()
people = peopleentry.get()
if not (total and tip):
ans['text'] = 'Enter total and tip as non-0 numbers'
else:
total = float(total)
tip = float(tip) / 100
people = int(people) if people else 1
ans['text'] = str(round(total * tip / people, 2)) + " per person"
calc = Button(root, text ="Calculate", fg = "black", command = answer)
calc.grid(row=3, column=1)
root.mainloop()