I wanted to create a multiple windows that can go back at the first window and can open another window.
I created a button that can transfer me to the first window but when I click the Go back Button, The Go Back Button also appear at the first window
from tkinter import *
class testing:
def __init__(self,root):
self.btn_Init(root)
def btn_Init(self,root):
self.btn = Button(root, text="Go back Login",command = lambda:window(root))
self.btn.pack()
class window:
def __init__(self,root):
root.config(bg='orange')
root.geometry("500x500")
self.btn_view = Button(root,text="View", bg='green',width=13,height=4,command =lambda:self.view_onclick(root))
self.btn_view.place(x=130,y=220)
def view_onclick(self,root):
self.top = testing(Toplevel(root))
root.withdraw()
root = Tk()
window(root)
root.mainloop()
change
class testing:
def __init__(self,root):
self.btn_Init(root)
def btn_Init(self,root):
self.btn = Button(root, text="Go back Login",command = lambda:window(root))
self.btn.pack()
to
class testing:
def __init__(self,root):
self.btn_Init(root)
def btn_Init(self,root):
self.btn = Button(root, text="Go back Login",command = lambda:window(root) and self.btn.pack_forget())
self.btn.pack()
But I think your code is very odd.
Why don't you just use .deiconify() and .withdraw()?You make it more complicated。
Related
How can I make a command to open second window and close the main window in python.
The code can open the next window but it cant close the main window..
This is the code:
from tkinter import *
def main():
root = Tk()
app = first(root)
class first:
def __init__(self, master):
self.master = master
self.master.title("First")
tit = Label(self.master, text="Im the first page", font=20)
tit.place(relx=0.5, rely=0.4, anchor=CENTER)
sec = Button(self.master, text="Second", width=20, height=10,
bg="black", fg="white", command=self.second_open)
sec.place(relx=0.5, rely=0.5, anchor=CENTER)
def second_open(self):
self.secondwindow = Toplevel(self.master)
self.app = second(self.secondwindow)
class second:
def __init__(self, master):
self.master = master
self.master.title("Second")
tit = Label(self.master, text="Im the second page", font=20)
tit.place(relx=0.5, rely=0.4, anchor=CENTER)
if __name__ == "__main__":
main()
mainloop()
tkinter is designed for you to create one root window, and keep that window until the program ends. That makes it difficult to do what you ask.
A better solution in many cases is to just keep and reconfigure the main window instead of destroying it and creating a new window.
Here's an example based on the code in the question:
def second_open(self):
for child in self.master.winfo_children():
child.destroy()
self.secondwindow = second(self.master)
I'm currently using tkinter to create a GUI for my program. If I open the golf quiz window and open the help window, then close the golf quiz window and re-open it, I am able to click the help window button and open another instance of the help button. How do I set the Help button to be disabled while the Help window is open?
from tkinter import *
from functools import partial
class Welcome_Screen:
def __init__(self, parent):
self.welcome_screen_frame = Frame(width=200, height=200, pady=10)
self.welcome_screen_frame.grid()
self.quiz_welcome_screen_label = Label(self.welcome_screen_frame, text = "quiz game", font="Arial 20 bold", padx=10)
self.quiz_welcome_screen_label.grid(row=0)
self.welcome_screen_buttons_frame = Frame(self.welcome_screen_frame)
self.welcome_screen_buttons_frame.grid(row=2)
self.golf_quiz_welcome_screen_button = Button(self.welcome_screen_buttons_frame, text="Golf Quiz", font="Arial 10 bold", command=self.golf_quiz_game, padx=10, pady=10)
self.golf_quiz_welcome_screen_button.grid(row=2, column=0, padx=5)
def golf_quiz_game(self):
get_golf_quiz_game = golf_quiz_game(self)
class golf_quiz_game:
def __init__(self, partner):
partner.golf_quiz_welcome_screen_button.config(DISABLED)
self.golf_quiz_box = Toplevel()
self.golf_quiz_box.protocol('WM_DELETE_WINDOW', partial(self.close_golf_quiz_game, partner))
self.golf_quiz_frame = Frame(self.golf_quiz_box)
self.golf_quiz_frame.grid()
self.golf_quiz_heading = Label(self.golf_quiz_frame, text="Golf Quiz game",
font="arial 18 bold", padx=10, pady=10)
self.golf_quiz_heading.grid(row=0)
self.golf_quiz_history_help_dismiss_buttons_frame = Frame(self.golf_quiz_frame)
self.golf_quiz_history_help_dismiss_buttons_frame.grid(row=6, pady=10)
self.help_button = Button(self.golf_quiz_history_help_dismiss_buttons_frame, text="Help", font="Arial 10 bold",command=self.Help, padx=10, pady=10)
self.help_button.grid(row=6, column=1, padx=5)
def close_golf_quiz_game(self, partner):
partner.golf_quiz_welcome_screen_button.config(state=NORMAL)
self.golf_quiz_box.destroy()
def Help(self):
get_help = Help(self)
class Help:
def __init__(self, partner):
partner.help_button.config(state=DISABLED)
self.help_box = Toplevel()
self.help_box.protocol('WM_DELETE_WINDOW', partial(self.close_Help, partner))
self.help_frame = Frame(self.help_box)
self.help_frame.grid()
self.help_heading = Label(self.help_frame, text="Help", font="arial 18 bold")
self.help_heading.grid(row=0)
self.help_text = Label(self.help_frame, text="Test",
width=60, wrap=400)
self.help_text.grid(row=1)
self.help_button = Button(self.help_frame, text="Dismiss", width=10, font="Arial 10 bold", command=partial(self.close_Help, partner), padx=10, pady=10)
self.help_button.grid(row=2, pady=10)
def close_Help(self, partner):
if partner.help_button.winfo_exists():
partner.help_button.config(state=NORMAL)
self.help_box.destroy()
# main routine
if __name__ == "__main__":
root = Tk()
root.title("quiz game")
something = Welcome_Screen(root)
root.mainloop()
Here is how you can do that (this is also the size (linewise (approx.)) of the minimal reproducible example which you should have provided):
from tkinter import Tk, Toplevel, Button
def close_top(top):
btn.config(state='normal')
top.destroy()
def open_help():
btn.config(state='disabled')
top = Toplevel(root)
top.protocol('WM_DELETE_WINDOW', lambda: close_top(top))
top.focus_force()
# put the rest of help stuff here
root = Tk()
btn = Button(root, text='Help', command=open_help)
btn.pack()
root.mainloop()
Class based approach:
from tkinter import Tk, Toplevel, Button
# this would be the window from where you open the help window
class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
self.btn = Button(self, text='Help',
command=lambda: self.open_help(self.btn))
self.btn.pack()
def open_help(self, btn):
HelpWindow(self, btn)
# this would be the help window
class HelpWindow(Toplevel):
def __init__(self, master, button):
Toplevel.__init__(self, master)
self.button = button
self.button.config(state='disabled')
self.focus_force()
self.protocol('WM_DELETE_WINDOW', self.close)
def close(self):
self.button.config(state='normal')
self.destroy()
MainWindow().mainloop()
Few things:
First of you can simply inherit from container and window classes that way you don't have to separately create them in the class and you can easily reference them in the class using just self
.focus_force() does what it says, it forces focus on the widget
Important (suggestions)
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.
I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case, class names in CapitalCase. Don't have space around = if it is used as a part of keyword argument (func(arg='value')) but use if it is used for assigning a value (variable = 'some value'). Have two blank lines around function and class declarations.
You need to make use of class variables inside golf_quiz_game in order to have only one instance of Help window:
class golf_quiz_game:
# class variables
_help_button = None # reference to instance "Help" button
_help_win = None # reference to instance "Help" window
def __init__(self, partner):
...
# set button state based on whether "Help" window is open or not
self.help_button.config(state="normal" if self.__class__._help_win is None else "disabled")
# update class reference of "Help" button
self.__class__._help_button = self.help_button
def close_golf_quiz_game(self, partner):
partner.golf_quiz_welcome_screen_button.config(state=NORMAL)
self.golf_quiz_box.destroy()
# update class reference of "Help" button
self.__class__._help_button = None
def Help(self):
if self.__class__._help_win is None:
# no "Help" window is open, create one
self.__class__._help_win = Help(self)
def help_closed(self):
if self.__class__._help_button:
# enable the "Help" button
self.__class__._help_button.config(state="normal")
# update "Help" window status
self.__class__._help_win = None
class Help:
...
def close_Help(self, partner):
self.help_box.destroy()
# notify partner that "Help" window is closed
partner.help_closed()
Sorry for any stupidity or ignorance on my part but I am new to Python, and coding in general. I have been trying to get a UI working for a game I'm going to make as a way of teaching myself python I have a main window and a few button widgets in this.
The Play game button opens a second window (for the game itself) and hides the root window with the .withdraw method. This works perfectly. Inside the game window I have another button which I would like to destroy the game window and bring the user back to the root menu window that I have withdrawn. This seems to work except every time I call it,it creates an new, duplicate set of widgets in the window so I end up with multiple sets.
I'll post my full code at the bottom but here are what I believe are the relevant parts.
A tkinter Button calls this inside the parent class (the main window). This works fine.
def playGame(self): #Start the main game window
self.master.withdraw()
gameWindow()
I'm using the bellow method inside of the child class to destroy the game window and then call a method in the parent class to bring back the earlier withdrawn window
def exitMenu(self):
self.g.destroy()
UI(root).showMenu()
this works except it duplicates the widgets each time resulting in this being shown:
screen capture of result
Bellow is all my code, thank you so much for any help.
import tkinter as tk
import PIL
from Config import *
root = tk.Tk()
class UI(): #Main Menu
def __init__(self, master):
#Create Main Menu Window
self.master = master
self.master.title("Monopoly")
self.master.wm_iconbitmap('icons\Monopoly-Icon.ico')
self.master.geometry((resolution))
#Menu Buttons
self.label = tk.Label(master, text= 'Welcome to Monopoly! PLACEHOLDER')
self.playButton = tk.Button(master, text= 'Play Game', command= self.playGame)
self.settingsButton = tk.Button(master, text= 'settings', command= self.settings)
self.exitButton = tk.Button(master, text= 'Exit', command= self.exitGame)
self.label.grid(columnspan=2)
self.playButton.grid(column=0)
self.settingsButton.grid(column=0)
self.exitButton.grid(column=0)
def settings(self): #Opens Settings Window
s = tk.Toplevel()
s.title('Settings')
s.wm_iconbitmap('icons\Monopoly-Icon.ico')
s.geometry((resolution))
self.master.withdraw()
resLabel = tk.Label(s, text= 'Resolution')
resOption = tk.OptionMenu(s, resolution, *resList)
resLabel.grid(column=0,row=0)
resOption.grid(column=0, row=4)
def showMenu(self): #Bring back menu windwow
self.master.deiconify()
def exitGame(self): #Exit Game Method
root.destroy()
def playGame(self): #Start the main game window
self.master.withdraw()
gameWindow()
class gameWindow(UI):
def __init__(self):
self.g = tk.Toplevel()
self.g.title('Monopoly')
self.g.wm_iconbitmap('icons\Monopoly-Icon.ico')
self.g.geometry((resolution))
self.menuButton = tk.Button(self.g, text= 'Main Menu', command= self.exitMenu)
self.menuButton.grid(column=0,row=0)
def exitMenu(self):
self.g.destroy()
UI(root).showMenu()
mainMenu = UI(root)
root.mainloop()
You should pass the parent class, UI, to the child class gameWindow, then you can use the showMenu() method of the parent class in the child class.
Code for showing the main window from the child window will be:
self.mainUI.showMenu() instead of UI(root).showMenu()
Child class becomes:
class gameWindow(UI):
def __init__(self, mainUI): # Make the main window a parameter/attribute
self.mainUI = mainUI # Make the main window a parameter/attribute
self.g = tk.Toplevel()
self.g.title('Monopoly')
self.g.wm_iconbitmap('icons\Monopoly-Icon.ico')
self.g.geometry((resolution))
self.menuButton = tk.Button(self.g, text= 'Main Menu', command= self.exitMenu)
self.menuButton.grid(column=0,row=0)
def exitMenu(self):
self.g.destroy()
self.mainUI.showMenu()
gameWindow now requires one argument, so you pass it the main UI as self
def playGame(self): #Start the main game window
self.master.withdraw()
gameWindow(self)
You can read more about hiding/showing window here
Here is the full code:
import tkinter as tk
import PIL
from Config import *
root = tk.Tk()
class UI(): #Main Menu
def __init__(self, master):
#Create Main Menu Window
self.master = master
self.master.title("Monopoly")
self.master.wm_iconbitmap('icons\Monopoly-Icon.ico')
self.master.geometry((resolution))
#Menu Buttons
self.label = tk.Label(master, text= 'Welcome to Monopoly! PLACEHOLDER')
self.playButton = tk.Button(master, text= 'Play Game', command= self.playGame)
self.settingsButton = tk.Button(master, text= 'settings', command= self.settings)
self.exitButton = tk.Button(master, text= 'Exit', command= self.exitGame)
self.label.grid(columnspan=2)
self.playButton.grid(column=0)
self.settingsButton.grid(column=0)
self.exitButton.grid(column=0)
def settings(self): #Opens Settings Window
s = tk.Toplevel()
s.title('Settings')
s.wm_iconbitmap('icons\Monopoly-Icon.ico')
s.geometry((resolution))
self.master.withdraw()
resLabel = tk.Label(s, text= 'Resolution')
resOption = tk.OptionMenu(s, resolution, *resList)
resLabel.grid(column=0,row=0)
resOption.grid(column=0, row=4)
def showMenu(self): #Bring back menu windwow
self.master.deiconify()
def exitGame(self): #Exit Game Method
root.destroy()
def playGame(self): #Start the main game window
self.master.withdraw()
gameWindow(self)
class gameWindow(UI):
def __init__(self, mainUI): # Make the main window a parameter/attribute
self.mainUI = mainUI # Make the main window a parameter/attribute
self.g = tk.Toplevel()
self.g.title('Monopoly')
self.g.wm_iconbitmap('icons\Monopoly-Icon.ico')
self.g.geometry((resolution))
self.menuButton = tk.Button(self.g, text= 'Main Menu', command= self.exitMenu)
self.menuButton.grid(column=0,row=0)
def exitMenu(self):
self.g.destroy()
self.mainUI.showMenu()
mainMenu = UI(root)
root.mainloop()
I am creating 2 window in my program and i am using two class, since the code is complex, i separate it in 2 different python file. After i imported the second window file, how can i make sure it open without having this error which show in this picture
The original result should look like this after the new window button clicked:
Coding for Main Window:
from tkinter import *
import classGUIProgram
class Window(Tk):
def __init__(self, parent):
Tk.__init__(self, parent)
self.parent = parent
self.initialize()
def initialize(self):
self.geometry("600x400+30+30")
self.wButton = Button(self, text='newWindow', command = self.OnButtonClick)
self.wButton.pack()
def OnButtonClick(classGUIProgram):
classGUIProgram.top = Toplevel()
master = Tk()
b = classGUIProgram.HappyButton(master)
master.mainloop()
if __name__ == "__main__":
window = Window(None)
window.title("title")
window.mainloop()
Coding for Second Window:
from tkinter import *
class HappyButton:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.printButton = Button(frame, text="Print message", command=self.printMessage)
self.printButton.pack(side=LEFT)
self.quitButton = Button(frame, text="Quit", command= quit)
self.quitButton.pack(side=LEFT)
self.downloadHistoryCB=Checkbutton(frame, text="Download History")
self.downloadHistoryCB.pack(side=LEFT)
def printMessage(self):
print("Wow this actually worked!")
master = Tk()
b = HappyButton(master)
master.mainloop()
You're creating extra Tk windows. Here is an example of using Toplevel widgets and another file.
mainWindow.py
import tkinter as tk
import secondWindow as sW
class MainWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("Main Window")
self.geometry("600x400+30+30")
tk.Button(self, text = "New Window", command = self.new_window).pack()
tk.Button(self, text = "Close Window", command = self.close).pack()
self._second_window = None
def new_window(self):
# This prevents multiple clicks opening multiple windows
if self._second_window is not None:
return
self._second_window = sW.SubWindow(self)
def close(self):
# Destory the 2nd window and reset the value to None
if self._second_window is not None:
self._second_window.destroy()
self._second_window = None
if __name__ == '__main__':
window = MainWindow()
window.mainloop()
secondWindow.py
import tkinter as tk
class SubWindow(tk.Toplevel):
def __init__(self, master):
super().__init__(master)
self.title("Sub Window")
self.geometry("400x300+30+30")
# Change what happens when you click the X button
# This is done so changes also reflect in the main window class
self.protocol('WM_DELETE_WINDOW', master.close)
tk.Button(self, text = "Print", command = self.printMessage).pack()
def printMessage(self):
print("Wow this actually worked!")
When using another file be sure to not have any global code you don't want running. Your classes don't have to inherit from Tk and Toplevel, this is just an example. But you need to ensure you only ever have one instance of Tk otherwise you get the behaviour you encountered
I am trying to make second menu button next to the one i already made but no matter what code i use, i cannot make a second one. I want to place it next the first button by using .grid() not .place()
heres the code
from tkinter import *
import tkinter.messagebox
import ctypes
class Application(Frame):
def __init__(self, master):
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
mb = Menubutton (self, text="Sniper Rifle", relief=RAISED)
mb.menu = Menu (mb, tearoff = 0)
mb["menu"] = mb.menu
self.m40a5Var = IntVar()
self.srrVar = IntVar()
mb.menu.add_checkbutton (label="M40A5", variable=self.m40a5Var)
mb.menu.add_checkbutton (label="SRR", variable=self.srrVar)
mb.grid()
root = Tk()
root.title("heeey")
root.geometry("180x100")
app = Application(root)
root.mainloop()
I don't understand the question. You say that no matter what you try you can't create a second button. All you have to do to create another button is... create another button:
mb = Menubutton(...)
another_mb = Menubutton(...)
...
mb.grid(row=0, column=0)
another_mb.grid(row=0, column=1)