How to make a button open a new window? - python

I am making a simple GUI that starts with a main menu them the user can click a button to proceed to a new window which has a picture of a keyboard and the user can press key on their keyboard to play the paino. Right now I cant figure out how to make a button that when pressed closes the main menu (labeled mainMenu()) and open the game menu (playGame).
import tkinter
from tkinter import *
class mainMenu:
def _init_(self, master):
frame = Frame(master)
frame.pack()
self.quitButton = Button(frame, text = "Quit", command = frame.quit)
self.quitButton.pack(side = LEFT)
self.proceedButton = Button(frame, text = "Play", command = playGame)
self.proceedButton.pack(side = LEFT)
def playGame(self):
frame.quit
gameMenu()
def gameMenu(self):
root = Tk()
b = mainMenu(root)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomeFrame.pack(side = BOTTOM)
photo = PhotoImage(file = "piano.png")
label = Label(root, image = photo)
label.pack()
root.mainloop()

You'll have to forgive me for removing your class but I've never personally worked with classes in python before. However I seem to have you code working to some degree.
import tkinter
from tkinter import *
def playGame():
frame.quit
gameMenu()
def gameMenu():
b = mainMenu(root)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomFrame.pack(side = BOTTOM)
photo = PhotoImage(file = "piano.png")
label = Label(root, image = photo)
label.pack()
root=Tk()
frame = Frame(root)
frame.pack()
quitButton = Button(frame, text = "Quit", command = frame.quit)
quitButton.pack(side = LEFT)
proceedButton = Button(frame, text = "Play", command = playGame)
proceedButton.pack(side = LEFT)
root.mainloop()
The main problem you had was that you were using both root and master. When declaring the main window in tkinter you normally use either root = Tk() or master = Tk() either one is acceptable, personally I use master. This variable contains the main window that everything else is placed into. You also hadn't put Tk() into any variable, meaning that when you hit root.mainloop() there was nothing to enter the main loop, this was because you were trying to declare root = Tk() inside gameMenu, which wasn't getting called in your program.
If you want to open windows within tkinter it's probably easier to write something like this:
from tkinter import *
master = Tk() #Declaring of main window
def ProceedButtonCommand(mainframe, master): #Command to attach to proceed button
mainframe.destroy()
DrawSecondScreen(master) #This line is what lets the command tied to the button call up the second screen
def QuitButtonCommand(master):
master.destroy()
def DrawFirstScreen(master):
mainframe = Frame(master) #This is a way to semi-cheat when drawing new screens, destroying a frame below master frame clears everything from the screen without having to redraw the window, giving the illusion of one seamless transition
ProceedButton = Button(mainframe, text="Proceed", command=lambda: ProceedButtonCommand(mainframe, master)) #Lambda just allows you to pass variables with the command
QuitButton = Button(mainframe, text = "Quit", command=lambda: QuitButtonCommand(master))
mainframe.pack()
ProceedButton.pack()
QuitButton.pack()
def DrawSecondScreen(master):
mainframe = Frame(master)
Label1 = Label(mainframe, text="Temp")
mainframe.pack()
Label1.pack()
DrawFirstScreen(master)
master.mainloop() #The mainloop handles all the events that occur in a tkinter window, from button pressing to the commands that a button runs, very important
This little script just draws a screen with two buttons, one draws a new screen with the text "temp" on it and the other button closes the master window.
In the future it's probably a better idea to ask a friend who is experienced in programming to help with this kind of stuff. Get talking on some computing forums, I'm sure you'll find a group of sharing and fixing code quickly.

Related

Python: Tkinter open custom widget in new window

