GUI - hiding buttons - python

from tkinter import *
import tkinter as tk
class dashboard(Frame):
def __init__(self, master):
super(dashboard, self).__init__(master)
self.grid()
self.buttons()
def buttons(self):
#student dashboard button
bttn1 = Button(self, text = "Student",
command=self.student, height = 2, width= 15)
bttn1.grid()
#teacher dashboard button
bttn2 = Button(self, text = "Teacher", height = 2, width= 15)
bttn2.grid()
#exit button
bttn3 = Button(self, text = "Exit",
command=root.destroy, height = 2, width= 15)
bttn3.grid()
def student(self):
#view highscores button
bttn1 = Button(self, text = "Highscores", height = 2, width= 15)
bttn1.grid()
#print score button
bttn2 = Button(self, text = "Print Score", height = 2, width= 15)
bttn2.grid()
#exit button
bttn3 = Button(self, text = "Main Menu",
command=root.destroy, height = 2, width= 15)
bttn3.grid()
#main
root = Tk()
root.title("Dashboard")
root.geometry("300x170")
app = dashboard(root)
root.mainloop()
Wondered if someone could help me basically, with this GUI I am creating I want to be able to access a new page on the same frame but the buttons from the main menu stay once I go to another page, does anyone know how I can hide/forget the buttons and go back to them at a later stage? Thanks.

Updated to use sub-Frames
You could do it using the universal grid_remove() method (here's some documentation). One way to use it would be to keep references to each of the Button widgets created so you can call this method on them as needed.
However that can be simplified slightly—even though it takes about the same amount of code—by putting all the Buttonss for each page into a separate sub-Frame and just showing or hiding it which will automatically propagate do to all the widgets it contains. This approach also provides a better foundation for the rest of your program.
I've implemented this by adding a main_button_frame attribute to your class, as well as one named student_button_frame to hold those you have on the student page (since you'll probably need it to hide them too).
One nice thing about grid_remove() is that if you later call grid() on the same widget, it will remember all the settings it (and its sub-widgets) had before it was removed, so you don't need to create and maintain a list of every single one of them yourself.
Also note I also made some general modifications to your code so it conforms to the PEP 8 - Style Guide for Python Code recommendations better. I highly recommend you read and start following it.
from tkinter import *
import tkinter as tk
class Dashboard(Frame):
def __init__(self, master):
super().__init__(master)
self.grid()
self.main_button_frame = None
self.student_button_frame = None
self.create_main_buttons()
def create_main_buttons(self):
if self.student_button_frame: # Exists?
self.student_button_frame.grid_remove() # Make it invisible.
if self.main_button_frame: # Exists?
self.main_button_frame.grid() # Just make it visible.
else: # Otherwise create it.
button_frame = self.main_button_frame = Frame(self)
button_frame.grid()
# Student Dashboard button
bttn1 = Button(button_frame, text="Student",
command=self.create_student_buttons, height=2,
width=15)
bttn1.grid()
# Teacher Dashboard button
bttn2 = Button(button_frame, text="Teacher", height=2, width=15)
bttn2.grid()
# Dashboard Exit button
bttn3 = Button(button_frame, text="Exit", command=root.destroy,
height=2, width=15)
bttn3.grid()
def create_student_buttons(self):
if self.main_button_frame: # Exists?
self.main_button_frame.grid_remove() # Make it invisible.
if self.student_button_frame: # Exists?
student_button_frame.grid() # Just make it visible.
else: # Otherwise create it.
button_frame = self.student_button_frame = Frame(self)
button_frame.grid()
# Highscores button
bttn1 = Button(button_frame, text="Highscores", height=2, width=15)
bttn1.grid()
# Print Score button
bttn2 = Button(button_frame, text="Print Score", height=2, width=15)
bttn2.grid()
# Student Exit button
bttn3 = Button(button_frame, text="Exit", command=root.destroy,
height=2, width=15)
bttn3.grid()
# main
root = Tk()
root.title("Dashboard")
root.geometry("300x170")
app = Dashboard(root)
root.mainloop()

Related

Checkbutton does not work on a nested tkinter window

