Python Tkinter Multiple buttons are getting created on clicking on radio buttons - python

These are few lines from my actual code - I am aware this is not the best way of writing a code, but as I am new and getting familiarize with Tkinter (py2) consider this as my scratch work.
I am listing a question and multiple options. When the user selects an option, a SUBMIT button is created and when clicks on SUBMIT button it will accordingly change the color of Option to green or red. If green then another NEXT button will be available to clean and move to next question.
The issue that I am facing is if a user selects option A but then without clicking the SUBMIT button selects another option the submit button multiplies. I want to destroy the unwanted buttons or even do not want to create multiple SUBMIT buttons.
Please do help in achieving the same.
import Tkinter
from Tkinter import *
import yaml
import random
grey = "#808080"
offwhite = "#e3e3e3"
filepath = "chapter-2.yaml"
tk = Tkinter.Tk()
tk.title("iCodet Learnings")
tk.geometry("800x600")
x = ''
tk.config(background=offwhite)
tk.resizable(0,0)
q_count = 0
def yaml_loader(filepath):
with open (filepath, "r") as fileread:
data = yaml.load(fileread)
return data
def cleaner(hint):
global rbutton
global q_count
global quest_label
global radio1
global button_game
quest_label.destroy()
radio1.destroy()
# destroys the radio buttons
for b in rbutton:
b.destroy()
# destroys the SUBMIT button
button_game.destroy()
# go to ext question
if hint == 'next':
q_count += 1
game_loop()
# This is display the first element from the yaml i.e the question
def display_question(questions, qc):
global quest_label
q = questions.keys()[qc]
a = questions[q]
v = a.keys()
quest_label = Label(tk, text = q, font = ("Consolas", 16), width = 500, justify = "center", wraplength = 400)
quest_label.pack(pady = (50,0))
return v
# This is for selecting the radio buttons
def selected():
global radio_default, button_next,radio1, val
global x, data,q_count, vali, rbutton, select_val
x = radio_default.get()
select_val = rbutton[x]
if q_count <= len(data):
q = data.keys()[q_count]
a = data[q] #second dictionary
v = a.keys() #second dictionary keys
# True or False from Yaml
val = a[v[x]][0]
press_button(val)
else:
print ("Mid way")
# This will list all the options under question
def display_answer(ans):
global radio1, rbutton
global x, q_count
global radio_default
radio_default = IntVar()
rbutton = []
rad_select = []
val_count = 0
for i in ans:
radio1 = Radiobutton(tk, text = i, font = ("times", 14, "bold"), value = val_count, variable = radio_default, command = selected, background = 'NavajoWhite3')
rbutton.append(radio1)
val_count += 1
radio1.pack(pady = (30,0))
radio_default.set(-1)
# This displays the SUBMIT buuton
def press_button(val):
global button_game
# true
if val:
button_game = Button(tk, text = 'SUBMIT', font = ("default", 15, "bold"), bg='orange', fg = 'white', border=2, height = 2, width = 8, command = lambda: cleaner('next'))
button_game.pack(pady = (30,0))
# false
elif not val:
print "Do nothing"
button_game = Button(tk, text = 'SUBMIT', font = ("default", 15, "bold"), bg='orange', fg = 'white', border=2, height = 2, width = 8, command = lambda: cleaner('stay'))
button_game.pack(pady = (30,0))
return True
def game_loop():
global q_count
global x, data
global quest_label, button_game
action = True
data = yaml_loader(filepath)
if q_count <= len(data)-1:
l_ans = display_question(data, q_count)
display_answer(l_ans)
else:
txt_label = Label(tk, text = "CONGRATULATIONS ON COMPLETING CHAPTER", font = ("Comicsans", 24, "bold"), background = offwhite, wraplength = 700)
txt_label.pack(pady = (100,0))
button_end = Button(tk, text = 'THANK YOU !', font = ("default", 15, "bold"), bg='saddle brown', fg = 'white', border=2, height = 3, width = 10, command = tk.destroy)
button_end.pack(pady = (50,0))
game_loop()
tk.mainloop()
chapter-1.yaml
> "What’s the complete name of Sachin Tendulkar ?":
> "Sachin Ramya Tendulkar":
> - False
> "Sachin Ramesh Tendulkar":
> - True
> "Sachin Tendehar":
> - False
> " Sachin 10dulkar":
> - False
> "Hint":
> - "biscuit & cookies"

