I am trying to use a loop to create multiple drop down menus based on an entry in a entry text box after submit is pressed. I have never worked with tkinter before so I am not sure if I am doing this correctly. Any help would be appreciated. the code I have below is what I have but it causes the program to enter into some kind of infinite loop
from Tkinter import *
def callback():
numQues = E1.get()
i = 0
while i < numQues:
variable = StringVar(top)
variable.set("Short Answer") # default value
w = OptionMenu(top, variable, "Short Answer", "Multiple Choice", "Fill in the Blank",
"True of False", "Mathcing", "Ordering")
w.grid(row = i+1, column=0)
i = i+1
top = Tk()
top.geometry("600x600")
L1 = Label(top, text="How many questions will the quiz be?")
L1.grid(row=0, column=0)
E1 = Entry(top, bd = 5)
E1.grid(row=0, column=1)
MyButton1 = Button(top, text="Submit", width=10, command=callback)
MyButton1.grid(row=1, column=1)
top.mainloop()
Related
I'm trying to create a program in python tkinter which user first have to login, then the first page is closed and new one opens with some buttons inside.
button must change it's color and text on click but it does not do anything
from tkinter import *
def button_clicked(button):
Button(button).configure(bg="red", text="not Active")
def open_setting_page():
loginPage.destroy()
setting_page = Tk()
setting_page.title("Setting")
setting_page.geometry("400x300")
b2 = Button(setting_page, text="Active", height=5, width=10, bg="green",command=lambda:button_clicked(b2)).grid(row=0, column=0)
b3 = Button(setting_page, text="Active", height=5, width=10, bg="green",command=lambda:button_clicked(b3)).grid(row=0, column=1)
setting_page.mainloop()
#program starts here
loginPage = Tk()
loginPage.title("Security System")
loginPage.geometry("400x300")
Label(text="\n\n\n\n").pack()
l1 = Label(text="Enter Password:")
l1.pack()
password_entry = Entry()
password_entry.insert(0, "Enter Your Password...")
password_entry.pack()
b1 = Button(text="Login", command=open_setting_page)
b1.pack()
loginPage.mainloop()
I want the buttons color and text be changed on click but noting happens when I click it.
there are two problems in this code:
in open_setting_page() -> the variables b2 and b3 become None because Button(XXX).grid() returns None -> lets separate the button creation and the grid placement into 2 steps.
in button_clicked(button) function -> Button(button).configure is wrong. it should be button.configure(XX) to get hold of the button that you gave to the function.
Here is how these two functions could look like:
def button_clicked(button):
button.configure(bg="red", text="not Active")
def open_setting_page():
loginPage.destroy()
setting_page = Tk()
setting_page.title("Setting")
setting_page.geometry("400x300")
b2 = Button(setting_page, text="Active", height=5, width=10, bg="green", command=lambda: button_clicked(b2))
b3 = Button(setting_page, text="Active", height=5, width=10, bg="green", command=lambda: button_clicked(b3))
b2.grid(row=0, column=0)
b3.grid(row=0, column=1)
setting_page.mainloop()
I want to get an integer from an entry field and create new entry boxes below that. I have written a code to do that using a button. However, I want to make it happen automatically without a button as I entered the number, the rows update.
I saw one way to automate it is using the callback.
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update():
for i in range(1, n_para.get()+1):
entryX = Entry(root)
entryX.grid(row=i+1, column=0)
entryY = Entry(root)
entryY.grid(row=i+1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i+1, column=2)
button1 = Button(root, text="update", command=update)
button1.grid(row=1, column=0)
root.mainloop()
So, I changed the code to the below one using callback.
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update(*args):
try:
for i in range(1, n_para.get()+1):
entryX = Entry(root)
entryX.grid(row=i+1, column=0)
entryY = Entry(root)
entryY.grid(row=i+1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i+1, column=2)
except ValueError:
return
n_para.trace_add('write', update)
root.mainloop()
When I enter a number, it works and an error raises: _tkinter.TclError: expected floating-point number but got "" which I don't know what is that for.
Also, the code only works when I put numbers in ascending format. forexample, if I first enter 5, then change it to 3 it doesn't work.
You should use StringVar to associate with the Entry, as the entry contains text.
There is a method in StringVar to trace any changes: StringVar().trace(). Se example code below:
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = StringVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update(*args):
print('update', n_para.get())
n_para.trace('w', update) # Trace changes in n_para and run update if detected
root.mainloop()
The error you get is because the Entry contains text. You will have to convert it to int before you use it.
New example
You could do this in many ways, but here is one example:
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = StringVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
row_list = [] # List of all currently displayed entry rows
# and each row is a list of entrys within this list
def update(*args):
try:
para = int(n_para.get())
except ValueError:
return # Return without changes if ValueError occurs
rows = len(row_list)
diff = para - rows # Compare old number of rows with entry value
if diff == 0:
return # Return without changes
elif diff > 0: # Add rows of entrys and remember them
for row in range(rows+1, rows+diff+1):
entry_list = [] # Local list for entrys on this row
for col in range(3):
e = Entry(root)
e.grid(row=row, column=col)
entry_list.append(e) # Add entry to list
row_list.append(entry_list) # Add entry list to row
elif diff < 0: # Remove rows of entrys and froget them
for row in range(rows-1, rows-1+diff, -1):
for widget in row_list[row]:
widget.grid_forget()
widget.destroy()
del row_list[-1]
n_para.trace('w', update) # Trace changes in n_para
root.mainloop()
Is that what you had in mind?
I am trying to make a quiz in tkinter, and I have five questions. But, I want to wait for an answer to be inputted to the entry widget. I know I will probably need a button, but I don't know how I would go about doing that.
My code so far:
for i in range(5):
randChoose = random.choice(choose)
questionLabel = Label(top, text=full[randChoose]).grid(row=0, column=0)
answerLabel = Label(top, text="Answer:").grid(row=1, column=0)
answerEntry = Entry(top, borderwidth=5).grid(row=1,column=1)
if answerEntry.get() == aFull[randChoose]:
correctLabel = Label(top, text="Correct!",fg="green").grid(row=2,column=0)
score += 1
scoreLabel = Label(top, text=f"Your Score is {score}",fg="green").grid(row=2,column=1)
else:
wrongLabel = Label(top, text="Incorrect!",fg="red").grid(row=2,column=0)
scoreLabel = Label(top, text=f"Your Score is {score}",fg="red").grid(row=2,column=1)
choose.remove(randChoose)
First, add a button
button_pressed = StringVar()
this variable button_pressed will tell us if the button was pressed or not
(we set button_pressed to a StringVar() so .set() can change this variable, in the button's command)
button = Button(app, text="Enter", command=lambda: button_pressed.set("button pressed"))
when the button is pressed it will set the variable button_pressed, to "button pressed"
button.grid(row=1, column=1)
Then, wait until the button is pressed
button.wait_variable(button_pressed)
this code will wait until the varialbe button_pressed is changed (to anything)
Finally, check the entry
if answerEntry.get() == aFull[randChoose]: etc.
Final code should look something like this:
for i in range(5):
randChoose = random.choice(choose)
questionLabel = Label(app, text=full[randChoose]).grid(row=0, column=0)
answerLabel = Label(app, text="Answer:").grid(row=1, column=0)
answerEntry = Entry(app, borderwidth=5).grid(row=1,column=1)
button_pressed = StringVar()
button = Button(app, text="Enter", command=lambda: button_pressed.set("button pressed"))
button.grid(row=1, column=1)
button.wait_variable(button_pressed)
if answerEntry.get() == aFull[randChoose]:
correctLabel = Label(app, text="Correct!", fg="green").grid(row=2, column=0)
score += 1
scoreLabel = Label(app, text="Your Score is {score}", fg="green").grid(row=2, column=1)
else:
wrongLabel = Label(app, text="Incorrect!", fg="red").grid(row=2, column=0)
scoreLabel = Label(app, text="Your Score is {score}", fg="red").grid(row=2, column=1)
choose.remove(randChoose)
and you probobly want to destroy this button so on the next question it wont display 2 buttons
button.destroy()
Here are the labels and buttons I am using, I want the login button to check for passwords in code, then if correct go to the next screen.
from tkinter import *
root = Tk()
# Main window of Application
root.title("Please Login")
root.geometry("300x150")
root.config(background='lightblue', borderwidth=5)
# Creating Label Widget
myLabel1 = Label(root, text="Username :", background='lightblue')
myLabel2 = Label(root, text="Password :", background='lightblue')
# Entry fields
username_1 = Entry(root)
password_1 = Entry(root, show='*')
# Putting labels onto screen
myLabel1.grid(row=0, column=0)
myLabel2.grid(row=1, column=0)
# Entry field Locations
username_1.grid(row=0, column=1)
password_1.grid(row=1, column=1)
Here i have the command quit button but having a hard time with the command for login to go to next window.
# Creating Buttons
loginButton1 = Button(root, text="Login")
cancelButton3 = Button(root, text="Cancel", command=quit)
# Putting buttons onto screen
loginButton1.grid(row=6, column=1)
cancelButton3.grid(row=7, column=1)
# New window
root.mainloop()
That is a lot for one question... I'll try to give you an idea of how you can do this though. I usually do not create a whole new window; I simply change the already existing window.
from tkinter import *
root = Tk()
# Main window of Application
root.title("Please Login")
root.geometry("300x150")
root.config(background='lightblue', borderwidth=5)
# Possible Login
possible_users = {'user1': 'user1_pass', 'user2': 'user2_pass'} # dictionary of corresponding user name and passwords
# StringVars
the_user = StringVar() # used to retrieve input from entry
the_pass = StringVar()
# Creating Label Widget
myLabel1 = Label(root, text="Username :", background='lightblue')
myLabel2 = Label(root, text="Password :", background='lightblue')
bad_pass = Label(root, text="Incorrect Username or Password")
# Entry fields
username_1 = Entry(root, textvariable=the_user)
password_1 = Entry(root, show='*', textvariable=the_pass)
# Putting labels onto screen
myLabel1.grid(row=0, column=0)
myLabel2.grid(row=1, column=0)
# Entry field Locations
username_1.grid(row=0, column=1)
password_1.grid(row=1, column=1)
def login(user):
forget_login_window()
next_window(user)
def check_login():
requested_user = the_user.get()
try:
if possible_users[requested_user] == the_pass.get():
login(requested_user)
else:
bad_pass.grid(row=2, column=1)
except KeyError:
bad_pass.grid(row=2, column=1)
loginButton1 = Button(root, text="Login", command=check_login)
cancelButton3 = Button(root, text="Cancel", command=quit)
# Putting buttons onto screen
loginButton1.grid(row=6, column=1)
cancelButton3.grid(row=7, column=1)
# New window
def forget_login_window(): # forget all the grid items.
username_1.grid_forget()
password_1.grid_forget()
myLabel1.grid_forget()
myLabel2.grid_forget()
loginButton1.grid_forget()
cancelButton3.grid_forget()
bad_pass.grid_forget()
def next_window(my_user):
root.title(my_user) # desired changes here
# you will need to create your tkinter objects (buttons, labels etc) in global and pack / grid / place them here.
root.mainloop()
from Tkinter import *
import random
menu = Tk()
subpage = Tk()
entry_values = []
population_values = []
startUpPage = Tk()
def main_menu(window):
window.destroy()
global menu
menu = Tk()
frame1 = Frame(menu)
menu.resizable(width=FALSE, height=FALSE)
button0 = Button(menu, text="Set Generation Zero Values", command=sub_menu(menu))
button1 = Button(menu, text="Display Generation Zero Values")
button2 = Button(menu, text="Run Model")
button3 = Button(menu, text="Export Data")
button4 = Button(menu, text="Exit Program", command=menu.destroy)
button0.grid(row=0, column=0, sticky=W)
button1.grid(row=2, column=0, sticky=W)
button2.grid(row=3, column=0, sticky=W)
button3.grid(row=4, column=0, sticky=W)
button4.grid(row=5, column=0, sticky=W)
menu.mainloop()
def sub_menu(window):
global subpage
window.destroy()
subpage = Tk()
subpage.resizable(width=FALSE, height=FALSE)
#defining sub page items
button5 = Button(subpage, text="Save Generation Data",command = main_menu(subpage))
juveniles_label0 = Label(subpage,text="Juveniles")
adults_label1 = Label(subpage,text="Adults")
seniles_label2 = Label(subpage,text="Seniles")
population_label3 = Label(subpage,text="Popultation")
survival_rate_label4 = Label(subpage,text="Survival Rate (Between 0 and 1)")
entry0 = Entry(subpage)
entry1 = Entry(subpage)
entry2 = Entry(subpage)
entry3 = Entry(subpage)
entry4 = Entry(subpage)
entry5 = Entry(subpage)
button4.grid(row=1, column= 6, sticky=E)
juveniles_label0.grid(row=0, column=1)
adults_label1.grid(row=0, column=2)
seniles_label2.grid(row=0, column=3)
population_label3.grid(row=1, column=0)
survival_rate_label4.grid(row=2, column=0)
entry0.grid(row=1, column=1)
entry1.grid(row=1, column=2)
entry2.grid(row=1, column=3)
entry3.grid(row=2, column=1)
entry4.grid(row=2, column=2)
entry5.grid(row=2, column=3)
#add entry 6 7 8
subpage.mainloop()
main_menu(subpage)
main_menu(startUpPage)
I'm very new to coding and stackoverflow. I am trying to create a GUI that has a main page which will be opened first and a sub page which will be opened by clicking a button which will be stored in the main page. my issue is that I have no clue why it isn't opening my main page. my thought is that it is something to do with the .destroy() or something similar. any help would be much appreciated.
As a general rule, you should create exactly one instance of Tk for the life of your program. That is how Tkinter is designed to be used. You can break this rule when you understand the reasoning behind it, though there are very few good reasons to break the rule.
The simplest solution is to implement your main menu and your sub menu as frames, which you've already done. To switch between them you can simply destroy one and (re)create the other, or create them all ahead of time and then remove one and show the other.
For example, the following example shows how you would create them ahead of time and simply swap them out. The key is that each function needs to return the frame, which is saved in a dictionary. The dictionary is used to map symbolic names (eg: "main", "sub", etc) to the actual frames.
def main_menu(root):
menu = Frame(root)
button0 = Button(menu, text="Set Generation Zero Values",
command=lambda: switch_page("sub"))
...
return menu
def sub_menu(root):
subpage = Frame(root)
button5 = Button(subpage, text="Save Generation Data",
command = lambda: switch_page("main"))
...
return subpage
def switch_page(page_name):
slaves = root.pack_slaves()
if slaves:
# this assumes there is only one slave in the master
slaves[0].pack_forget()
pages[page_name].pack(fill="both", expand=True)
root = Tk()
pages = {
"main": main_menu(root),
"sub": sub_menu(root),
...
}
switch_page("main")
root.mainloop()
For a more complex object-oriented approach see Switch between two frames in tkinter
heres some code that does what you want.. make a window, destroy it when button is clicked and then make a new window...
from Tkinter import *
import random
def main_menu():
global root
root = Tk()
b = Button(root,text='our text button',command = next_page)
b.pack()
def next_page():
global root,parent
parent = Tk()
root.destroy()
new_b = Button(parent,text = 'new Button',command=print_something)
new_b.pack()
def print_something():
print('clicked')
main_menu()
root.mainloop()
parent.mainloop()
ps. ive done this in python3 so keep that in mind though it wouldnt be a problem in my opinion