How to disable multiple radiobuttons in Python? - python

This part of my program allows user to choose numbers from 1 to 5 and provide the sum of all numbers chosen. I want to disable the radio buttons when the sum reaches 30. How can I do that?
total_choices = [("1"),
("2"),
("3"),
("4"),
("5")]
var = tk.IntVar()
var.set(0)
sum = 0
def Calculator():
global sum
num = var.get()
sum = sum + num
if sum>30
# Grey out all the radio buttons
for val, choice in enumerate(total_choices):
tk.Radiobutton(root,
text=choice,
indicatoron = 0,
width = 10,
variable=var,
command=Calculator,
value=val).place(x=val*100,y=180)

You can disable radio buttons by looking them up from the children list of their parents:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def disable_multiple_radiobuttons():
global total
print(repr(sum_label['text']))
total += var.get()
sum_label['text'] = total
if total >= 30:
for child in root.winfo_children():
if child.winfo_class() == 'Radiobutton':
child['state'] = 'disabled'
root = tk.Tk()
var = tk.IntVar(value=1)
total = 0
sum_label = tk.Label(root, text=total)
sum_label.pack()
for i in range(1, 6):
tk.Radiobutton(root, text=i, variable=var, value=i,
command=disable_multiple_radiobuttons).pack()
tk.mainloop()
or you can put them in a collection type and simply disable them at ease:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def on_rb_press():
sum_label['text'] += var.get()
if sum_label['text'] >= 30:
for key in radiobuttons:
radiobuttons[key]['state'] = 'disabled'
root = tk.Tk()
sum_label = tk.Label(root, text=0)
sum_label.pack()
radiobuttons = dict()
var = tk.IntVar(value=1)
for i in range(1, 6):
radiobuttons[i] = tk.Radiobutton(root, text=i, variable=var,
value=i, command=on_rb_press)
radiobuttons[i].pack()
tk.mainloop()

I would store all the radio buttons in a list, then disable every buttons when you reach 30, as seen below :
total_choices = [("1"),
("2"),
("3"),
("4"),
("5")]
var = tk.IntVar()
var.set(0)
sum = 0
def Calculator():
global sum
global buttons
num = var.get()
sum = sum + num
if sum>30
# Grey out all the radio buttons
for b in buttons:
b.config(state=disabled)
global buttons
buttons = list()
for val, choice in enumerate(total_choices):
buttons.append(tk.Radiobutton(root,
text=choice,
indicatoron = 0,
width = 10,
variable=var,
command=Calculator,
value=val))
buttons[-1].place(x=val*100,y=180))

Related

Why exec function in python adds '.!' at the beginning of the text?