As things are, each time press_button() is run, a new Button object is generated, and placed in the button_game variable. This does not remove or hide the previous button, which still exists in the packed UI.
A simple solution that would save the machine some work is to initialize the button only once, earlier in the code, but omit placing/displaying/packing it until that block within press_button() is run.

I was able to achieve what I was looking for with the help of config.
I created the SUBMIT button once at the beginning and then instead of calling the whole function again and again; I just replaced press_button with button_game.config(command = lambda: right(chapter, num_ques, topic, val))
Now I should write this code using class in python.

Related

When I click on button entries won't display [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 1 year ago.
I'm going to ask the user to enter a number in an entry and press the 'enter' button, then show that number of entries below on the window, here is my code, the test class makes a list of entries and it works well alone but when I combine it with the first scenario and press the button nothing happens:
from tkinter import *
root = Tk()
root.geometry("600x600+50+50")
font = ('Verdana', 10)
def enter():
try:
class test:
def __init__(self, root):
self.variables = []
n = eval(txt_num.get())
for i in range(n):
self.variables.append(StringVar())
self.labels = []
self.entrys = []
mod = n % 4
c = 0
d = 0
e = 0
for ii in range(int(n/4)):
for jj in range(4):
char = c+(jj+1)
self.labels.append(Label(root , text = char))
self.labels[-1].grid(padx=0, pady=0, row=ii+d+1, column=jj)
self.entrys.append(Entry(root, textvariable =self.variables[c+(jj+1)]))
self.entrys[-1].grid(padx=0, pady=0, row=ii+d+2, column=jj)
d+=2
c+=4
e = ii+d+1
for kk in range(mod):
char = c+(kk+1)
self.labels.append(Label(root , text = char))
self.labels[-1].grid(padx=0, pady=0, row=int(n/4)+1+e+1, column=kk)
self.entrys.append(Entry(root, textvariable =self.variables[c+(kk)]))
self.entrys[-1].grid(padx=0, pady=0, row=int(n/4)+1+e+2, column=kk)
T = test(root)
except:
pass
lable_num = Label(font = font, text = 'Enter the number of your numbers:')
lable_num.grid(row = 0 , column = 0, columnspan = 3)
txt_num = Entry(width = 15, font = font, fg = 'gray' )
txt_num.grid(row = 0 , column = 4)
button_enter = Button(text = 'Enter' , font = font, command = enter())
button_enter.grid(row = 0 , column = 5)
root.mainloop()
The problem was calling the function command = enter() wrongly, since I have to pass the function itself as the command= option; it should be command = enter.

Module won't open properly / having trouble with opening file [duplicate]

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 2 years ago.
My code is not working out for some reason. But when I don't open my file in a function it will work. So I need help opening a python file in my menu file. Here is the code:
first file:
from tkinter import *
def Game():
mult = 1
clicks = 0
clickgame = Tk()
clickgame.geometry("500x500")
clickgame.title("Techno Clicker")
def buttonCommand():
global clicks
clicks += 1*(mult)
clickslabel.config(text=clicks)
def multiplyerX1():
global clicks
global mult
if clicks > 99:
clicks -= 100
mult += 1
clickslabel.config(text=clicks)
else:
lickslabel.config(text="Not Enough clicks")
def multiplyerX5():
global clicks
global mult
if clicks > 499:
clicks -= 500
mult += 5
clickslabel.config(text=clicks)
else:
clickslabel.config(text="Not Enough clicks")
def multiplyerX10():
global clicks
global mult
if clicks > 999:
clicks -= 1000
mult += 10
clickslabel.config(text=clicks)
else:
clickslabel.config(text="Not Enough clicks")
Background_btn = PhotoImage(file="/Users/PrivateInfo/Desktop/ClickImage-3.png")
clickslabel = Label(clickgame, text="0 Clicks")
clickButton = Button(clickgame, image=Background_btn, command=buttonCommand, borderwidth=0)
clickmultX1 = Button(clickgame, text="Buy Click Multiplyer x1 (Costs 100C)", command=multiplyerX1, padx = 10, pady = 5)
clickmultX5 = Button(clickgame, text="Buy Click Multiplyer x5 (Costs 500C)", command=multiplyerX5, padx = 10, pady = 5)
clickmultX10 = Button(clickgame, text="Buy Click Multiplyer x10 (Costs 10000C)", command=multiplyerX10, padx = 10, pady = 5)
clickslabel.pack()
clickButton.pack()
clickmultX1.pack()
clickmultX5.pack()
clickmultX10.pack()
clickgame.mainloop()
Second File:
from tkinter import *
import os
import sys
import ClickingGame
mult = 1
clicks = 0
menu = Tk()
q = 0
def firegame():
global q
ClickingGame.Game()
TitleLabel = Label(menu, text='Welcome To Techno Play')
GameLabel = Label(menu, text='Games:')
ClickingGameButton = Button(menu, text='Clicking Game', command=firegame)
TitleLabel.pack()
GameLabel.pack()
ClickingGameButton.pack()
Everytime I run this I get a error saying _tkinter.TclError: image "pyimage1 doesn't exist". But the first file runs fine if I run it alone. I am using python idle 3.8.2.
Try putting clickgame = Tk() at the beggining of the file that contains the mainloop() function
You have two Tk() created when your script is running, menu = Tk() and clickgame = Tk(), try chaging the one inside your first file to Toplevel() and delete clickgame.mainloop() since you change clickgame to a Toplevel of your main GUI.
In the first file:
def Game(menu):
mult = 1
clicks = 0
clickgame = Toplevel(menu)
...
...
In the second file just make menu a global variable, right before menu = Tk(), then send this root when you call your function ClickingGame like this ClickingGame.Game(menu) and at the end of the file start the mainloop:
...
...
...
TitleLabel.pack()
GameLabel.pack()
ClickingGameButton.pack()
main.mainloop()

