Tkinter cbox doesn't change var value - python

So, essentially what is going on is I made a password manager that had a password generation part to it, I moved it to a windowed Tkinter program for ease of use. I got everything down except for the check box, so at first when the function was called it would give me the error that alphabet had empty length so I set alphabet equal to the list with special characters. After that I tried them with while loops, same result. (this whole code is a function inside the program that only gets ran when a button is pressed) I know I could probably fix this issue with the init but I was hoping if anyone knew an easier way without rewriting too much. Here is the edit to make the code simplified. I used it with a while loop, and got the same result as the if statement. I get the error that a is not defined in this situation.
from tkinter import *
import random
def cbox_var():
while cbox_1 == True:
a = 10
while cbox_1 == False:
a = 20
print(a)
main = Tk()
cbox_1 = Checkbutton(main, text="yes or no")
cbox_1.pack()
testbutton = Button(main,text="Test", command=cbox_var)
testbutton.pack()
main.mainloop()

To get the value of a checkbutton you must assign one of the special tkinter variables to it. You can then get the value by calling the get method on the variable.
Example:
import tkinter as tk
def cbox_var():
checked = cbox_variable.get()
print("Checked?", checked)
main = tk.Tk()
cbox_variable = tk.BooleanVar()
cbox_1 = tk.Checkbutton(main, variable=cbox_variable, text="yes or no")
cbox_1.pack()
testbutton = tk.Button(main,text="Test", command=cbox_var)
testbutton.pack()
main.mainloop()

Related

How to solve error "ValueError: could not convert string to float: ' ' " [duplicate]

