Related
This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 2 years ago.
Hello im trying to create a questionnaire with 5 choises for each question. Since I have lots of questions, I wanted to create labels and radiobuttons in a loop. However, I can not call mainloop() function of tkinter in a loop so when I call it on the outside of the loop, my selection on the questionnaire of any question becomes the answer of the last question. How can I fix this?
def selected(value, question):
answer_values[question-1] = value
print(value, question)
root = Tk()
root.title('Kişilik Analiz Testi')
answers = {}
for x in range(0, enneagram.shape[0]):
soru = str(x+1) + ". " + enneagram.SORULAR[x] + " Cümlesi sizi ne kadar iyi ifade ediyor?"
myLabel = Label(root, text = soru).grid(row = x+1, column = 1, sticky = W)
Label(root, text = "Sorular").grid(row = 0, column = 1, sticky = W)
Label(root, text = "Çok Zayıf ").grid(row = 0, column = 2)
Label(root, text = "Zayıf ").grid(row = 0, column = 3)
Label(root, text = "Orta ").grid(row = 0, column = 4)
Label(root, text = " İyi ").grid(row = 0, column = 5)
Label(root, text = "Çok İyi").grid(row = 0, column = 6)
answers["soru{0}".format(x)] = IntVar()
answers["soru{0}".format(x)].set(3)
button = Radiobutton(root, variable = answers["soru{0}".format(x)], value = 1, command = lambda: selected(1, x+1)).grid(row = x+1, column = 2)
button = Radiobutton(root, variable = answers["soru{0}".format(x)], value = 2, command = lambda: selected(2, x+1)).grid(row = x+1, column = 3)
button = Radiobutton(root, variable = answers["soru{0}".format(x)], value = 3, command = lambda: selected(3, x+1)).grid(row = x+1, column = 4)
button = Radiobutton(root, variable = answers["soru{0}".format(x)], value = 4, command = lambda: selected(4, x+1)).grid(row = x+1, column = 5)
button = Radiobutton(root, variable = answers["soru{0}".format(x)], value = 5, command = lambda: selected(5, x+1)).grid(row = x+1, column = 6)
root.mainloop()
When I run this cell, i get this window. Default choice is the middle one. When I click on other choices it prints out the index of the last question:
Try this code:
import tkinter as tk
from functools import partial
def function(i):
print("You toggled number %i"%i)
print([var.get() for var in variables])
root = tk.Tk()
variables = []
for i in range(5):
# Create the new variable
variable = tk.IntVar()
variables.append(variable)
# Create the command using partial
command = partial(function, i)
# Create the radio button
button = tk.Radiobutton(root, variable=variable, value=i, command=command)
button.pack()
root.mainloop()
It uses the partial function/class from functools.
I am creating a code to create a calculator but I keep on getting this error:
Traceback (most recent call last):
File "C:\Users\Monish Shah\AppData\Local\Programs\Python\Python36-
32\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\Monish Shah\AppData\Local\Programs\Python\Python36-
32\monish-play\calc-completed-copy-for-editing-copy2.py", line 40, in click
Label (window, text = str(sqrt(n_textentry)), bg = "white") .grid(row = 13,
column = 0, sticky = N)
TypeError: must be real number, not Entry
Does anyone know why my code does not work? I don't really understand why it cannot be and entry since I am collecting the user's input? I was researching but I could not figure out how to correctly incorporate the user's input into the code.
Here is my code that I used:
from math import sqrt
from tkinter import *
window = Tk()
window.title("Welcome to Calculator ")
window.configure(background = "white")
Label (window, text = "Calculator", bg = "white") .grid(row = 0, column = 0,
sticky = N)
#to create the box for the first number and store it
Label (window, text = "Enter the first number", bg = "white") .grid(row = 1,
column = 0, sticky = N)
n_textentry = Entry(window, width = 10, bg = "white")
n_textentry.grid(row = 2, column = 0, sticky = N)
#to create the box for the second number
Label (window, text = "Enter the second number", bg = "white") .grid(row = 5,
column = 0, sticky = N)
m_textentry = Entry(window, width = 10, bg = "white")
m_textentry.grid(row = 6, column = 0, sticky = N)
#click function
def click():
n_textentry.get()
m_textentry.get()
operation_textentry.get()
if operation_textentry == 1:
result1 = Label (window, text = str(n_textentry + m_textentry), bg =
"white") .grid(row = 13, column = 0, sticky = N)
elif operation_textentry == 2:
Label (window, text = str(n_textentry - m_textentry), bg = "white")
.grid(row = 13, column = 0, sticky = N)
elif operation_textentry == 3:
Label (window, text = str(n_textentry * m_textentry), bg = "white")
.grid(row = 13, column = 0, sticky = N)
elif operation_textentry == 4:
Label (window, text = str(n_textentry / m_textentry), bg = "white")
.grid(row = 13, column = 0, sticky = N)
elif operation_textentry == 5:
Label (window, text = str(n_textentry ** m_textentry), bg = "white")
.grid(row = 13, column = 0, sticky = N)
else:
Label (window, text = str(sqrt(n_textentry)), bg = "white")
.grid(row = 13, column = 0, sticky = N)
# operation_textentry == 6:
# Label (window, text = str(sqrt(n_textentry)), bg = "white")
.grid(row = 13, column = 0, sticky = N)
#else:
# print("Invalid Operation ")
#to show list of options
Label (window, text = '''
Enter 1 for addition
Enter 2 for subtraction
Enter 3 for multiplication
Enter 4 for division
Enter 5 for exponentiation
Enter 6 for square root *This will only work for 1st choice*''', bg =
"white") .grid(row = 9, column = 0, sticky = W)
operation_textentry = Entry(window, width = 10, bg = "white")
operation_textentry.grid(row = 10, column = 0, sticky = N)
Button(window, text = "Submit", width = 6, command=click) .grid(row = 11,
column = 0, sticky = N)
There are a number of problems with this code:
You need to store the results of those get calls.
As suggested by Joel, you need to convert them to float or int.
You should create the results Label once at startup, and config the text in this callback, instead of creating a new Label every time the user hits Submit.
Instead of repeating all of the same code 6 times, just calculate a result in the elif chain, and then use it at the end.
I already explained most of this in my answer to your previous question.
The result should look something like this:
result_label = Label(window, text = str(n_textentry ** m_textentry), bg = "white")
result_label.grid(row = 13, column = 0, sticky = N)
def click():
n = int(n_textentry.get())
m = int(m_textentry.get())
operation = int(operation_textentry.get())
if operation == 1:
result = n+m
elif operation == 2:
result = n-m
elif operation == 3:
result = n*m
elif operation == 4:
result = n/m
elif operation == 5:
result = n**m
else:
result = "Invalid Operation"
result_label.config(text=str(result))
As I mentioned before, you probably want some error handling for the case where the user leaves one of the entries blank, or inputs text instead of a number, or divides by zero, etc. The simplest way to do this with a try: around the whole click function:
def click():
try:
n = int(n_textentry.get())
# etc.
except Exception as e:
result_label.config(text=repr(e))
Try converting user input to a float or int. It looks like you're trying to apply a mathematical operation on user input (the Entry object), but mathematical operations are not supported for Entry objects.
I was trying to create a code to create a GUI Calculator with buttons and I tried looking up Tkinter help, but I was not able to get help. How do I incorporate the commented out section at the bottom to display the value of the numbers shown? Please feel free to add suggestions to my code.
EDIT: I fixed the code as #abarnert suggested but when I run the code, it always writes Invalid Operation. I do not know how to fix this. Does anyone have a better idea to fix my code? I just need to get the operation to work. My edited code is below.
from math import sqrt
from tkinter import *
window = Tk()
window.title("Welcome to Calculator ")
window.configure(background = "white")
Label (window, text = "Calculator", bg = "white") .grid(row = 0, column =
0, sticky = N)
#click function
def click():
n = n_textentry.get()
m = m_textentry.get()
operation = operation_textentry.get()
if operation == 1:
print(n + m)
elif operation == 2:
print(n - m)
elif operation == 3:
print(n * m)
elif operation == 4:
print(n / m)
elif operation == 5:
print(n ** m)
elif operation == 6:
print(sqrt(n))
else:
print("Invalid Operation ")
#to create the box for the first number and store it
Label (window, text = "Enter the first number", bg = "white") .grid(row =
1, column = 0, sticky = N)
n_textentry = Entry(window, width = 10, bg = "white")
n_textentry.grid(row = 2, column = 0, sticky = N)
Button(window, text = "Submit", width = 6, command=click) .grid(row = 3,
column = 0, sticky = N)
#to create the box for the second number
Label (window, text = "Enter the second number", bg = "white") .grid(row =
5, column = 0, sticky = N)
m_textentry = Entry(window, width = 10, bg = "white")
m_textentry.grid(row = 6, column = 0, sticky = N)
Button(window, text = "Submit", width = 6, command=click) .grid(row = 7,
column = 0, sticky = N)
#to show list of options
Label (window, text = ''' Enter 1 for addition
Enter 2 for subtraction
Enter 3 for multiplication
Enter 4 for division
Enter 5 for exponentiation
Enter 6 for square root *This will only work for 1st choice*''', bg =
"white") .grid(row = 9, column = 0, sticky = W)
operation_textentry = Entry(window, width = 10, bg = "white")
operation_textentry.grid(row = 10, column = 0, sticky = N)
Button(window, text = "Submit", width = 6, command=click) .grid(row = 11,
column = 0, sticky = N)
In a GUI program, once the GUI is up and running, you can only run your code in the callbacks to event handlers. This is called event-driven programming, and it can take a while to get used to at first.
For example, when the user clicks that first Submit button, it calls your function click. Inside that function, you can do whatever's appropriate there.
You've made all three buttons call the same click function. That doesn't make too much sense here.
In fact, why do you even want three separate buttons? Think of a typical form in a typical GUI—there's a bunch of Entry fields, and then a single "Submit" button that the user clicks after filling out all of the fields. So, let's just scrap the first two buttons and only have one at the end.
Now, inside that click function, you can "do whatever's appropriate". But what's appropriate here?
The first thing you need to do is get the values out of the three Entry boxes. But you tried to store all three of them in the same variable, so you can't access all three of them, only the last one. So, instead of doing this three times:
textentry = Entry(window, width = 10, bg = "white")
… give them all different names:
n_entry = Entry(window, width = 10, bg = "white")
# ...
m_entry = Entry(window, width = 10, bg = "white")
# ...
operation_entry = Entry(window, width = 10, bg = "white")
And now, your click function can get all three values:
def click():
n = n_entry.get()
m = m_entry.get()
operation = operation_entry.get()
Of course these are going to be strings—exactly like what you get back from calling input() in a command-line app. So, you have to do the same thing here—call int or float on them, handle errors, etc.
But, once you've done that, the rest of click can be your existing commented-out code. (Except that you have to get rid of those break statements—there's no loop to break out of here.)
if operation == 1:
print(n + m)
elif operation == 2:
print(n - m)
# etc.
However, you might want to change those print calls to instead display the result in the GUI. For example, you might have an empty Label named results_label, and config its text to be str(n+m), etc.
I am in the process of making a Hangman type game. So far, I have written the CLI version which works well, i'm just porting it over to create a GUI.
I have become stuck :-(. The program is not complete, and there's still more to do but I have two issues. The first is the label update.
When a letter is chosen, it creates enough dashes for the letter, and places this in a label called 'letter'.
When a user enters a letter, it replaces the dashes, however it then adds a new label next to the old label, instead, I would like to replace this label. I have tried using the .set() but this doesn't seem to work.
My second issue, and this is more of a logic error (I think), is that I wanted to keep track of the letters entered so that I could compare this to newly entered letters and alert the user. This works well, however when a letter has been entered it will warn the user even if its the first time it has been typed.
Here's the code:
import tkinter
from tkinter import *
from tkinter import messagebox
import random
guesses = 8
def play():
print("play game")
wordList = ["talking", "dollar","choice", "famous", "define", "features"]
wordChoice = random.choice(wordList)
print(wordChoice)
wordLength = (len(wordChoice))
print(wordLength)
guessedLetters = []
dashes = []
def enterLetter():
print("Guess")
global guesses
print(guessedLetters)
while guesses != 0:
guess = entry.get().lower()
if len(guess) >1:
messagebox.showinfo("Error","Sorry, only one letter at a time")
entry.delete("0","end")
return
elif guess.isalpha() == False:
messagebox.showinfo("Error","Letters only please")
entry.delete("0","end")
return
elif guess in guessedLetters:
messagebox.showinfo("Error","You have already used the letter")
entry.delete("0","end")
return
guessedLetters.append(guess)
print(guessedLetters)
print(guesses)
count = 0
for i in range(wordLength):
if wordChoice[i] == guess:
dashes[i] = guess
count = count +1
letter = Label(play, text = dashes, font = ("Arial",20)).grid(row = 2, column = i+1,padx = 10, pady =10)
if count == 0:
guesses -= 1
if guesses == 0:
print("You have ran out of guesses!")
print("The word was:",wordChoice)
###### Play Game GUI
play = Toplevel()
play.title("Play Hangman!")
label = Label(play, text="HANGMAN", font = ("Arial",16)).grid(row = 0)
label = Label(play, text="Enter your guess >").grid(row = 3, column = 0)
for i in range(wordLength):
dashes.append("-")
letter = Label(play, text = dashes, font = ("Arial",20)).grid(row = 2, column = i+1,padx = 10, pady =10)
entry = Entry(play)
entry.grid(row = 3, column = 1, columnspan = wordLength)
enterButton = Button(play, text = "Enter Guess", width = 15, command = enterLetter).grid(row = 3, column = (wordLength+2))
label = Label(play, text = "Letter used: ").grid(row = 4, columnspan = 2)
label = Label(play, text = "").grid(row= 4, columnspan = 6)
def scores():
print("check scores")
def howToPlay():
print("how to play")
####### Main Menu
root = Tk()
root.geometry("500x300")
root.title("HANGMAN")
label = Label(root, text="HANGMAN", font = ("Arial",30)).grid(row = 0, columnspan = 3)
label = Label(root, text = "Option 1 :", font = ("Arial",12)).grid(row = 1, column = 1)
playButton = Button(root, text = "Play Game", width = 15, command = play).grid(row = 1, column = 2)
label = Label(root, text = "Option 2 :", font = ("Arial",12)).grid(row = 2, column = 1)
instructionsButton = Button(root, text = "How to play", width = 15, command = howToPlay).grid(row = 2, column = 2)
label = Label(root, text = "Option 3 :", font = ("Arial",12)).grid(row = 3, column = 1)
scoresButton = Button(root, text = "View Scores", width = 15, command = scores).grid(row = 3, column = 2)
label = Label(root, text = "Option 4 :", font = ("Arial",12)).grid(row = 4, column = 1)
exitButton = Button(root, text = "Exit", width = 15, command = exit).grid(row = 4, column = 2)
root.mainloop()
You need to configure the Label, not recreate it.
Why do you use a while-loop in enter_letter? Its just run when the Button is clicked, it needs to be an if guesses > 0:
Your program did not terminate when the right word was entered; I added this.
Code:
import tkinter
from tkinter import *
from tkinter import messagebox
import random
guesses = 8
letter = None
def play():
global letter
print("play game")
wordList = ["talking", "dollar","choice", "famous", "define", "features"]
wordChoice = random.choice(wordList)
print(wordChoice)
wordLength = (len(wordChoice))
print(wordLength)
guessedLetters = []
dashes = []
play = Toplevel()
play.title("Play Hangman!")
label = Label(play, text="HANGMAN", font = ("Arial",16)).grid(row = 0)
label = Label(play, text="Enter your guess >").grid(row = 3, column = 0)
for i in range(wordLength):
dashes.append("-")
letter = Label(play, text = dashes, font = ("Arial",20))
letter.grid(row = 2, column = i+1,padx = 10, pady =10)
print(letter)
def enterLetter():
print("Guess")
global guesses, letter
print(guessedLetters)
if guesses != 0:
guess = entry.get().lower()
if len(guess) >1:
messagebox.showinfo("Error","Sorry, only one letter at a time")
return
elif guess.isalpha() == False:
messagebox.showinfo("Error","Letters only please")
return
elif guess in guessedLetters:
messagebox.showinfo("Error","You have already used the letter")
return
entry.delete("0","end")
guessedLetters.append(guess)
#print(guessedLetters)
#print(guesses)
print(dashes)
count = 0
for i in range(wordLength):
if wordChoice[i] == guess:
dashes[i] = guess
count += 1
letter.configure(text = dashes)
if count == 0:
guesses -= 1
if "".join(dashes) == wordChoice:
print("succsess!")
play.destroy()
return
if guesses == 0:
print("You have ran out of guesses!")
print("The word was:",wordChoice)
###### Play Game GUI
entry = Entry(play)
entry.grid(row = 3, column = 1, columnspan = wordLength)
enterButton = Button(play, text = "Enter Guess", width = 15, command = enterLetter).grid(row = 3, column = (wordLength+2))
label = Label(play, text = "Letter used: ").grid(row = 4, columnspan = 2)
label = Label(play, text = "").grid(row= 4, columnspan = 6)
def scores():
print("check scores")
def howToPlay():
print("how to play")
####### Main Menu
root = Tk()
root.geometry("500x300")
root.title("HANGMAN")
label = Label(root, text="HANGMAN", font = ("Arial",30)).grid(row = 0, columnspan = 3)
label = Label(root, text = "Option 1 :", font = ("Arial",12)).grid(row = 1, column = 1)
playButton = Button(root, text = "Play Game", width = 15, command = play).grid(row = 1, column = 2)
label = Label(root, text = "Option 2 :", font = ("Arial",12)).grid(row = 2, column = 1)
instructionsButton = Button(root, text = "How to play", width = 15, command = howToPlay).grid(row = 2, column = 2)
label = Label(root, text = "Option 3 :", font = ("Arial",12)).grid(row = 3, column = 1)
scoresButton = Button(root, text = "View Scores", width = 15, command = scores).grid(row = 3, column = 2)
label = Label(root, text = "Option 4 :", font = ("Arial",12)).grid(row = 4, column = 1)
exitButton = Button(root, text = "Exit", width = 15, command = exit).grid(row = 4, column = 2)
root.mainloop()
I hope this helps you.
The reason you cant update your label is because you haven't stored it in any variable. The grid, pack and place functions of the Label object and of all other widgets returns None, therefore when you call:
letter = Label(play, text = dashes, font = ("Arial",20)).grid(row = 2, column = i+1,padx = 10, pady =10)
your label cannot be accessed by variable letter. To fix this you should split it like so:
letter = Label(play, text = dashes, font = ("Arial",20))
letter.grid(row = 2, column = i+1,padx = 10, pady =10)
To update text of that label, you can call .configure(text = 'new text') on it.
# letter = Label(play, text = dashes, font = ("Arial",20)).grid(row = 2, column = i+1,padx = 10, pady =10) #
letter.configure(text = dashes)
As for your second issue, i think you confused while loop and if statement in the function enterLetter. It's called once per click and you only need to check one time if player has ran out of guesses.
if guesses != 0:
...
elif guesses == 0:
....
I am trying to start a count down timer to display on sense hat when I run the code it doesn't get the value typed into the entry box with no error returned just displays a 0 on the sense hat
from sense_hat import SenseHat
from tkinter import *
#set up
window = Tk()
window.title('timer')
window.geometry("300x100") #wxh
window.resizable(0,0)
#define and place labels
box1 = Label(window, text="time: ")
box1.grid(row = 1, column = 1,padx = 5, pady = 5)
#define entry box
answerVar = IntVar()
answertext = Entry(window,textvariable=answerVar)
string_answer = answertext.get()
int_answer = int(string_answer)
#display boxes
answertext.grid(row = 1, column = 2)
#define and place buttons
buttonstart = Button( window,text ='start:', command=lambda:int_answer)
sense = SenseHat()
G = [128,0,128] #led color
for i in range(int_answer,-1,-1): #create range start from input, stop at
#0 is -1
#decrease in steps is -1 Range is only a number
sense.show_letter(str(i),G)
exitbtn = Button( window,text ='Exit', command=exit)
#place buttons
buttonstart.grid(row = 4, column = 1,padx = 1, pady = 1)
exitbtn.grid(row = 4, column = 2,padx = 1, pady = 1)
#display window
window.mainloop()