I am currently working on a hangman game using tkinter in python.
When I click a button of the letter and it is in the word that we are guessing it should show the letter. But when I click the button this problem is popping up:
This example is only with one button. People say that this problem is because of the mainloop(), but i have no idea how to fix it.
from tkinter import *
from tkinter import messagebox
from generate_word import word
#DEFAULT VALUES
score = 0
count = 0
win_count = 2
WINDOW_BG = '#e5404e'
WINDOW_SIZE = '1200x870+300+80'
FONT = ('Arial', 40)
from tkinter import *
from tkinter import messagebox
from generate_word import word
#DEFAULT VALUES
score = 0
count = 0
win_count = 2
WINDOW_BG = '#e5404e'
WINDOW_SIZE = '1200x870+300+80'
FONT = ('Arial', 40)
#this is an example with only one button
buttons = [['b1','a',80,740]]
#Creating window and configurating it
window = Tk()
window.geometry(WINDOW_SIZE)
window.title('Hangman')
window.config(bg = WINDOW_BG)
#generates all of the labels for the word
def gen_labels_word():
label = Label(window, text = " ", bg = WINDOW_BG, font = FONT)
label.pack( padx = 40,pady = (500,100),side = LEFT)
label1 = Label(window, text = word[0], bg = WINDOW_BG, font = FONT)
label1.pack( padx = 41,pady = (500,100),side = LEFT)
x = 21
for var in range(1,len(word)):
exec('label{}=Label(window,text="_",bg=WINDOW_BG,font=FONT)'.format(var))
exec('label{}.pack(padx = {}, pady = (500,100), side=LEFT)'.format(var,x))
x += 1
exec('label{} = Label(window, text = "{}", bg = WINDOW_BG, font = FONT)'.format(len(word),word[-1]))
exec('label{}.pack( padx = {},pady = (500,100),side = LEFT)'.format(len(word), x+1))
# ---------------------------------------------------------------------------------------------------------------------------------------------------
gen_labels_word()
#----------------------------------------------------------------------------------------------------------------------------------------------------
#letters icons(images)
#hangman (images)
hangman = ['h0','h1','h2','h3','h4','h5','h6']
for var in hangman:
exec(f'{var}=PhotoImage(file="{var}.png")')
han = [['label0','h0'],['label1','h1'],['label2','h2'],['label3','h3'],['label4','h4'],['label5','h5'],['label6','h6']]
for p1 in han:
exec('{}=Label(window, bg = WINDOW_BG ,image={})'.format(p1[0],p1[1]))
exec('label0.place(x = 620,y = 0)')
for var in letters:
exec(f'{var}=PhotoImage(file="{var}.png")')
for var in buttons:
exec(f'{var[0]}=Button(window,bd=0,command=lambda: game_brain("{var[0]}","{var[1]}"),bg = WINDOW_BG,font=FONT,image={var[1]})')
exec('{}.place(x={},y={})'.format(var[0],var[2],var[3]))
def game_brain(button, letter):
global count,win_count,score
exec('{}.destroy()'.format(button))
if letter in word:
for i in range(1,len(word)):
if word[i] == letter:
win_count += 1
exec(f'label{i}.config(text="{letter}")')
if win_count == len(word):
score += 1
messagebox.showinfo('GOOD JOB, YOU WON!\n GOODBYE!')
window.destroy()
else:
count += 1
exec('label{}.destroy()'.format(count-1))
exec('label{}.place(x={},y={})'.format(count,620,0))
if count == 6:
messagebox.showinfo('GAME OVER','YOU LOST!\nGOODBYE!')
window.destroy()
def EXIT():
answer = messagebox.askyesno('ALERT','Do you want to exit the game?')
if answer == True:
window.destroy()
e1 = PhotoImage(file = 'exit.png')
ex = Button(window,bd = 0,command = EXIT,bg = WINDOW_BG,font = FONT,image = e1)
ex.place(x=1050,y=20)
#-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
window.mainloop()
Why exec function in python adds '.!' at the beginning of the text?
The exec function isn't doing that. Tkinter by default names all of its widgets with a leading exclamation point. When you print out a widget, it has to be converted to a string. For tkinter widgets, the result of str(some_widget) is the widget's name.
You can see this quite easily without exec:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root)
print(label)
The above will print something like .!label. If you create a second label it will be .!label2, a third will be .!label3 and so on.
On an unrelated note, you shouldn't be using exec to create widgets. It makes the code very hard to understand and debug. If you want to create widgets in a loop, add them to a dictionary or list instead of dynamically creating variables with exec.
For example:
labels = {}
for var in range(1,len(word)):
label = Label(window,text="_",bg=WINDOW_BG,font=FONT)
label.pack(padx=500, pady=100)
labels[var] = label
With that, you can later reference the widgets as labels[1], labels[2], etc.
You should do the same thing with the images, or anything else that you create in a loop and want to keep track of.

How to assign a tkinter Scale value to a variable in Jupyter Notebook?