It's the whole day I'm trying to solve this ridiculous problem, but without success; in this forum there is a lot of material, but usually they are enormous amounts of code and I cannot understand what's going on. On the internet they generally suggest casting but it doesn't work. To make things easy I wrote a sample code to illustrate the issues I'm having in a bigger code
import tkinter as tk
from tkinter import *
#from tkinter import ttk
my_window = tk.Tk()
my_label = tk.Label(master=my_window,text="N")
my_label.pack()
my_entry = tk.Entry(master=my_window)
my_entry.pack()
N = my_entry.get()
print(float(N))
my_window.mainloop()
Very nice and simple, but I get the following message
ValueError: could not convert string to float: ''
I tried many possibilities, but anything worked. Any little suggestion is very much appreciated. Thanks
Edit:
I want to understand how to assign float(N) to a global variable, say a, so I can use it later on in the code, and I just took the code of #Cool Cloud and modified it a little
import tkinter as tk
from tkinter import *
my_window = tk.Tk()
a=1.
def cast():
N = my_entry.get()
try: # Try to execute this
print(float(N))
a=float(N)
except ValueError: # If ValueError(meaning it is not a float) is triggered then print...
print('Not a number!')
my_label = tk.Label(master=my_window,text="N")
my_label.pack()
my_entry = tk.Entry(master=my_window)
my_entry.pack()
# N = my_entry.get() N will be empty as my_entry is empty when code is executed
Button(my_window,text='Click me to convert to
float',command=cast).pack() # A button to trigger event
print(a)
my_window.mainloop()
The output of this is in the following image
As you can see it directly prints 1.0 without waiting for the assignment a=float(N), so my doubt is how can I actually do this assignment, to use it later in my code. Thanks
P.S.: I understand that print(a) inside the definition of cast() would give correctly 123.0 in this case, but my problem is more general: I'm trying to understand how to entry an N value, making it float and "propagate" it to the rest of the program. My doubt is given by the fact that print(a) almost at the very last line of the program, and still doesn't wait for cast() to come in.
GUI programming is event driven, which means you will have to code based on events triggered. Every python code runs from top to bottom, and in this case all the code from top to bottom, outside functions, is executed. That means as soon as:
my_entry = tk.Entry(master=my_window)
my_entry.pack()
...is executed, the next line to be executed is N = my_entry.get(), and at the time of execution there is NOTHING inside the entry widget and hence N becomes empty string, and then you are trying to convert that empty string to a float, which will obviously give an error.
What you should be doing is, make a button and when you click it(event is triggered) and connect it to a function that will get the input and convert to float. So that when you click the button you have entered something onto the entry and now it is no longer empty.
import tkinter as tk
from tkinter import *
my_window = tk.Tk()
def cast():
N = my_entry.get()
try: # Try to execute this
print(float(N))
except ValueError: # If ValueError(meaning it is not a float) is triggered then print...
print('Not a number!')
my_label = tk.Label(master=my_window,text="N")
my_label.pack()
my_entry = tk.Entry(master=my_window)
my_entry.pack()
# N = my_entry.get() N will be empty as my_entry is empty when code is executed
Button(my_window,text='Click me to convert to float',command=cast).pack() # A button to trigger event
my_window.mainloop()
Another way, and an unpopular way, is to use DoubleVar() which will get() the text for you, in this case, your entry will accept any value but when you get() the value from the DoubleVar() it will raise a TclError if it is not a float.
def cast():
# Unlike before, error will be generated at get() and you dont need float()
# because if there is no error then it is guaranteed to be a float anyway
try:
N = var.get()
print(N)
except TclError: # If TclError is triggered then print...
print('Not a number!')
var = DoubleVar() # tkinter control variable
my_entry = tk.Entry(master=my_window,textvariable=var)
my_entry.pack()
Note: You can do my_entry.get() and it wont give any error even if the input is not a float, error comes only in the case of var.get().
From:https://www.geeksforgeeks.org/python-tkinter-entry-widget/
"get() : Returns the entry’s current text as a string."
I think that you can't just convert string to float.

Create a function that ends mainloop and starts new one in tkinter

I'm writing my first GUI program today using Tkinter and I have stumbled onto a problem. I am trying to make a game that starts with an introduction window that closes after you press a button, then opens a new window where you can choose one of two modes. Unfortunately, I just can't get it running. It looks a little something like this.
#These are the functions that I defined to make it work
def start():
root.destroy()
def Rules_mode_1():
root.destroy
rules1 = Tk()
understood1 = Button(rules1, text="I understood", command="Start_game_mode_1")
understood.pack()
rules1.mainloop
# I haven't added rules 2 yet cause I couldn't get it to work with rules 1 so I haven't even #bothered but it would be the same code just switching the 1 for a 2. But really it isn't even
#necessary to have 2 different rule functions because the rules are the same but I couldn't think
#of another way to go about it. if you have an idea let me know
def Start_game_mode_1():
rules1.destroy #<----- THIS IS WHERE THE PROBLEM LIES. JUST DOESN'T RUN
gamemode1 = Tk()
#Here I would have the game
gamemode1.mainloop()
#now same here don't have gamemode 2 yet cause it just doesn't work yet
#This is where it really starts
root = Tk()
startbutton = Button(root, text="Start", command=start)
startbutton.pack
root.mainloop
root = Tk()
def mode():
mode1 = Button(root, command=Rules_mode_1)
mode1.pack
mode2 = #Buttonblablabla
mode()
root.mainloop()
Now I've been trying around for hours, trying to give the mainloops different names. For example giving the
rules1.mainloop
#the name
root.mainloop
but that obviously didn't work. I tried it with dozens of helper function and with the lambda expression and did hours of research but just can't seem to fix it. Does anybody have any ideas? Please be respectful and keep in mind it's my first time using Tkinter.
Thank you for your help!
After the comments didn't really help me I just tried things out for hours and in case anybody ever is having a a similar problem and reads this: The rules1 variable is inside a function, and therefore only local, which means it can't be destroyed in another function. I fixed it by making it a global, like:
def Rules_mode_1():
root.destroy
global rules1
rules1 = Tk()
understood1 = Button(rules1, text="I understood", command="Start_game_mode_1")
understood.pack()
rules1.mainloop
After that I could destroy the mainloop in the next function.

using Tkinter with condition in python

I want to use Tkinter in loop and not sure how to do that. I want to display an "Correct" message when certain condition is met using Tkinter. for ex if the value is <=20 then it should display message otherwise show " not correct". I am only able to create a code to display message but do not know how to use this message with the condition. Below is my code :
import tkinter
from tkinter import messagebox
# This code is to hide the main tkinter window
root = tkinter.Tk()
root.withdraw()
# Message Box
messagebox.showinfo(" Correct!!")
My solution will going to have an example inspired by your explanation about what you are trying to do.
Well your code would not do anything like you want to. So I am writing a code which will take a number input from a user. If the number is greater than 20 then it would display "Correct" else it would display "Incorrect".
Here is the code I wrote:
import tkinter
from tkinter import messagebox
root = tkinter.Tk()
question = tkinter.Label(root, text="Enter any number")
question.place(x=5, y=5)
question_entry = tkinter.Entry(root)
question_entry.place(x=5, y=50)
def check():
x = 20
y = int(question_entry.get())
if y >= x:
messagebox.showinfo(title="Check", message="Correct!")
elif y < x:
messagebox.showinfo(title="Check", message="Incorrect!")
else:
messagebox.showerror(title="Check", message="Some unexpected error occured!")
submit_button = tkinter.Button(root, text="Start", command=check)
submit_button.place(x=5, y=100)
root.mainloop()
Explanation:
Using label to display "Enter any number"
I have used Entry widget to take input from the user. And to retrieve it I have used int(question_entry.get()). Also I have added int() to make the entry an integer as the default entry is str.
The function check is created so as to run the program when the button is pressed. I have used command=check attribute run the program when it is clicked.
showinfo is being used to send a message in a separate window. showerror is created in else condition just in case some error comes up. (less likely to happen)
I have removed the root.withdraw() statement as this program can be used multiple time. But just in case if you want to hide the window you can add root.withdraw() just above the line x=20 and it would work just fine. (I tried is already)
It there is still something that I failed to explain, please feel free to ask in the comments. :)

