I wrote complicated program in Python 3.4 (with tkinter gui). It's temperature converter (Celsius to Fahrenheit and reverse) in real-time. It works almost good, but there is one problem. I have to add a space after input value every time. Anyone have idea what's wrong in this program?
from tkinter import *
def cel_na_fahr(event):
e = ".0"
a = float(ent1.get())
a = round((32+9/5*a),2)
a = str(a)
if a.endswith(e):
a=a.replace(".0","")
ent2.delete(0,END)
ent2.insert(0,a+event.char)
else:
ent2.delete(0,END)
ent2.insert(0,a+event.char)
def fahr_na_cel(event):
e = ".0"
a = float(ent2.get())
a = round(5/9*(a-32),2)
a = str(a)
if a.endswith(e):
a=a.replace(".0","")
ent1.delete(0,END)
ent1.insert(0,a+event.char)
else:
ent1.delete(0,END)
ent1.insert(0,a+event.char)
root = Tk()
root.geometry("300x180+400+400")
fr1 = Frame(root, padx=5, pady=40)
fr1.pack(side=TOP)
fr2 = Frame(root)
fr2.pack(side=TOP)
lbl1 = Label(fr1, text="cel to fahr ")
lbl1.pack(side=LEFT)
ent1 = Entry(fr1)
ent1.pack(side=RIGHT)
lbl2 = Label(fr2, text="fahr to cel ")
lbl2.pack(side=LEFT)
ent2 = Entry(fr2)
ent2.pack(side=RIGHT)
ent1.bind('<Key>', cel_na_fahr)
ent2.bind('<Key>', fahr_na_cel)
root.mainloop()
You have to type a space because when the <Key> callback triggers, the key that the user most recently pressed hasn't yet been added to the entry. This is probably what you're trying to compensate for by adding event.char, although you're doing it in the wrong place anyway.
Change your bindings to KeyRelease, so that the callbacks trigger after the entry is updated, and remove the +event.char stuff, as you don't need it any more.
from tkinter import *
def cel_na_fahr(event):
print(ent1.get())
e = ".0"
a = float(ent1.get())
a = round((32+9/5*a),2)
a = str(a)
if a.endswith(e):
a=a.replace(".0","")
ent2.delete(0,END)
ent2.insert(0,a)
else:
ent2.delete(0,END)
ent2.insert(0,a)
def fahr_na_cel(event):
print(ent2.get())
e = ".0"
a = float(ent2.get())
a = round(5/9*(a-32),2)
a = str(a)
if a.endswith(e):
a=a.replace(".0","")
ent1.delete(0,END)
ent1.insert(0,a)
else:
ent1.delete(0,END)
ent1.insert(0,a)
root = Tk()
root.geometry("300x180+400+400")
fr1 = Frame(root, padx=5, pady=40)
fr1.pack(side=TOP)
fr2 = Frame(root)
fr2.pack(side=TOP)
lbl1 = Label(fr1, text="cel to fahr ")
lbl1.pack(side=LEFT)
ent1 = Entry(fr1)
ent1.pack(side=RIGHT)
lbl2 = Label(fr2, text="fahr to cel ")
lbl2.pack(side=LEFT)
ent2 = Entry(fr2)
ent2.pack(side=RIGHT)
ent1.bind('<KeyRelease>', cel_na_fahr)
ent2.bind('<KeyRelease>', fahr_na_cel)
root.mainloop()
Related
The main function gives me an error, not sure how I can fix this, and some explanation as to what is happening in this error will be much appreciated.
I tried to input in the entry field a random position in this format "28.834592° -46.099829°" without quotes.
import tkinter as tk
import ctypes
window = tk.Tk()
user32 = ctypes.windll.user32
# Main Function
def main():
lat = input_coordinate()[0]
long = input_coordinate()[1]
print(lat,long)
def input_coordinate():
try:
user_coordinates = lat_long_Entry.get()
# print (user_coordinates)
new_user_coordinates = user_coordinates.replace("°"," ")
new_coordinates = new_user_coordinates.split(" ",1)
#print (new_user_coordinates)
coordinates = []
counter = []
for item in new_coordinates:
coordinates.append(float(item))
#print (coordinates)
for i in range(len(coordinates)):
counter.append(i)
#print (counter)
if (coordinates[0] is str) or (counter[0] is None) or (counter == [0]):
print("fail")
else:
print("Success")
return coordinates
except ValueError:
popupmsg_nocoordinate()
def popupmsg_nocoordinate():
popup = tk.Tk()
popup.wm_title("Error")
label = tk.Label(popup, text="Please Enter a Valid Coordinates in decimal degree !", font="NORM_FONT")
label.pack(side="top", fill="x", pady=10)
B4 = tk.Button(popup, text="Cancel", command=popup.destroy)
B4.pack()
popup.mainloop()
# label fields
window.title("Scale Calculator")
window.geometry('350x350')
Title = tk.Label(text="Calculator")
lat_long = tk.Label(text="Enter Coordinates")
lat_long_Entry = tk.Entry()
run = tk.Button(text="Run", command=main)
lat_long.grid (row=1, column=0, )
lat_long_Entry.grid (row=1, column=2, )
run.grid (row=5, column=0, )
window.mainloop()
I feel this is not the most optimized way to achieve what I wanted.
I'm trying to create a factorial calculator GUI.
The program works fine, but the problem I'm having is that when there are too many numbers coming in from the output, the screen automatically increases in width. I've tried using tk.Text to create a limit to the size of the textbox and so the text continues to the next row when the columns are filled.
But when I had to input text in to the tk.Text it didn't work since the variable I used is being processed in the function that gets called when the button is pressed. I have tried googling this problem but I couldn't find anything, I did find some people explaining how to use variables that get created/processed inside of a function, but that didn't work so I think I have done something wrong in my code.
Note: I am using lambda to call my function (not sure if this is important or not).
TLDR: Text gets too long when too much information is outputted. tk.Text didn't work for me since I couldn't figure out how to use the variable that is created/processed inside of a function that is only called when the button is pressed.
Here is my entire code: https://pastebin.com/1MkdRjVE
Code for my function:
def start_calc():
output_array = ["placehold"]
start_text.set("Loading...")
i = 1
global e1
global e2
output_array.clear()
string = e1.get()
string2 = e2.get()
integr = int(string)
integr2 = int(string2)
if string == "":
error_message.set("Please enter correct numbers.")
elif string2 == "":
error_message.set("Please enter correct numbers.")
else:
while integr2 >= i:
calc = integr ** i
calcstr = (str(calc))
output_array.append(calcstr)
i += 1
start_text.set("Start!")
output_array_str = (', '.join(output_array))
output_msg.set("Output: " + output_array_str)
print(output_array_str) #This is just so I know if it's working or not in the terminal
Code for my output:
output_msg = tk.StringVar()
output_text = tk.Label(root, textvariable=output_msg, font="Raleway")
output_msg.set("Output: ")
output_text.grid(columnspan=3, column=0, row=14)
I think this is what you are looking for:
#Imports
import tkinter as tk
#Variables
root = tk.Tk()
#Tkinter GUI setup basic
canvas = tk.Canvas(root, width= 400, height=400)
canvas.grid(columnspan=3, rowspan=120)
#Title
text = tk.Label(root, text="Calculating factorials", font="Raleway")
text.grid(column=1, row=1)
#Function
def start_calc():
output_array = ["", ""]
start_text.set("Loading...")
i = 1
global e1
global e2
output_array.clear()
string = e1.get()
string2 = e2.get()
integr = int(string)
integr2 = int(string2)
if string == "":
error_message.set("Please enter correct numbers.")
elif string2 == "":
error_message.set("Please enter correct numbers.")
else:
while integr2 >= i:
calc = integr ** i
calcstr = (str(calc))
output_array.append(calcstr)
i += 1
start_text.set("Start!")
output_array_str = (', '.join(output_array))
# Change the output
output_text.config(state="normal")
# delete last output:
output_text.delete("0.0", "end")
# insert new output:
output_text.insert("end", output_array_str)
output_text.config(state="disabled")
print(output_array_str) #This is just so I know if it's working or not in the terminal
#input
tk.Label(root, text="Number :").grid(row=10)
tk.Label(root, text="Factorial :").grid(row=11)
e1 = tk.Entry(root)
e2 = tk.Entry(root)
e1.grid(row=10, column=1)
e2.grid(row=11, column=1)
#Error message if the input is invalid
error_message = tk.StringVar()
error_text = tk.Label(root, textvariable=error_message, font="Raleway")
error_message.set(" ")
error_text.grid(column=1, row=12)
#Startbutton
start_text = tk.StringVar()
start_btn = tk.Button(root, textvariable=start_text, command=start_calc, font="Raleway", bg="#20bebe", fg="white", height=2, width=15)
start_text.set("Start!")
start_btn.grid(column=1, row=13, pady=10)
#output
output_text = tk.Text(root, height=1, width=20, wrap="none", font="Raleway")
output_text.insert("end", "Output")
output_text.config(state="disabled")
output_text.grid(columnspan=3, column=0, row=14, sticky="news")
#Adding a scrollbar
scrollbar = tk.Scrollbar(root, orient="horizontal", command=output_text.xview)
scrollbar.grid(columnspan=3, column=0, row=15, sticky="news")
output_text.config(xscrollcommand=scrollbar.set)
#disclaimer message
disclaimer_text = tk.Label(root, text="Disclaimer: The factorials will be printed from 1 to the number you entered.")
disclaimer_text.grid(columnspan=3, column=0, row=110)
root.mainloop()
I used a <tkinter.Text> widget with wrap="none", height=1 and width=20 to make the output box. I disabled the entry so that the user can't change the results but can still copy it.
I have been trying to learn tkinter and have created something that post the results of a bunch of functions, and in the terminal the string formats works, but in the gui the string format does not work at all. I am super confused on why?
The code is below:
from tkinter import *
import ForFeesCovered
root = Tk()
root.title("Staff Fee Calculator")
root.geometry("375x400")
myLabel = Label(root,
text="Staff Fee Calculator")
e = Entry(root,
width=50,
borderwidth=5)
def output():
input_file = e.get()
f = ForFeesCovered.readfile(input_file)
file = ForFeesCovered.readfile(input_file)
staff = ForFeesCovered.getnamesofstaff(f)
staff.sort(reverse=False)
dic = ForFeesCovered.sort_dic(staff)
line_skip = 1
for lines in file:
line = lines.strip().split(",")
if line_skip != 1:
total = float("
{:.2f}".format(ForFeesCovered.getfeesforline(line)))
name = ForFeesCovered.get_name_of_staff(line, staff)
dic = ForFeesCovered.populating_dic(dic, name, total)
else:
line_skip += 1
string_dic = ""
result_file = open("result.txt", "w+")
for key in dic:
result_file.write("{} : {}\n".format(key, dic[key]))
string_dic = string_dic + "{:30} : {:>30}\n".format(key,
dic[key])
print(string_dic)
result_file.close()
output_dic = Label(root, text=string_dic, justify=LEFT)
output_dic.grid(row=2, column=0, pady=20)
submit = Button(root, text="Submit", command=output)
myLabel.grid(row=0, column=0)
e.grid(row=1, column=0,)
submit.grid(row=1, column=2)
root.mainloop()
The terminal is using a fixed-width font, the GUI is using a variable-width font.
If you are trying to line things up with spaces, you will need to used a fixed-width font.
I am trying to run a while loop inside my program, but when the while loop is in place, the code stops, and the tkinter window does not open. How do I solve this? It should be so that the code writes out two random numbers, and then when the correct answer is input, it should re-loop.
from tkinter import *
import random
root = Tk()
#Frames
topFrame = Frame(root) # I want an invisible container in root
topFrame.pack()
bottomFrame = Frame(root) # I want an invisible container in root
bottomFrame.pack(side=BOTTOM)
#End Of Frames
#Addition Question Maker
AnswerBox = Entry(topFrame)
AnswerBox.grid(row=0,column=4)
EqualsSign = Label(topFrame, text="=").grid(row=0,column=3)
AdditionSign = Label(topFrame, text="+").grid(row=0,column=1)
NewQuestion = True
while NewQuestion == True:
AdditionQuestionLeftSide = random.randint(0, 10)
AdditionQuestionRightSide = random.randint(0, 10)
global Total
Total = AdditionQuestionLeftSide + AdditionQuestionRightSide
AdditionQuestionRightSide = Label(topFrame, text= AdditionQuestionRightSide).grid(row=0,column=0)
AdditionQuestionLeftSide= Label(topFrame, text= AdditionQuestionLeftSide).grid(row=0,column=2)
answer = None
def OutputAnswerText(event):
global answer
answer = AnswerBox.get()
if Total == int(answer):
Correct = Label(topFrame, text="Correct").grid(row=2,column=3)
NewQuestion = True
else:
Correct = Label(topFrame, text="Wrong").grid(row=2,column=3)
AnswerBox.bind('<Return>', OutputAnswerText)
root.mainloop()
Instead of making a while loop, I suggest making NewQuestion a function. The function gets called initially, then if the answer is correct the function gets called again. Here is my code for the function, along with an automatic entry delete option to remove the need to backspace your answer after inputting a correct answer.
from tkinter import *
import random
root = Tk()
#Frames
topFrame = Frame(root) # I want an invisible container in root
topFrame.pack()
bottomFrame = Frame(root) # I want an invisible container in root
bottomFrame.pack(side=BOTTOM)
#End Of Frames
#Addition Question Maker
AnswerBox = Entry(topFrame)
AnswerBox.grid(row=0,column=4)
EqualsSign = Label(topFrame, text="=").grid(row=0,column=3)
AdditionSign = Label(topFrame, text="+").grid(row=0,column=1)
def NewQuestion():
AdditionQuestionLeftSide = random.randint(0, 10)
AdditionQuestionRightSide = random.randint(0, 10)
global Total
Total = AdditionQuestionLeftSide + AdditionQuestionRightSide
AdditionQuestionRightSide = Label(topFrame, text= AdditionQuestionRightSide).grid(row=0,column=0)
AdditionQuestionLeftSide= Label(topFrame, text= AdditionQuestionLeftSide).grid(row=0,column=2)
answer = None
return
NewQuestion()
def OutputAnswerText(event):
global answer
global AnswerBox
answer = AnswerBox.get()
if Total == int(answer):
Correct = Label(topFrame, text="Correct").grid(row=2,column=3)
AnswerBox.delete(0, END)
NewQuestion()
else:
Correct = Label(topFrame, text="Wrong").grid(row=2,column=3)
AnswerBox.bind('<Return>', OutputAnswerText)
root.mainloop()
You have an infinite loop:
while NewQuestion == True:
There is no place where NewQuestion can become false (and no break in the loop). So the loop is infinite.
Also:
EqualsSign = Label(topFrame, text="=").grid(row=0,column=3)
doesn't work because grid returns None. If you want to keep a reference to the widget, you have to use the two-lines version like in:
AnswerBox = Entry(topFrame)
AnswerBox.grid(row=0,column=4)
What is wrong with this program? Every time I run it the first math problem is show before I push start. Also the answer is always the first math problem, it never changes. Also there should not be a math problem above the timer. Thanks, Scott
from Tkinter import*
import time
import tkMessageBox
import random
def Questions():
number1 = random.randrange(1,25)
number2 = random.randrange(1,50)
answer = number1 + number2
prompt = ("Add " + str(number1) + " and " + str(number2))
label1 = Label(root, text=prompt, width=len(prompt), bg='yellow')
label1.pack()
return answer
def start():
global count_flag
Questions()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
# put the count value into the label
label['text'] = str(count)
# wait for 0.1 seconds
time.sleep(0.1)
# needed with time.sleep()
root.update()
# increase count
count += 0.1
def Submit(answer, entryWidget):
""" Display the Entry text value. """
global count_flag
count_flag = False
print answer
if entryWidget.get().strip() == "":
tkMessageBox.showerror("Tkinter Entry Widget", "Please enter a number.")
if answer != int(entryWidget.get().strip()):
tkMessageBox.showinfo("Answer", "INCORRECT!")
else:
tkMessageBox.showinfo("Answer", "CORRECT!")
# create a Tkinter window
root = Tk()
root.title("Math Quiz")
root["padx"] = 40
root["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(root)
#Create a Label in textFrame
entryLabel = Label(textFrame)
entryLabel["text"] = "Answer:"
entryLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
entryWidget = Entry(textFrame)
entryWidget["width"] = 50
entryWidget.pack(side=LEFT)
textFrame.pack()
#directions
directions = ('Click start to begin. You will be asked a series of questions.')
instructions = Label(root, text=directions, width=len(directions), bg='orange')
instructions.pack()
# this will be a global flag
count_flag = True
answer = Questions()
Sub = lambda: Submit(answer, entryWidget)
#stopwatch = lambda: start(answer)
# create needed widgets
label = Label(root, text='0.0')
btn_submit = Button(root, text="Submit", command = Sub)
btn_start = Button(root, text="Start", command = start)
btn_submit.pack()
btn_start.pack()
label.pack()
# start the event loop
root.mainloop()
Your problem is with how you're calling the Questions() method. You only ask for the answer once with
answer = Questions()
and you do this before you press start (which is why it shows up before you hit start)
To fix it you could use code like this:
from Tkinter import*
import time
import tkMessageBox
import random
def Questions():
number1 = random.randrange(1,25)
number2 = random.randrange(1,50)
answer = number1 + number2
prompt = ("Add " + str(number1) + " and " + str(number2))
label1 = Label(root, text=prompt, width=len(prompt), bg='yellow')
label1.pack()
return answer
def start():
global count_flag
global answer
answer = Questions()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
# put the count value into the label
label['text'] = str(count)
# wait for 0.1 seconds
time.sleep(0.1)
# needed with time.sleep()
root.update()
# increase count
count += 0.1
def Submit(answer, entryWidget):
""" Display the Entry text value. """
global count_flag
count_flag = False
print answer
if entryWidget.get().strip() == "":
tkMessageBox.showerror("Tkinter Entry Widget", "Please enter a number.")
if answer != int(entryWidget.get().strip()):
tkMessageBox.showinfo("Answer", "INCORRECT!")
else:
tkMessageBox.showinfo("Answer", "CORRECT!")
# create a Tkinter window
root = Tk()
root.title("Math Quiz")
root["padx"] = 40
root["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(root)
#Create a Label in textFrame
entryLabel = Label(textFrame)
entryLabel["text"] = "Answer:"
entryLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
entryWidget = Entry(textFrame)
entryWidget["width"] = 50
entryWidget.pack(side=LEFT)
textFrame.pack()
#directions
directions = ('Click start to begin. You will be asked a series of questions.')
instructions = Label(root, text=directions, width=len(directions), bg='orange')
instructions.pack()
# this will be a global flag
count_flag = True
Sub = lambda: Submit(answer, entryWidget)
#stopwatch = lambda: start(answer)
# create needed widgets
label = Label(root, text='0.0')
btn_submit = Button(root, text="Submit", command = Sub)
btn_start = Button(root, text="Start", command = start)
btn_submit.pack()
btn_start.pack()
label.pack()
# start the event loop
root.mainloop()
In this code the answer is updated every time you hit start and only updates when you hit start.