Here is the first cell of Jupyter Notebook which is a simple tkinter program.
Can I assign the scale value to the variable "a" and use it in the following cells of Jupyter Notebook?
Now the value of "a" I can get is always 0 in the following cells of Jupyter Notebook.
from tkinter import *
a = 0
def sel():
selection = "Value = " + str(var.get())
a = var.get()
label.config(text = selection)
root = Tk()
var = DoubleVar()
scale = Scale( root, variable = var )
scale.pack(anchor=CENTER)
button = Button(root, text="Get Scale Value", command=sel)
button.pack(anchor=CENTER)
label = Label(root)
label.pack()
root.mainloop()
#print(a)
a = var.get(): Here a is a local variable within the function.
a = 0
def sel():
a = 2
print("a from sel:", a)
sel()
print("a:", a)
Output:
a from sel: 2
a: 0
Alternatively, you can make a a global variable.
from tkinter import *
global scale_value
# set default
scale_value = 0
def save_scale_value(event):
global scale_value
# save the current value while the program is running
scale_value = event.widget.get()
print(f"Saved: {scale_value}")
def sel():
# reuse a variable in another function
global scale_value
print(f"global scale_value: {scale_value}")
selection = "Value = " + str(var.get())
label.config(text = selection)
root = Tk()
var = DoubleVar()
scale = Scale( root, variable = var )
scale.pack(anchor=CENTER)
button = Button(root, text="Get Scale Value", command=sel)
button.pack(anchor=CENTER)
label = Label(root)
label.pack()
scale.bind("<ButtonRelease>", save_scale_value)
root.mainloop()
# this will only print after the window is closed, when the root is destroyed
print(scale_value)
Also, you may not need an additional variable. You can use var after closing the window too.
from tkinter import *
def sel():
selection = "Value = " + str(var.get())
label.config(text = selection)
root = Tk()
var = DoubleVar()
scale = Scale(root, variable = var)
scale.pack(anchor=CENTER)
button = Button(root, text="Get Scale Value", command=sel)
button.pack(anchor=CENTER)
label = Label(root)
label.pack()
root.mainloop()
# this will only print after the window is closed, when the root is destroyed
print(var.get())
# Later, you can assign the scale value to a variable in a cell.
# name = var.get()

Tkinter - Retrieve text from button created in a loop

I'm learning to work with Python and Tkinter, so I'm doin this simple calculator app. My main problems come from the function calculator_tasks:
In the first condition, it should be deleting the 0, but it doesn't do it, why is that?
I'm trying to get text when I press the button, but it just prints '/', what's wrong in that?
Please see below the full code, so you might be able to help me.
from tkinter import *
import tkinter as tk
class calculator:
def __init__(self, master):
self.master = master
master.title("Calculator")
master.geometry("10x10")
grid_size = 4
a=0
while a <= grid_size:
master.grid_rowconfigure(a,weight=1, uniform='fred')
master.grid_columnconfigure(a,weight=1, uniform='fred')
a += 1
self.ini_frame = Frame(master,bg="light blue",highlightthickness=2, highlightbackground="black")
self.calc_title = Label(self.ini_frame, text ="Calculator",bg="light blue")
self.calculation_frame = Frame(master,bg="black")
self.calculation = IntVar(master,0)
self.calc_figure = Text(self.calculation_frame,fg="white",bg='black')
self.calc_figure.insert(END,0)
self.ini_frame.grid(columnspan=4,sticky=NSEW)
self.calculation_frame.grid(row=1,columnspan=4,sticky=NSEW)
self.calc_title.grid(padx=20)
self.calc_figure.grid(pady=20,padx=20)
master.update_idletasks()
def calculator_tasks():
if self.calc_figure.get("1.0",END) == 0:
self.calc_figure.delete(0,END)
self.calc_figure.insert(END,i)
else:
self.calc_figure.insert(END,i)
r = 2
c = 0
numbers = list(range(10))
numbers.remove(0)
self.calculator_btns=[ ]
for i in numbers:
if c == 2:
self.calculator_btns.append( Button(master, text = i, command = calculator_tasks))
self.calculator_btns[-1].grid(row = r, column = c, pady=20, padx=20,sticky=NSEW)
r += 1
c = 0
else:
self.calculator_btns.append( Button(master, text = i,command=calculator_tasks))
self.calculator_btns[-1].grid(row = r, column = c, pady=20, padx=20,sticky=NSEW)
c += 1
operators = ["+","*","/"]
self.operator_btns =[ ]
r=2
for i in operators:
self.operator_btns.append( Button(master, text = i))
self.operator_btns[-1].grid(row = r, column = 3, pady=20, padx=20,sticky=NSEW)
r += 1
root = Tk()
gui = calculator(root)
root.mainloop()
Here is a simple example:
According to your question: Retrieve text from button created in a loop
import tkinter as tk
root = tk.Tk()
####### Create Button ###############
def get_text(text):
print(text)
for i in range(10):
text = f'Hello I am BeginnerSQL74651 {i}'
button = tk.Button(root, text=text, command=lambda button_text=text: get_text(button_text))
button.grid()
root.mainloop()