My aim is to generate a window with a button "NewWindow" on it. If I press the button, the program should open a new window. This window I stored in a class "NewWindow" to quickly reproduce it.
In this "NewWindow" I have another button. If I press it the label of basic window should be updated and the window "NewWindow" should be closed automatically.
Here is my code:
from tkinter import *
class NewWindow(Toplevel):
def __init__(self, master = None):
super().__init__(master = master)
self.title('NewWindow')
self.lb = Label(self, text='Hello')
self.lb.grid(column=0, row=0, columnspan=1)
self.bt1 = Button(self, text="apply Hello", command= self.bt_press)
self.bt1.grid(column=0, row=1)
def bt_press(self):
window.basic_lb.text = "Hello"
window = Tk()
def new_Editor():
a = NewWindow(window)
window.title("BasicWindow")
window.basic_lb = Label(window, text='None')
window.basic_lb.grid(column=0, row=0, columnspan=1)
window.basic_bt = Button(window, text="NewWindow", command=new_Editor)
window.basic_bt.grid(column=0, row=1)
window.mainloop()
Problems:
At start both windows NewWindow and BasicWindow are displayd. I only want to open BasicWindow and NewWindow should be opened after button basic_bt is clicked. How can I solve it? (already solved by commed below)
Why the label text in basic_lb did not get some update after pressing self.bt1?
How is it possible to close NewWindow with use of bt_press method?
You have a few typos/errors in your code that are casuing some of your problems. As #Tim said, when you pass a function to a command like command=function(), it will be called on runtime, not when the button is pressed. You need to pass the function handle to the command, command=function. You got around this by using a lambda function in your button command, but it is easier to just have command=self.bt_press
Answering your second question, window.basic_lb.text = "Hello" is not how you change the text in a tkinter Label, use <Label>.config(text="Hello"). You also should use self.master and define self.master = master in __init__ instead of just using window, because while you can access window due to it not being defined in local scope, it's better to explicitly define it.
You can close a window using window.destroy().
Your working code is now:
from tkinter import *
class NewWindow(Toplevel):
def __init__(self, master = None):
super().__init__(master = master)
self.title('NewWindow')
self.master = master
self.lb = Label(self, text='Hello')
self.lb.grid(column=0, row=0, columnspan=1)
self.bt1 = Button(self, text="apply Hello", command=self.bt_press)
self.bt1.grid(column=0, row=1)
def bt_press(self):
self.master.basic_lb.config(text="Hello")
self.destroy()
window = Tk()
def new_Editor():
a = NewWindow(window)
window.title("BasicWindow")
window.basic_lb = Label(window, text='None')
window.basic_lb.grid(column=0, row=0, columnspan=1)
window.basic_bt = Button(window, text="NewWindow", command=new_Editor)
window.basic_bt.grid(column=0, row=1)
window.mainloop()

How can I prevent my main window from running with a Toplevel window in python and Tkinter?

I am trying to stop the main window from running until a button has been pressed on a separate Toplevel window.
Example:
from tkinter import *
let_user_through = False
window = Tk()
def activate_main_window():
global let_user_through
let_user_through = True
frame = Toplevel()
b = Button(frame, text="Enter", command=activate_main_window).pack()
if let_user_through == True:
lbl = Label(window, text="Hello")
#bunch of code
#bunch of code
window.mainloop()
In this example, in the main window there is a label that reads: "Hello".
But I don't want people to be able to see it if they haven't pressed the button on the frame
Once the user has pressed the button, the frame will destroy itself and the main window will continue executing a bunch of code.
I'm a beginner to tkinter so i'm not sure if the answer is obvious or not. Thanks!
You can use frame.wait_window() to wait until frame is destroyed. Also you need to call frame.destroy() inside activate_main_window().
from tkinter import *
let_user_through = False
window = Tk()
def activate_main_window():
global let_user_through
let_user_through = True
frame.destroy() # need to destroy frame
# wait for root window becomes visible
# otherwise "frame" may be open behind root window
window.wait_visibility()
frame = Toplevel()
Button(frame, text="Enter", command=activate_main_window).pack()
frame.grab_set() # capture keyboard/mouse events
frame.wait_window() # wait for "frame" to be destroyed
if let_user_through:
Label(window, text="Hello").pack()
#bunch of code
#bunch of code
# should it be within the above for loop?
window.mainloop()
A small change to your code using window.withdraw and window.deiconify works for me. #acw1668 correctly pointed out an error in my original code, so here is the fix.
Your main window is invisible until user presses button.
import tkinter as tk
let_user_through = False
window = tk.Tk()
window.withdraw()
def activate_main_window():
global let_user_through
let_user_through = True
frame.destroy() # need to destroy frame
frame = tk.Toplevel()
tk.Button(frame, text="Enter", command=activate_main_window).pack()
frame.wait_window() # wait for "frame" to be destroyed
if let_user_through:
tk.Label(window, text="Hello").pack()
window.update()
window.deiconify()
#bunch of code
#bunch of code
window.mainloop()
I've created a class that removes the need for let_user_through and sets up code for any next steps.
import tkinter as tk
class invisible:
def __init__( self ):
self.window = tk.Tk()
self.window.withdraw() # make window invisible
self.frame = tk.Toplevel()
tk.Button(
self.frame, text = "Enter", command = self.activate_main_window ).pack( fill='both' )
self.frame.wait_window( ) # wait for "frame"
self.button = tk.Button( self.window, text = "Hello", command = self.remove_next )
self.button.pack( fill = 'both')
self.window.update()
self.window.deiconify() # make window visible
def activate_main_window( self ):
self.frame.destroy() # need to destroy frame
def remove_next( self ):
self.button.destroy()
tk.Label( self.window, text = "Bunch of codeA" ).pack( fill = 'both' )
tk.Label( self.window, text = "Bunch of codeB" ).pack( fill = 'both' )
tk.Label( self.window, text = "Bunch of codeC" ).pack( fill = 'both' )
# continue code initialization
if __name__ == '__main__':
make = invisible()
tk.mainloop()