I am trying to create a Tkinter window with a button which when clicked will provide with a new window. The new window has a checkbox and I want some actions to be done based on the checkbox value.
from tkinter import *
from tkinter import messagebox
def my_command():
def run():
pass
def cb_command():
f1 = fname1.get()
messagebox.showinfo("First Name", f1)
if cbVar.get() == 1:
messagebox.showinfo(cbVar.get())
my_button['state'] = 'active'
else:
messagebox.showinfo("Not found!")
my_button['state'] = 'disabled'
root = Tk()
root.geometry("200x200")
fname = Label(root, text="First Name")
fname.grid(row= 0, column = 0, sticky = "news", padx=5, pady=5)
fname1 = Entry(root, width = 10)
fname1.grid(row =0, column = 1, sticky = "news", padx=5, pady=5)
cbVar = IntVar()
cb1 = Checkbutton(root, text="Please check this", variable=cbVar, onvalue=1, offvalue=0, command=cb_command)
cb1.grid(row = 1, column = 0)
my_button = Button(root, text = "Run", bg = '#333333', fg='#ffffff', font = 'Helvetica', command = run, state='disable')
my_button.grid(row = 2, column = 0)
root.mainloop()
window = Tk()
window.geometry("200x200")
button1 = Button(window, text = "Run", command = my_command)
button1.pack()
window.mainloop()
I wrote this simple code which works fine with all other entry widgets. However, the checkbutton in the new window does not work. Can someone suggest any alternative?
Update:
Sorry, that I didn't clarify what actions to be done. I want the checkbox when clicked impact the state of the "Run" button in the toplevel window. The actual actions are based on the "Run" button.
Thank you Thingamabobs for suggesting a very simple solution. Just replaced one instance of Tk with Toplevel and it works.
from tkinter import *
def new_window():
second_window = Toplevel()
def checkbutton_checked():
# If you just want to take some action, once the checkbutton has been checked, you could do this here
# Alternatively you could also add a button to the toplevel and on click check the value of
# the checkbutton and perform actions based on that...
cb1.configure(text="Checkbutton checked")
cb1 = Checkbutton(second_window, text="Check here", command=checkbutton_checked)
cb1.pack()
window = Tk()
b1 = Button(window, text="Open new window", command=new_window)
b1.pack()
window.mainloop()
I hope this provides some help and you can solve your problem, if not let me know please.
Further details about the purpose of the checkbutton would also help me.

How do I use a tkinter entry as a parameter for a function

I would like a text box to ask for input in a tkinter window, then use that input as a parameter to call a function that draws a Sierpinski triangle. My buttons work but my input box does not. I keep trying to fix my code but it is not working, any help would be appreciated.
import tkinter as tk
from tkinter import *
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
root.title('Fractals') #titles the button box
top_frame = tk.Frame()
mid_frame = tk.Frame()
prompt_label = tk.Label(top_frame, \
text='Enter a number of iterations (more is better):')
iterations = tk.Entry(root,bd=1)
itr=iterations.get()
itr=int(itr)
button = tk.Button(frame,
text="QUIT",
fg="red",
command=quit)
button.pack(side=tk.LEFT)
sTriangle = tk.Button(frame,
text="Triangle",
command=lambda: sierpinski(fred, (-500,-500), (500,-500),
(0,500),itr))
sTriangle.pack(side=tk.LEFT)
fsquare = tk.Button(frame,
text="Square",
command=fractalsquare(fred,(-500,-500),(500,-500),
(500,500),(-500,500),itr))
fsquare.pack(side=tk.LEFT)
root.mainloop()
There are several issues:
1) Choose one way to import tkinter or confusion will result
2) You should provide a master for your Frames and then pack them. Pay attention on where the frames appear and what they contain.
3) It's usual to assign a textvariable to the Entry which will contain what you enter into it. The textvariable should be a tk.StringVar.
4) If a Button has a callback function, it must be defined before you create the button.
5) The variable fred is not defined.
Example of how you can write it:
import tkinter as tk
root = tk.Tk()
root.title('Fractals') #titles the button box
# Create the Label at the top
top_frame = tk.Frame(root) # Top Frame for
top_frame.pack()
prompt_label = tk.Label(top_frame,
text='Enter a number of iterations (more is better):')
prompt_label.pack()
# Create the Entry in the middle
mid_frame = tk.Frame(root)
mid_frame.pack()
itr_string = tk.StringVar()
iterations = tk.Entry(mid_frame,textvariable=itr_string)
iterations.pack()
fred=None # Was not defined...
# Create Buttons at the bottom
bot_frame = tk.Frame(root)
bot_frame.pack()
button = tk.Button(bot_frame, text="QUIT", fg="red", command=quit)
button.pack(side=tk.LEFT)
def sierpinski(*args): # sTriangle button callback function
itr = int(itr_string.get()) # How to get text from Entry
# if Entry does not contain an integer this will throw an exception
sTriangle = tk.Button(bot_frame, text="Triangle",
command=lambda: sierpinski(fred, (-500,-500), (500,-500),(0,500),itr_string))
sTriangle.pack(side=tk.LEFT)
def fractalsquare(*args): pass # fsquare button callback function
fsquare = tk.Button(bot_frame, text="Square", command=fractalsquare(fred,
(-500,-500),(500,-500),(500,500),(-500,500),itr_string))
fsquare.pack(side=tk.LEFT)
root.mainloop()
You should seriously study a basic tkinter tutorial. Try this one: An Introduction To Tkinter