reading and playing a word in the message window

I have a problem with the code and an error message appears in word -> word = "" word = str (Entry.get (input_text)) which obviously refers to printing full text which does not work the way I want it when I want it to work in a non-root window window but reading window.
This is the codes :
from tkinter import *
import sys
import tkinter as tk
from tkinter import messagebox
#---------
root = Tk()
root.title("Window")
#----------
#toiminnot root ikkunassa
functions = Label(root, text = "Select an action!")
functions.place(x = 70, y= 10)
#lue toimonto koodi alkaa
def read():
reading_window = Tk()
reading_window.title("Read function")
frame = Frame(reading_window)
frame.pack()
read_the_text = Label(reading_window, text = "Enter text in the box!")
read_the_text.place(x = 70, y = 10)
word = ""
word = str(Entry.get(input_text))
#frame johon kirjoitetaan
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
#lueikkuna koko ja sijoitus
reading_window.geometry("300x300+100+100")
#lue sana painike joka tuo viestin
print_button = tk.Button(reading_window, text = 'Show typed text', height = 1, width = 15) #, command = print1)
print_button.place(x=80, y=60)
text_a_tip = Label(reading_window, text ="The typed text is displayed in\nthe message window!")
text_a_tip.place(x = 50, y = 90)
def print1():
tk.messagebox.showinfo('Kirjoitetun tekstin tulostus viestiikkunaan', (Entry.get(input_text)))
def close():
reading_window.destroy()
read_close_button = tk.Button(reading_window, text = 'Close the reading function', height = 1, width = 20, command = close)
read_close_button.place(x = 60, y = 270)
read.mainloop()
#lue toiminto koodi loppuu
read_function = tk.Button(root, text='Read function', height = 1, width = 15, command = read)
read_function.place(x = 55,y = 35)
#ohjleman lopettamisen koodi alkaa
def quit_prog():
MsgBox = tk.messagebox.askquestion('Quit program', ' Are you sure you want to close the program?',icon = 'warning')
if MsgBox == 'yes':
root.destroy()
sys.exit(0)
else:
tk.messagebox.showinfo('Back','Now you are back!')
quit_programbutton = tk.Button(root, text='Close program', height = 1, width = 15, command = quit_prog)
quit_programbutton.place(x=50, y=220)
#ohjelman lopettamisen koodi loppuu tähän
#----------
#----------
root.geometry("250x250+20+60") #"450x450=leveysxkorkeus"+"20+40=vasenreuna+yläreuna"
root.mainloop()
source
I don't really see what is "word" variable for, but I assume that You need it. You can't use variable defined under line in which you use it.
word = ""
word = str(Entry.get(input_text)) # input_text is defined below, interpreter doesn't know what is it "input_text" yet.
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
It should be rather.
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
word = ""
word = str(Entry.get(input_text)) # now there is no error
It doesn't solve your problem, because I see that in function print1 you use again imput_text but it's defined in different function so it won't work.
def print1():
# input_text is local variable in read function.
tk.messagebox.showinfo('Kirjoitetun tekstin tulostus viestiikkunaan', (Entry.get(input_text)))
To solve your problem you can pass input_text as argument of print1, like in this working example.
def read():
reading_window = Tk()
reading_window.title("Read function")
frame = Frame(reading_window)
frame.pack()
read_the_text = Label(reading_window, text = "Enter text in the box!")
read_the_text.place(x = 70, y = 10)
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
word = ""
word = str(Entry.get(input_text))
reading_window.geometry("300x300+100+100")
# pass input_text to print1
print_button = tk.Button(reading_window, text = 'Show typed text', height = 1, width = 15, command = lambda: print1(input_text))
print_button.place(x=80, y=60)
text_a_tip = Label(reading_window, text ="The typed text is displayed in\nthe message window!")
text_a_tip.place(x = 50, y = 90)
def print1(input_text):
# print1 takes now one argument and has reference to input_text
tk.messagebox.showinfo('Kirjoitetun tekstin tulostus viestiikkunaan', (Entry.get(input_text)))
def close():
reading_window.destroy()
read_close_button = tk.Button(reading_window, text = 'Close the reading function', height = 1, width = 20, command = close)
read_close_button.place(x = 60, y = 270)
read.mainloop()
Consider also using different geometry manager than place, it is even written in effbot doc:
It is usually not a good idea to use place for ordinary window and dialog layouts; its simply to much work to get things working as they should. Use the pack or grid managers for such purposes.
Place Geometry Manager