How to display text on a new window Tkinter?

I've started learning Tkinter on Python few weeks ago and wanted to create a Guess Game. But unfortunately I ran into a problem, with this code the text for the rules ( in the function Rules; text='Here are the rules... ) doesn't appear on the window ( rule_window).
window = Tk()
window.title("Guessing Game")
welcome = Label(window,text="Welcome To The Guessing Game!",background="black",foreground="white")
welcome.grid(row=0,column=0,columnspan=3)
def Rules():
rule_window = Tk()
rule_window = rule_window.title("The Rules")
the_rules = Label(rule_window, text='Here are the rules...', foreground="black")
the_rules.grid(row=0,column=0,columnspan=3)
rule_window.mainloop()
rules = Button(window,text="Rules",command=Rules)
rules.grid(row=1,column=0,columnspan=1)
window.mainloop()
Does anyone know how to solve this problem?
In your code you reset whatever rule_window is to a string (in this line: rule_window = rule_window.title(...))
Try this:
from import tkinter *
window = Tk()
window.title("Guessing Game")
welcome = Label(window, text="Welcome To The Guessing Game!", background="black", foreground="white")
welcome.grid(row=0, column=0, columnspan=3)
def Rules():
rule_window = Toplevel(window)
rule_window.title("The Rules")
the_rules = Label(rule_window, text="Here are the rules...", foreground="black")
the_rules.grid(row=0, column=0, columnspan=3)
rules = Button(window, text="Rules", command=Rules)
rules.grid(row=1, column=0, columnspan=1)
window.mainloop()
When you want to have 2 windows that are responsive at the same time you can use tkinter.Toplevel().
In your code, you have initialized the new instances of the Tkinter frame so, instead of you can create a top-level Window. What TopLevel Window does, generally creates a popup window kind of thing in the application. You can also trigger the Tkinter button to open the new window.
from tkinter import *
from tkinter import ttk
#Create an instance of tkinter window
root= Tk()
root.geometry("600x450")
#Define a function
def open_new():
#Create a TopLevel window
new_win= Toplevel(root)
new_win.title("My New Window")
#Set the geometry
new_win.geometry("600x250")
Label(new_win, text="Hello There!",font=('Georgia 15 bold')).pack(pady=30)
#Create a Button in main Window
btn= ttk.Button(root, text="New Window",command=open_new)
btn.pack()
root.mainloop()

Tkinter opens second GUI first