How to position widgets using tkinter (entries,labels)

I want to create a GUI with Tkinter, such that you are at a grocery store, you enter the item, price, and quantity, and each item will appear on the top part of the screen.
I have a top and bottom frame, and when I place an entry it goes right in the middle of the bottom frame. I have tried justifying the position to the left, anchoring it, sticking it and doing whatever, but it's not moving.
This is my code.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
actual = MenuBoard(root)
root.mainloop()
-Use
bottomFrame.grid_propagate(False)
to expand the frame and
storeItemEntry.grid(pady=30)
Or whatever value you want for pady. You might have to give row and column numbers to grid() if you're going to place other widgets in bottomFrame.
You saw "a strange dark grey background" as mentioned in the comment because you gave bg = "grey" to bottomFrame. The background wasn't visible initially because the frame shrank to fit the Entry. You can change the color to what you want or remove it entirely.
The following should be close to what you're looking for:
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), textvariable=textInput, bd =4)
storeItemEntry.grid(pady=30)
actual = MenuBoard(root)
root.mainloop()
UPDATE:
Based on your comments, here is a rough implementation to work with.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
mainFrame.grid_propagate(False)
mainFrame.grid_columnconfigure(0, weight=1)
heading = " Store Item".ljust(45)[:45] + "Item Price" # Pad the text with white spaces
listHeading = Label(mainFrame, text=heading, anchor="w", font=("Courier New",14,"bold"))
listHeading.grid(row=1, column=0, pady=5, stick="we")
# Use Text widget so you can keep inserting items
self.listItems = Text(mainFrame, font=("Courier New",12))
self.listItems.grid(row=2, column=0, pady=5, stick="we")
self.listItems.config(state="disabled") # Prevents edits on the Text
welcomeLabel = Label(mainFrame, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0, stick="we")
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemLabel = Label(bottomFrame, text="Food Item: ")
storeItemLabel.grid(row=0, column=0)
self.storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.storeItemEntry.grid(row=0, column=1, pady=15)
priceLabel = Label(bottomFrame, text="Price: ")
priceLabel.grid(row=2, column=0)
self.priceEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.priceEntry.grid(row=2, column=1,)
btn = Button(bottomFrame, text="Add Item", command=self.add)
btn.grid(row=3, column=1, pady=15)
def add(self):
price = self.storeItemEntry.get() # Get item name from Entry
#Get price, format name and price
groceryItem = price.ljust(50)[:50] + "$%s" %(self.priceEntry.get())
self.listItems.config(state="normal") # Enable edits on the Text
self.listItems.insert("end", "\n "+groceryItem) # Edit Text
self.listItems.config(state="disabled") # Prevents edits on the Text
actual = MenuBoard(root)
root.mainloop()
A couple of things to note:
I removed some of your frames because they seemed redundant, you can add them back if needed.
Since you're working with a class, I added the self keyword to some of the attributes so I can use/call them later in other methods without errors. I left out the attributes that I do not need to call after creation.
StringVar/textvariable is not needed since you're updating the list with a button click.
There are lots of refinements I did not do (i.e. checking to see if a valid input is given before updating the list, ability to delete from the list, etc).
I used methods and features that you may or may not be aware of (.ljust(50)[:50], %s, etc)
I hope this helps :).

Trying to create and configure multiple buttons from the same function in tkinter