Checking if the user presses 'Return' while selected in an Entry box Tkinter

I'm using Tkinter to create a GUI for a simple geometry calculator I'm creating.
Basically, what I have is an Entry box. What I want is for the program/GUI/system to detect when the user of the program hits the 'Enter' or 'return' key WHILE they are in the Entry box. When this is detected, I want the contents of the Entry box to be appended to a list I have defined earlier. I also want a simple label to be created on the GUI that displays the contents of the list (including the appended item(s)). Note that the list begins with nothing in it.
Here is my code so far:
from tkinter import *
#Window setup(ignore this)
app = Tk()
app.title('Geometry Calculator')
app.geometry('384x192+491+216')
app.iconbitmap('Geo.ico')
app.minsize(width=256, height=96)
app.maxsize(width=384, height=192)
app.configure(bg='WhiteSmoke')
#This is the emtry list...
PointList = []
#Here is where I define the variable that I will be appending to the list (which is the object of the Entry box below)
StrPoint = StringVar()
def list_add(event):
#I don't really know how the bind-checking works and how I would implement it; I want to check if the user hits enter while in the Entry box here
if event.char == '':
PointList.append(StrPoint)
e1 = Entry(textvariable=StrPoint).grid(row=0, column=0)
app.bind('<Return>', list_add)
mainloop()
I don't really know the proper way to check for 'Return' and then use it in an if statement.
I hope you understand what I'm trying to get help with, and I've looked all around for an explanation that I could understand with no success.
Instead of binding with the app just bind it with the Entry widget object,i.e,e1
from tkinter import *
#Window setup(ignore this)
app = Tk()
app.title('Geometry Calculator')
app.geometry('384x192+491+216')
app.iconbitmap('Geo.ico')
app.minsize(width=256, height=96)
app.maxsize(width=384, height=192)
app.configure(bg='WhiteSmoke')
#This is the emtry list...
PointList = []
#Here is where I define the variable that I will be appending to the list (which is the object of the Entry box below)
StrPoint = StringVar()
def list_add(event):
print ("hello")
#I don't really know how the bind-checking works and how I would implement it; I want to check if the user hits enter while in the Entry box here
if event.char == '':
PointList.append(StrPoint)
e1 = Entry(textvariable=StrPoint)
e1.grid(row=0, column=0)#use grid in next line,else it would return None
e1.bind('<Return>', list_add)# bind Entry
mainloop()
The solution is to set the binding on the widget itself. That way, the binding will only apply while focus is on that widget. And since you're binding on a specific key, you don't need to check for the value later. You know the user pressed return, because that's the only thing that will cause the binding to fire.
...
e1.bind('<Return>', list_add)
...
You have another problem in that your list_add function needs to call the get method of the variable rather than accessing the variable directly. However, since you aren't using any of the special features of a StringVar, you really don't need it -- it's just one more thing you have to manage.
Here's how to do it without the StringVar:
def list_add(event):
PointLit.append(e1.get())
...
e1 = Entry(app)
e1.grid(row=0, column=0)
e1.bind('<Return>', list_add)
Note that you need to create the widget and lay out the widget in two steps. Doing it the way you did it (e1=Entry(...).grid(...) will cause e1 to be None since that is what .grid(...) returns.

Python Tkinter Calculator wont evaluate text from entry widget

I am trying to make a simple calculator app using tkinter, but everytime I run the code below i get an error message saying
Traceback (most recent call last):
File "C:\Python33\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 326, in RunScript
exec(codeObject, __main__.__dict__)
File "C:\Users\csp\Python\Calculator App.py", line 17, in <module>
solved = eval(expression)
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
CODE:
from tkinter import *
tk = Tk()
tk.title('Calculator')
inp = Entry(tk,text="Enter Expression Here",width=20)
inp.pack()
exit = False
def exitbtn():
global exit
exit = True
return exit
btn = Button(tk,text="Quit?",command=exitbtn)
btn.pack
canvas = Canvas(tk,width=200,height=200)
canvas.pack()
while not exit:
expression = inp.get()
solved = eval(expression)
canvas.create_text(100,100,text=expression,font=('Times', 15))
canvas.create_text(100,150,text=solved,font=('Times', 15))
if exit == True:
break
tk.destroy()
i am really new to Python and dont understand why the "solved = eval(expression)" line wont work. please help
So, the reason why eval is not working is because when you first start your program, expression is just an empty string. If you go to the python shell, and type in eval(''), you'll see the same error appear.
One solution would be to check if expression is an empty string or not, and do something like this:
expression = inp.get()
if expression != '':
solved = eval(expression)
else:
solved = '?'
However, even after you apply this fix, your program won't work, for unrelated reasons. The primary reason is that you never call tk.mainloop() (or whatever it's called), so the window will not show up.
This is because of your while loop -- what you wanted to do was to constantly check the input field and update your canvas whenever you get new input after running it through eval.
However, GUI programs, in general, don't work that way and require a different mindset and approach while writing them. Instead of writing loops to check and update program state, you write functions that will automatically be called whenever the program state changes (which are called events). It'll feel a bit backwards at first, but over time it'll help make your code cleaner and easier to manage.
You're actually already doing this in one part of your program -- with your exitbtn function. Now, you just need to convert your while loop into a similar function and bind it to the Entry object.
EDIT:
Here's some example code that does what you want:
import sys
from tkinter import *
# Create the GUI
tk = Tk()
tk.title('Calculator')
inp = Entry(tk, text="Enter Expression Here", width=20)
inp.pack()
btn = Button(tk, text="Quit?")
btn.pack()
canvas = Canvas(tk, width=200, height=200)
canvas.pack()
# Create callback functions
def end_program(event):
'''Destroys the window and ends the program without needing
to use global variables or a while loop'''
tk.destroy()
sys.exit() # Automatically ends any Python program
def update_canvas(event):
'''Gets the input, tries to eval it, and displays it to the canvas'''
expression = inp.get()
try:
solved = eval(expression)
except SyntaxError:
# The expression wasn't valid, (for example, try typing in "2 +")
# so I defaulted to something else.
solved = '??'
canvas.delete('all') # remove old text to avoid overlapping
canvas.create_text(100, 100, text=expression,font=('Times', 15))
canvas.create_text(100, 150, text=solved,font=('Times', 15))
# Bind callbacks to GUI elements
btn.bind('<Button-1>', end_program)
inp.bind('<KeyRelease>', update_canvas)
# Run the program
tk.mainloop()
Some things to note:
I moved your code for checking inp and writing to the canvas to the update_canvas function, and got rid of the while loop.
The update_canvas function will automatically be called whenever somebody lets go of a key while typing in the inp object (the <KeyRelease> event).
This can cause some problems -- this will mean your update_canvas function will be called while the user is in the process of typing text into your calculator. For example, what if the user types in 2 + 2 *? It's not a complete expression, so can't be parsed by eval.
To solve this, I just wrapped eval in a try-except to prevent any bad input from mucking up the program.
Similarly, end_program will be called whenever somebody left-clicks on the btn object (the <Button-1> event).

Categories

Resources