I'm trying to build a login screen for practice and I'm having trouble with it. The general idea is that pressing the Login button closes the current window and opens another in a separate file. However, when I run the main file it opens the GUI window created in the second file. I'm not sure what would be causing it to do this.
import tkinter as tk
import loginEntry
HEIGHT = 200
WIDTH = 500
def login_function():
root.destroy()
loginEntry.NewScreen()
def register_function():
print("Register!")
root = tk.Tk()
root.title("Login Screen")
root.resizable(False, False)
canvas = tk.Canvas(root, height = HEIGHT, width = WIDTH)
canvas.pack()
frame = tk.Frame(root, bg='grey')
frame.place(relx=0.1, rely=0.25, relwidth=0.8, relheight=0.5)
login = tk.Button(frame, text="Login", command=login_function)
login.place(relx=0.05, rely=0.25, relwidth=0.425, relheight=0.5,)
register = tk.Button(frame, text="Register", command=register_function)
register.place(relx=0.525, rely=0.25, relwidth=0.425, relheight=0.5,)
introduction = tk.Label(root, text="Hello and welcome to DogNet, please login below.", font='bold 12')
introduction.place(relx=0.5, anchor='center', rely=0.1)
root.mainloop()
and then the second file
import tkinter as tk
def NewScreen():
root = tk.Tk()
canvas = tk.Canvas(root, bg='black')
canvas.pack()
root.mainloop()
NewScreen()
This is because, in your second file, you are calling the definition when it is imported.
import tkinter as tk
def NewScreen():
root = tk.Tk()
canvas = tk.Canvas(root, bg='black')
canvas.pack()
root.mainloop()
NewScreen() #< here you call the definition
This means that the series of events that happen in your program are as follows.
First file starts
Second file is imported
Definition "NewScreen" is called
tkinter mainloop starts which puts your program into a loop and stops the program from going on to any new lines until the loop is closed

Menu floats above menu button

So to begin with here is my code:
from Tkinter import *
def hello():
print "Hello"
root = Tk()
root.attributes('-fullscreen', 1)
icons = []
icons.append(PhotoImage(file="Icons\start.gif"))
icons.append(PhotoImage(file="Icons\quit.gif"))
icons.append(PhotoImage(file="Icons\save.gif"))
icons.append(PhotoImage(file="Icons\load.gif"))
icons.append(PhotoImage(file="Icons\Next.gif"))
screensizex = root.winfo_screenwidth()
screensizey = root.winfo_screenheight()
mainframe = Frame(root, height=(screensizey-(screensizey/20)), width=screensizex, bg="#50a9ad")
mainframe.grid(row=0)
menuframe = Frame(root, height=(screensizey/20), width=screensizex)
menuframe.grid(row=1, sticky="w")
startmenu = Menubutton ( menuframe, text="Start", image=icons[0], compound = LEFT, relief=RAISED,
direction="above")
startmenu.grid(row=0, column=0)
startmenu.place(relx=0.03, rely=0.5, anchor=CENTER)
startmenu.menu = Menu(startmenu, tearoff=0)
startmenu["menu"] = startmenu.menu
startmenu.configure(font=("Arial", 8, "bold"))
startmenu.menu.add_command(label="Next Day", image = icons[4], compound = LEFT, command=hello)
startmenu.menu.add_separator()
startmenu.menu.add_command(label="Save", image = icons[2], compound = LEFT, command=hello)
startmenu.menu.add_command(label="Load", image = icons[3], compound = LEFT, command=hello)
startmenu.menu.add_separator()
startmenu.menu.add_command(label="Quit", image = icons[1], compound = LEFT, command=root.quit)
startmenu.menu.configure(font=("Arial", 8))
root.mainloop()
And here is what I get:
GUI
As you can see the menu "Floats" above the menu button instead of just being above it.
I am not sure of what causes that but I can't figure out how to fix it. I am sure it's something pretty simple but I am a beginner with Python....
Thanks in advance for your help.
The problem seems to be with putting the menu button on the absolute bottom. Here is near minimal code, with menu button one 'line' up from bottom, that works with 3.6 (tk 8.6) on Win10
import tkinter as tk
root = tk.Tk()
root.attributes('-fullscreen', 1)
tk.Button(root, text='Close', command=root.destroy).pack()
mb = tk.Menubutton(root, text='Menu', direction='above')
#mb.pack(side='bottom')
tk.Label(root, text='Filler2').pack(side='bottom')
mb.pack(side='bottom')
tk.Label(root, text='Filler1').pack(side='bottom')
menu = tk.Menu(mb, tearoff=0)
menu.add_command(label='Popup', command=lambda:print('hello'))
mb['menu'] = menu
Popup is on top of Filler1. Move the bottom down to the bottom (by commenting and uncommenting pack lines) and popup is in same place, leaving a gap. I tried using a ttk Menubutton instead and got the same behavior. I then went to the official Tk docs and discovered the 'flush' direction which puts the box 'over' the button. For tk, this means means 'on top of so as to cover the button'. For ttk, it means 'flush against the top, leaving the button exposed', which is what you want. So the solution, as least on Windows with tk 8.6 is to create the button with
mb = ttk.Menubutton(root, text='Menu', direction='flush')

Categories