Any idea on how to make all the entry and labels in my GUI start blank but then update when the calculate function happens? They currently start with a 0. I have tried many things but nothing has worked.
Here is code:
from tkinter import *
root = Tk(className="Page Calculator")
root.title("PgCalc")
read = IntVar()
total = IntVar()
left = IntVar()
percent = IntVar()
def calculate(event=None):
try:
left.set(total.get() - read.get())
percent.set(int(read.get()*100/total.get()))
except ZeroDivisionError:
print("ZeroDivisionError")
else:
print()
root.bind('<Return>', calculate)
read_label = Label(root,text="Pages Read:")
read_label.grid(column=1, row=1)
read_entry = Entry(root, width=8, textvariable=read)
read_entry.grid(column=2, row=1)
read_entry.focus()
total_label = Label(root,text="Total Pages:")
total_label.grid(column=1, row=2)
total_entry = Entry(root, width=8, textvariable=total)
total_entry.grid(column=2, row=2)
calculate_button = Button(root,text="Calculate",command= calculate)
calculate_button.grid(column=2, row=3)
percent_label = Label(root,text="Percent Finished:")
percent_label.grid(column=1, row=4)
left_label = Label(root,text="Pages Left:")
left_label.grid(column=1, row=5)
percentresult_label = Label(root,textvariable=percent)
percentresult_label.grid(column=2, row=4)
leftresult_label = Label(root,textvariable=left)
leftresult_label.grid(column=2, row=5)
root.mainloop()
IntVar() has a default value of 0. Even though they are IntVar, you can set strings as their value (note that when you try to get its value, you'll get an error if they still contain strings).
So you can simply do
read = IntVar()
read.set("")
But, since you are using Entry, you don't need any IntVar at all. You can directly get entry's value and cast it to an integer.
def calculate(event=None):
try:
leftresult_label.config(text=str(int(total_entry.get()) - int(read_entry.get())))
except ValueError:
print("Please enter a number")
#You need to remove textvariables from entries as well like below
total_entry = Entry(root, width=8)
Related
I'm gonna preface this by saying that im quite new to this, dont judge haha.
The script im writing is to make a random password from different strings and randomize them. That I have already succeeded in completing, but know that I want to build a GUI for that script, the implementation with functions and tkinter is giving me trouble. I have two functions: One (add2all)that is supposed to check wether a variable is true, and if it is true add it to the string "all", that im later going to randomize with my second function. Im sure there are problems with how I get the value from the Checkbuttons (used to get the user input what kind of characters they want in the password), and then how they are added to the string. My second function (pwdgen) is supposed to get the input length from an Entry box were the user types an int, and then calls the add2all function to see what characters the user wants. add2all should generate a string with all the charracters that have been defined as true, so that pwdgen can randomize them with the given length. I also have a Button that is supposed to start the process. It calls on pwdgen, which then ccalls add2all and at the end, the variable password should have a randomized string which I can display to an entry box.
TL;DR: The function and tkinter implementation of a very simple script I previously wrote isn't working at all.
import random
from tkinter import *
from tkinter import ttk
root = Tk()
upper, lower, nums, syms = False, False, False, False
uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lowercase = "abcdefghijklmnopqrstuvwxyz"
digits = "1234567890"
symbols = "!§$%&?*+#~-;()/"
all = StringVar()
CheckBool1 = IntVar()
CheckBool2 = IntVar()
CheckBool3 = IntVar()
CheckBool4 = IntVar()
pwlength = IntVar()
#function that checks if a CheckButton input (which characters are wanted in password)
#is true, if true adds the corresponding character string to the all string
def add2all():
if CheckBool1:
upper = True
if CheckBool2:
lower = True
if CheckBool3:
nums = True
if CheckBool4:
syms = True
if upper:
all += uppercase
if lower:
all += lowercase
if nums:
all += digits
if syms:
all += symbols
#function that gets password length from user, then calls add2all, then gives var password
#the string of all randomized with specified length and then puts it into entry box pwdoupt
def pwdgen():
pwdoutpt.delete(0, END)
v = amt.get()
v = pwlength
add2all()
password = "".join(random.choices(all, k=pwlength))
pwdoutpt.insert(0, password)
greet = Label(root, text="Welcome to the interactive password generator!", height=3)
pwdoutpt = Entry(root, width=30)
generate = Button(root, text="Generate", command = lambda: pwdgen())
#inits all the labels and checkbuttons for my gui
chck_1 = Checkbutton(root, width = 5, var = CheckBool1)
chck_2 = Checkbutton(root, width = 5, var = CheckBool2)
chck_3 = Checkbutton(root, width = 5, var = CheckBool3)
chck_4 = Checkbutton(root, width = 5, var = CheckBool4)
lbl_1 = Label(root, text="Capital Letters")
lbl_2 = Label(root, text="Lowercase Letters")
lbl_3 = Label(root, text="Digits")
lbl_4 = Label(root, text="Symbols")
amt = Entry(root, width = 5)
amtlbl = Label(root, text="Num of characters in pwd.")
sep = ttk.Separator(root, orient="horizontal")
greet.grid(column=0, row=0, columnspan=4, pady=3)
pwdoutpt.grid(column=0, row=7, columnspan=4, padx=30, sticky=W)
amt.grid(column=0, row=1, sticky=W)
amtlbl.grid(column=1, row=1, columnspan=1, sticky=E)
chck_1.grid(column=0, row=2, sticky=E)
chck_2.grid(column=0, row=3, sticky=E)
chck_3.grid(column=0, row=4, sticky=E)
chck_4.grid(column=0, row=5, sticky=E)
lbl_1.grid(column=1, row=2, columnspan=1, sticky=W)
lbl_2.grid(column=1, row=3, columnspan=1, sticky=W)
lbl_3.grid(column=1, row=4, columnspan=1, sticky=W)
lbl_4.grid(column=1, row=5, columnspan=1, sticky=W)
sep.grid(column=0, columnspan=10, row=6, sticky=EW)
generate.grid(column=2, row=7)
root.mainloop()
Firstly, don't use all as the variable name for your StringVar; it's a built-in python function. Don't use wildcard imports (from <module> import *), it's a bad habit and doesn't conform to PEP8. Instead, use import tkinter as tk.
You need to read how to use a StringVar; it is NOT a string and you can't add to it like one. A good application of using a StringVar in this code would be to display the generated password. If you bind the StringVar to your pwdoutpt Entry, updating the StringVar will automatically display the updated string.
You say you already had your password generator working correctly. Why not slightly adapt your password generator function so it takes the length and character types as inputs, and returns a randomly generated password? You are currently trying to integrate the password generating function into the GUI code, which is a bad idea is it can get messy super fast.
Taking all of the above into consideration, here is a working modified version of your code:
import random
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
# Your password generating function
def pwdgen(password_length, chars_allowed):
chars = [
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"abcdefghijklmnopqrstuvwxyz",
"1234567890",
"!§$%&?*+#~-;()/"
]
valid_chars = [x for i, x in enumerate(chars) if chars_allowed[i] == True]
valid_chars = "".join(valid_chars)
password = "".join(random.choices(valid_chars, k=password_length))
return password
# Set up tkinter window
root = tk.Tk()
root.title("Password generator")
# Vars for checkbuttons and password entry
CheckBool1 = tk.IntVar()
CheckBool2 = tk.IntVar()
CheckBool3 = tk.IntVar()
CheckBool4 = tk.IntVar()
password = tk.StringVar()
# Main widgets
greet = tk.Label(root, text="Welcome to the interactive password generator!", height=3)
chck_1 = tk.Checkbutton(root, width = 5, var = CheckBool1)
chck_2 = tk.Checkbutton(root, width = 5, var = CheckBool2)
chck_3 = tk.Checkbutton(root, width = 5, var = CheckBool3)
chck_4 = tk.Checkbutton(root, width = 5, var = CheckBool4)
lbl_1 = tk.Label(root, text="Capital Letters")
lbl_2 = tk.Label(root, text="Lowercase Letters")
lbl_3 = tk.Label(root, text="Digits")
lbl_4 = tk.Label(root, text="Symbols")
amt = tk.Entry(root, width = 5)
amtlbl = tk.Label(root, text="Num of characters in pwd.")
sep = ttk.Separator(root, orient="horizontal")
# Password output
pwdoutpt = tk.Entry(root, width=30, textvariable=password, state="readonly")
# Generate password function and button
def insert_password():
try:
password_length = int(amt.get())
chars_allowed = [CheckBool1.get(), CheckBool2.get(), CheckBool3.get(), CheckBool4.get()]
password.set(pwdgen(password_length, chars_allowed))
except ValueError:
messagebox.showerror("Error", "Invalid password length")
except IndexError:
messagebox.showerror("Error", "No character type selected")
generate = tk.Button(root, text="Generate", command = insert_password)
# Gridding widgets
greet.grid(column=0, row=0, columnspan=4, pady=3)
pwdoutpt.grid(column=0, row=7, columnspan=4, padx=30, sticky=tk.W)
amt.grid(column=0, row=1, sticky=tk.W)
amtlbl.grid(column=1, row=1, columnspan=1, sticky=tk.E)
chck_1.grid(column=0, row=2, sticky=tk.E)
chck_2.grid(column=0, row=3, sticky=tk.E)
chck_3.grid(column=0, row=4, sticky=tk.E)
chck_4.grid(column=0, row=5, sticky=tk.E)
lbl_1.grid(column=1, row=2, columnspan=1, sticky=tk.W)
lbl_2.grid(column=1, row=3, columnspan=1, sticky=tk.W)
lbl_3.grid(column=1, row=4, columnspan=1, sticky=tk.W)
lbl_4.grid(column=1, row=5, columnspan=1, sticky=tk.W)
sep.grid(column=0, columnspan=10, row=6, sticky=tk.EW)
generate.grid(column=2, row=7)
root.mainloop()
Some further notes on the code for you:
The function insert_password uses a try except to test if the inputs are correct before generating the password.
pwdoutpt has state="readonly" so that the user can't modify the generated password but can still copy it
I'm trying to create a function in tkinter where I can print out what the user writes in a Entry box. I'm able to print out ask_an_entry_get, but when I try to print what_is_answer_entry_get
, I get nothing my empty spaces.
Please find out the problem here. Also I'm using the Entry widget, along with the get() function, to get input from the user.
def answer_quizmaker_score():
print(ask_an_entry_get)
print(what_is_answer_entry_get)
I made a lot of global variables so I could use them all around my code.
global what_is_answer_entry
what_is_answer_entry = Entry(root4)
what_is_answer_entry.pack()
I then used the get() function to retrieve what the user typed.
global what_is_answer_entry_get
what_is_answer_entry_get = what_is_answer_entry.get()
This is the exact process I did for both ask_an_entry_get and what_is_answer_entry_get. However for some reason only ask_an_entry_get is printed, while what_is_answer_entry_get is printing nothing in the console.
from tkinter import *
root = Tk()
root.geometry("500x500")
txt1 = StringVar()
txt2 = StringVar()
def txt_printer():
print(txt1.get())
print(txt2.get())
x = Entry(root, textvariable=txt1, width=20)
x.place(x=0, y=0)
y = Entry(root, textvariable=txt2, width=20)
y.place(x=0, y=50)
btn_print = Button(root, text="print", command=txt_printer)
btn_print.place(x=0, y=100)
# Or if you want to show the txt on window then:
def txt_on_window():
lb1 = Label(root, text=txt1.get())
lb1.place(x=0, y=200)
lb2 = Label(root, text=txt2.get())
lb2.place(x=0, y=235)
btn_print_on_window = Button(root, text="print on screen", command=txt_on_window)
btn_print_on_window.place(x=0, y=150)
root.mainloop()
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.
Hello im having python learning project. I want to insert in GUI two numbers, which are defining range for program to generate random number from.
I am really having problems with calling function with press of the button. And constantly getting error ValueError: invalid literal for int() with base 10: '', when trying to convert string from entry in GUI to int and then inserting them into random.randint.
Thx for Help!
from tkinter import *
import random
root = Tk()
root.title("Generator custom random number")
#function that gets number from entry converts string to int and defines target number in stevilo
def function():
string_answer1 = prvo_stevilo.get()
int1 = int(string_answer1)
string_answer2 = drugo_stevilo.get()
int2 = int(string_answer2)
stevilo = random.randint(int1, int2)
#Defining GUI
navodilo = Label(root, text="Choose custom lower and upper number to chose random number from", width=60)
navodilo2 = Label(root, text="From", width=20, borderwidth=3)
navodilo3 = Label(root, text="To", width=20, borderwidth=3)
prvo_stevilo = Entry(root, width=20, borderwidth=3)
drugo_stevilo = Entry(root, width=20, borderwidth=3)
gumb = Button(root, text="Generate number", width=17, height=2, command=function)
praznavrstica = Label(root, text="")
izpis = Label(root, text="Random number is: ", width=20)
izpis_stevila = Label(root, text="" + stevilo)
#Showcase of gui
navodilo.grid(row=0, column=0, columnspan=1)
navodilo2.grid(row=1, column=0, columnspan=1)
navodilo3.grid(row=3, column=0, columnspan=1)
prvo_stevilo.grid(row=2, column=0, columnspan=1)
drugo_stevilo.grid(row=4, column=0, columnspan=1)
praznavrstica.grid(row=5, column=0, columnspan=1)
gumb.grid(row=6, column=0, columnspan=1)
praznavrstica.grid(row=7, column=0, columnspan=1)
izpis.grid(row=8, column=0, columnspan=1)
izpis_stevila.grid(row=9, column=0, columnspan=1)
#Loop
root.mainloop()
I've noticed few problems with your code. I was able to make it running without too many changes, although probably it is not the best way.
First answer to your question: you are getting this error, because you are trying to change string -> '' to int. It happens because function() is running before you click button.
Another problem:
izpis_stevila = Label(root, text="" + stevilo)
variable 'stevilo' simply doesn't exist before calling function(), so delete it from here.
My proposition for changes:
1)
gumb = Button(root, text="Generate number", width=17, height=2,command = lambda: function())
Without lambda your function will run no matter of state of your button.
2)
first = IntVar(root, value=0)
second = IntVar(root, value=1)
prvo_stevilo = Entry(root, width=20, borderwidth=3, textvariable=first)
drugo_stevilo = Entry(root, width=20, borderwidth=3, textvariable=second)
If you run function without any values in your entry you will get error. This change allows you to put default value for your entry widgets.
3)
def function():
if prvo_stevilo.get() == '' or drugo_stevilo.get() =='':
return
else:
string_answer1 = prvo_stevilo.get()
int1 = int(string_answer1)
string_answer2 = drugo_stevilo.get()
int2 = int(string_answer2)
stevilo = random.randint(int1, int2)
izpis_stevila = Label(root, text=str(stevilo))
izpis_stevila.grid(row=9, column=0)
Firstly check if your entry is not empty.
Secondly update label, also remeber about changing int to string here text=str(stevilo).
I am a beginner. I have tried everything to make the following code take numeric inputs into entry boxes and do a calculation with them. I am getting the ValueError and nothing I do makes that stop happening. This is supposed to be a program that calculates monthly interest payments and a total paid out. I am keeping it at a simple product until I fix this much more basic problem. Thanks.
def multiply(var1, var2, var3):
product = float(var1 * var2 * var3)
return product
def btnClick(event):
x = float(entry.get())
main = Tk()
main.title("Assignment 16")
main.geometry("500x500")
main["bg"] = "#000066"
lblFirst = Label(main, text="Amount to Pay: ")
lblFirst.grid(row=0, column=3, pady=5)
entry = Entry(main, width=20)
entry.grid(row=0, column=4)
amount = entry.get()
lblSecond = Label(main, text="Interest Rate (like 7.5): ")
lblSecond.grid(row=2, column=3, pady=10)
entry2 = Entry(main, width=20)
entry2.grid(row=2, column=4)
rate = entry2.get()
lblThird = Label(main, text="Years to Pay: ")
lblThird.grid(row=4, column=3, pady=15)
entry3 = Entry(main, width=20)
entry3.grid(row=4, column=4)
years = entry3.get()
try:
# Try to make it a float
if amount.isnumeric():
amount = float(amount)
except ValueError:
# Print this if the input cannot be made a float
print("Bad input")
try:
# Try to make it a float
if rate.isnumeric():
rate = float(rate)
except ValueError:
# Print this if the input cannot be made a float
print("Bad input")
try:
# Try to make it a float
if years.isnumeric():
years = int(years)
except ValueError:
# Print this if the input cannot be made a float
print("Bad input")
lblFourth = Label(main, text="Monthly Payment: ")
lblFourth.grid(row=6, column=3, pady=15)
lblFourthTwo = Label(main, text="XXXXX")
lblFourthTwo.grid(row=6, column=4)
lblFifth = Label(main, text="Total of Paymenta: ")
lblFifth.grid(row=8, column=3, pady=15)
lblFifthTwo = Label(main, text="XXXXX")
lblFifthTwo.grid(row=8, column=4)
button1 = Button(main, text='Convert', width=10, command=btnClick)
button2 = Button(main, text='Calculate', width=10, command=multiply(amount, rate, years))
button1.grid(padx=20, pady=20)
main.mainloop()
All your code runs before the mainloop starts.
Programs using GUI-toolkits like tkinker are event-driven. Your code only runs in the set-up before the mainloop and after that in event-handlers.
You can use validation to ensure that only numbers are entered.
Working example (for Python 3) below. This also shows how to get the value from an editbox in an event handler and how to create synthetic events to update other widgets.
import tkinter as tk
from tkinter import ttk
# Creating and placing the widgets
root = tk.Tk()
root.wm_title('floating point entry')
qedit = ttk.Entry(root, justify='right')
qedit.insert(0, '100')
qedit.grid(row=0, column=0, sticky='ew')
result = ttk.Label(root, text='100')
result.grid(row=1, column=0)
ttk.Button(root, text="Exit", command=root.quit).grid(row=2, column=0)
# Callback functions
def is_number(data):
if data == '':
return True
try:
float(data)
print('value:', data)
except ValueError:
return False
result.event_generate('<<UpdateNeeded>>', when='tail')
return True
def do_update(event):
w = event.widget
number = float(qedit.get())
w['text'] = '{}'.format(number)
# The following settings can only be done after both the
# widgets and callbacks have been created.
vcmd = root.register(is_number)
qedit['validate'] = 'key'
qedit['validatecommand'] = (vcmd, '%P')
result.bind('<<UpdateNeeded>>', do_update)
# Run the event loop.
root.mainloop()