My variable will not change in function

My variable is not changing and I know it's not changing because "1" is printed to the console.
I'm trying to make the label increment when i press the button. However when I press the button, the variable stays at 1.
What am I doing wrong?
I've looked online for an answer but I cannot really find one that I can understand.
num = 0
import tkinter
box = tkinter.Tk()
v = tkinter.StringVar()
labels = tkinter.Label(box, textvariable = v)
labels.pack()
def numberz(num,v):
num += 1
v.set(num)
print(num)
class MainWindow():
box.title("My Stupid Program")
buddon = tkinter.Button(box, text='PRESS ME', command = lambda:numberz(num,v))
buddon.pack()
box.mainloop()
num = 0
import tkinter
box = tkinter.Tk()
v = tkinter.StringVar()
labels = tkinter.Label(box, textvariable = v)
labels.pack()
def numberz(num,v):
num += 1
v.set(num)
print(num)
class MainWindow():
box.title("My Stupid Program")
buddon = tkinter.Button(box, text='PRESS ME', command = lambda:numberz(num,v))
buddon.pack()
box.mainloop()
You are changing the parameter num and not the global variable num
To change the global you need to specifically reference it. Notice how num is not passed in the lambda and now there is a global num in you function.
num = 0
import tkinter
box = tkinter.Tk()
v = tkinter.StringVar()
labels = tkinter.Label(box, textvariable = v)
labels.pack()
def numberz(v):
global num
num += 1
v.set(num)
print(num)
class MainWindow():
box.title("My Stupid Program")
buddon = tkinter.Button(box, text='PRESS ME', command = lambda:numberz(v))
buddon.pack()
box.mainloop()
In any case, using globals should be restricted to very specific cases and not be of general use.

How do I make time.sleep() work with tkinter?

I'm trying to show a sequence of numbers on the screen at regular intervals.
I'm new to python so it may be something obvious but I have tried .after and pygame.time.wait, but neither worked.
this is the code:
from tkinter import*
from random import *
import time
my_list = []
def Create_NUM(event):
x = 0
for x in range(level + 2):
button1.destroy()
num = randint(1, 100)
my_list.append(num)
Label(root, text=num,fg="red").pack()
one.pack()
time.sleep(2)
root=Tk()
num = 0
level = 1
bottomFrame = Frame(root)
bottomFrame.pack(side=BOTTOM)
button1 = Button(bottomFrame, text="Click to start game",fg="red")
button1.bind("<Button-1>", Create_NUM)
button1.pack()
root.mainloop()
I assume you want to show new number in place of old number, not below it.
import tkinter as tk
import random
def start():
# hide button
button.pack_forget()
# run `add_number` first time
add_number(level+2)
def add_number(x):
num = random.randint(1, 100)
my_list.append(num)
label['text'] = num
if x > 0:
# repeat after 2000ms (2s)
root.after(2000, add_number, x-1)
else:
# show button again after the end
button.pack()
# --- main ---
my_list = []
level = 1
root = tk.Tk()
label = tk.Label(root)
label.pack()
button = tk.Button(root, text="Click to start game", command=start)
button.pack()
root.mainloop()
Just use this simple command in your function root.update()

Categories