Issue with adding images to button in tkinter application

I am helping with a small project where we want to add and take items away from a store. The code is below:
from tkinter import *
import tkinter
####################
# Variables
eggs = 0
milk = 0
butter = 0
lemon = 0
guiSize = "800x1280"
def newItemGUI():
main.withdraw()
def addEgg():
global eggs
eggs += 1
updateLabels()
def menu():
global eggs
update(eggs)
itemWindow.destroy()
main.deiconify()
def updateLabels():
eggLabel = Label(itemWindow, text = eggs)
eggLabel.grid(row = 3,column = 0)
itemWindow = Toplevel()
itemWindow.geometry(guiSize)
itemWindow.title("Add a new item")
itemWindow.configure(background = "#a1dbcd")
heading = Label(itemWindow, text="Add new items", font=("Arial",20),background = "#a1dbcd")
heading.grid(row=0, columnspan = 3)
egg = PhotoImage(file ="images/egg.gif")
eggButton = Button(itemWindow, image = egg, command = addEgg)
eggButton.grid(row = 2, column = 0,padx = 10, pady = 10)
eggLabel = Label(itemWindow, text = eggs).grid(row = 3,column = 0)
back = Button(itemWindow, text = "Main Menu", command = menu, width = 15)
back.grid(row = 4, column = 0, padx = 20, pady = 20)
def update(eggs):
items.delete("1.0",END)
items.insert(END,"Eggs \t:")
items.insert(END,eggs)
items.insert(END,"\n")
main=tkinter.Tk()
main.geometry(guiSize)
bgColour = "#DDA0DD"
main.configure(background = bgColour)
button1 = Button(main, text="Input new products", width = 20, height = 5, command = newItemGUI)
button1.grid(column = 1, row =2, padx = 20, pady = 20)
label2 = Label(main,text = "Items in the fridge :", font =("Arial,20"), background = bgColour)
label2.grid(row=4, columnspan = 2)
items = Text(main, width = 60, height = 10)
items.insert(END,"Eggs \t:")
items.insert(END,eggs)
items.insert(END,"\n")
items.grid(row=5, columnspan = 4)
main.mainloop()
When you click on the input new products button, this takes you to a new screen. On the screen should be a photo of an egg with a count underneath. For some reason the image of the egg is not showing and the button will not click.
If I change the eggButton from an image to:
eggButton = Button(itemWindow, text = "egg", command = addEgg)
this seems to allow me to click and the variable and it increases. Any idea as to what/where we have gone wrong? I know the path is correct as I can get the button to display a picture of an egg in a Label.
The problem is because the PhotoImage is being stored in a variable named egg which is local to the newItemGUI() function, so it (and associated image object) are being deleted when the function returns. This is a fairly common problem, so your question is likely a duplicate of another (and may get closed).
This PhotoImage documentation mentions avoiding this potential issue the way shown below in the Note near the end.
Regardless, to prevent that from happening, you can store the value somewhere else such as in an attribute of the Toplevel window. I would also recommend changing its name to something more descriptive like egg_image.
Here are changes to your code showing what how it could be done:
itemWindow.egg_image = PhotoImage(file="images/egg.gif")
eggButton = Button(itemWindow, image=itemWindow.egg_image, command = addEgg)