so i'm trying to create a code which when each button is clicked it will make that button fit a certain style but with changes to the name, however my current code will replace the button you click and them when you click on another it disables the last one you clicked permanently is there anyway to make it so that the buttons all use the same function but dont get disabled when you activate another button?
from tkinter import *
MainWindow = Tk()
def SquadInfoBttnFull():
global SquadFullBttn
SquadFullBttn = Toplevel(MainWindow)
SquadFullBttn.geometry("658x600")
# -- unit buttons -- #
for i in range(10):
Unit_Button = Button(SquadFullBttn, text="EMPTY", width=8, height=6)
Unit_Button.grid(row = 0, column = i)
Unit_Button.bind("<Button-1>", UnitFill)
def SquadInfoBttn():
InfoBttn = Button(MainWindow, wraplength=50, justify=LEFT, text="SquadInfo Here", width=100, command=SquadInfoBttnFull)
InfoBttn.grid(row=0, column=0, sticky=W)
def UnitInfoBttn():
UnitInfo = Toplevel(SquadFullBttn)
UnitInfo.geometry("300x200")
def UnitFill(event):
global photo
photo = PhotoImage(file="csmSingle.png")
btn = event.widget
grid_info = event.widget.grid_info()
btn = Button(SquadFullBttn, text="UNIT", image=photo, width=58, height=93, command=UnitInfoBttn, compound = TOP)
btn.grid(row=grid_info["row"], column=grid_info["column"], sticky=E)
SquadInfoBttn()
MainWindow.mainloop()
You are trying to make changes to the existing button and not create a new one. Also, you don't need to create a new instance of PhotoImage every time. The following code works for me:
from tkinter import *
MainWindow = Tk()
photo = PhotoImage(file="csmSingle.png")
def SquadInfoBttnFull():
global SquadFullBttn
SquadFullBttn = Toplevel(MainWindow)
SquadFullBttn.geometry("658x600")
# -- unit buttons -- #
for i in range(10):
Unit_Button = Button(SquadFullBttn, text="EMPTY", width=8, height=6)
Unit_Button.grid(row = 0, column = i)
Unit_Button.bind("<Button-1>", UnitFill)
def SquadInfoBttn():
InfoBttn = Button(MainWindow, wraplength=50, justify=LEFT, text="SquadInfo Here", width=100, command=SquadInfoBttnFull)
InfoBttn.grid(row=0, column=0, sticky=W)
def UnitInfoBttn():
UnitInfo = Toplevel(SquadFullBttn)
UnitInfo.geometry("300x200")
def UnitFill(event):
btn = event.widget
grid_info = event.widget.grid_info()
btn.config(text="UNIT", image=photo, width=58, height=93, command=UnitInfoBttn, compound = TOP)
btn.grid(row=grid_info["row"], column=grid_info["column"], sticky=E)
SquadInfoBttn()
MainWindow.mainloop()

Tkinter - How would I create buttons in a new window, which has been created by a function being called? Python 3

from tkinter import *
def begin():
root = Tk()
root.title("main window")
root.geometry("1920x1080")
return #How would a button be placed in this window made by this function?
root = Tk()
root.title("Start up page")
root.geometry("1920x1080")
BeginButton = Button(app, text = "Begin", command=begin, bg="green")
BeginButton.grid(column = 2, row = 2, sticky = W)
BeginButton.config(height = 10, width = 30 )
root.mainloop()
How would I create new buttons in the new window, if the new window is being made by, in this case a function known as "begin".
Any response would be much appreciated!
I believe what you want to do is to modify the root window rather than create a new one. Here is a minimal working example:
from tkinter import *
root = Tk()
class App:
def __init__(self):
root.title("Start up page")
root.geometry("1920x1080")
self.beginB = Button(root, text="Begin", command=self.begin,
bg="green", height=10, width=30)
self.beginB.grid(sticky = W)
def begin(self):
root.title("main window")
self.beginB.destroy()
del self.beginB
self.goB = Button(root, text='Go on', command=self.go_on,
bg='red')
self.goB.grid(sticky=E)
def go_on(self):
self.label = Label(root, text="you have continued")
self.label.grid(row=1, sticky=S)
App()
root.mainloop()
An advantage of defining a class is that you can make forward references. In your code, you had to define the begin function before you create the begin button. With a class, I could put it after init, which to me is a more natural order. It is ofter the case that the initialization code calls or binds more than one function.

Categories

Resources