How do I make the program wait for an input using an Entry box in Python GUI?

This is the code for the function I'm using to start the main part of the program, however I want some sort of loop or something which creates ten questions, but waits for an input from the Entry box before moving onto the next question.
Any ideas?
def StartGame():
root = Tk()
root.title("Maths Quiz - Trigonometry and Pythagoras' Theorem | Start The Game")
root.geometry("640x480")
root.configure(background = "gray92")
global AnswerEntry
TotScore = 0
Count = 0
AnswerReply = None
WorkingArea = Text(root, width = 70, height = 10, wrap = WORD).place(x = 38, y = 100)
n = GetRandomNumber()
Angle,Opposite,Adjacent,Hypotenuse = Triangle()
Question,RealAnswer = QuestionLibrary(Opposite,Adjacent,Hypotenuse,Angle,n)
AskQuestion = Label(root, text = Question, wraplength = 560).place(x = 48, y = 300)
PauseButton = ttk.Button(root, text = "Pause").place(x = 380, y = 10)
HelpButton = ttk.Button(root, text = "Help", command = helpbutton_click).place(x = 460, y = 10)
QuitButton = ttk.Button(root, text = "Quit", command = root.destroy).place(x = 540, y = 10)
AnswerEntry = Entry(root)
AnswerEntry.place(x = 252, y = 375)
SubmitButton = ttk.Button(root, text = "Submit", command = submit_answer).place(x = 276, y = 400)
TotScore,AnswerReply = IsAnswerCorrect(Answer,RealAnswer)
ScoreLabel = ttk.Label(root, text = TotScore).place(x = 38, y = 10)
AnswerReplyLabel = ttk.Label(root, text = AnswerReply).place(x = 295, y = 440)
root.mainloop()
I want the loop to start after the AnswerReply = None
You don't want a loop. The only really important loop inside a GUI should be the mainloop(), handling signal and executing callbacks.
Example:
try:
import Tkinter as Tk
except ImportError:
import tkinter as Tk
class QAGame(Tk.Tk):
def __init__(self, questions, answers, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
self.title("Questions and answers game")
self._setup_gui()
self._questions = questions[:]
self._answers = answers
self._show_next_question()
def _setup_gui(self):
self._label_value = Tk.StringVar()
self._label = Tk.Label(textvariable=self._label_value)
self._label.pack()
self._entry_value = Tk.StringVar()
self._entry = Tk.Entry(textvariable=self._entry_value)
self._entry.pack()
self._button = Tk.Button(text="Next", command=self._move_next)
self._button.pack()
def _show_next_question(self):
q = self._questions.pop(0)
self._label_value.set(str(q))
def _move_next(self):
self._read_answer()
if len(self._questions) > 0:
self._show_next_question()
self._entry_value.set("")
else:
self.quit()
self.destroy()
def _read_answer(self):
answer = self._entry_value.get()
self._answers.append(answer)
def _button_classification_callback(self, args, class_idx):
self._classification_callback(args, self._classes[class_idx])
self.classify_next_plot()
if __name__ == "__main__":
questions = ["How old are you?",
"What is your name?"]
answers = []
root = QAGame(questions, answers)
root.mainloop()
for q,a in zip(questions, answers):
print "%s\n>>> %s" % (q, a)
We only have a Label, an Entry and a Button (I did not care about layout!, just pack()).
Attached to the button is a command (aka callback). When the button is pressed, the answer is read and the new question is assigned to the label.
Usage of this class is understandable from the example in the `if name == "main" block. Please note: the answers-list is filled in place, the questions-list is kept unchanged.
I don't know Tk, but is there no any signals of input text changed? There should be for sure. Just check if this signal occured and then move onto new question, because it means that someone typed something in input box.

Categories

Resources