I'm writing a tkinter app that creates a class with multiple toplevels. I need to be able to close the whole gui when any of the X button in the toplevels are pressed. How can I do this?
def main():
root = tk.Tk()
app = Example(master=root)
app.mainloop()
class Example(tk.Frame):
def __init__(self, master):
self.master = master
super().__init__(master)
self.initUI()
def initUI(self):
self.master.withdraw()
self.initUIL = tk.Toplevel(self.master)
self.initUIL.title('Init')
self.pack(fill = tk.BOTH, expand=1)
frame1 = tk.Frame(self.initUIL)
#I need to close the whole gui when the x in this toplevel is pressed
I solved it, it was pretty easy, you need to change the protocol for each toplevel.
self.toplevel.protocol("WM_DELETE_WINDOW", self.ask_quit)
def ask_quit():
MsgBox = tk.messagebox.askquestion ('Quit',"Are you sure you want to quit?")
if MsgBox == 'yes':
self.master.destroy()
Related
below my code:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - TEST")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.obj = NewWindow(self)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico")
# the "try/except" code has an issue..
try:
self.window.focus()
self.mw.parent.attributes('-disabled', 1)
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
finally:
self.mw.parent.attributes('-disabled', 0)
def main():
app=MainWindow()
if __name__=="__main__":
main()
the try/except code makes the Toplevel window important. when it runs, the user can't touch the root window, and if he try to do it, a bell songs and the Toplevel window flashes. it's the exactly behaivour that I want! but this piece of code has an issue.. when the user close the Toplevel window, the root doesn't became the active window. it's a big issue because it makes the root window to go back the other ones. see my gif to understand better what I mean:
http://www.imagebam.com/image/c983ce1356199964
how can I solve this issue?
You've got the wrong idea about try ... finally; it does not work that way. There are 2 ways to do what you want. One way is to simply put that code in the main window:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - TEST")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.parent.attributes('-disabled', 1)
self.obj = NewWindow(self)
self.parent.attributes('-disabled', 0)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico")
self.window.focus()
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
def main():
app=MainWindow()
app.parent.mainloop()
if __name__=="__main__":
main()
Another way is to make a method to run when the toplevel closes:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - TEST")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.obj = NewWindow(self)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico")
self.window.protocol("WM_DELETE_WINDOW", self.on_close)
self.window.focus()
self.mw.parent.attributes('-disabled', 1)
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
def on_close(self):
self.mw.parent.attributes('-disabled', 0)
self.window.destroy()
def main():
app=MainWindow()
app.parent.mainloop()
if __name__=="__main__":
main()
I have two tkinter class1.py and class2.py. I face the problem that when i import the class2.py in class1.py it executes the class2.py first then only execute class1.py.
###class 1.py
import tkinter as tk
import class2
from class2 import root2
class MyApp1(object):
def __init__(self, parent):
self.root1 = parent
self.root1.title("Main frame")
self.frame = tk.Frame(parent)
self.frame.pack()
btn = tk.Button(self.frame, text="Open Frame", command=)
btn.pack()
def call(self):
self.root1.withdraw()
x = class2.MyApp2(root2)
root1 = tk.Tk()
root1.geometry("800x600")
app = MyApp1(root1)
root1.mainloop()
###class2.py
import tkinter as tk
class MyApp2(object):
def __init__(self, parent):
self.root2 = parent
self.root2.title("Main frame")
self.frame = tk.Frame(parent)
self.frame.pack()
btn = tk.Button(self.frame, text="Open Frame", command=self.openFrame)
btn.pack()
def openFrame(self):
pass
root2 = tk.Tk()
root2.geometry("800x600")
#app = MyApp2(root2)
root2.mainloop()
Now How can I import the class2.py from the class1.py and outcome becomes class1 tkinter window then only class2 tkinter window?
You should not be importing code like this. The proper way to make your code importable is to make sure it only has functions and class definitions. Then, the code that does the importing is responsible for calling the functions and instantiating the classes.
class2.py should look something like this:
import tkinter as tk
class MyApp2(object):
def __init__(self, parent):
self.root2 = parent
self.root2.title("Main frame")
self.frame = tk.Frame(parent)
self.frame.pack()
btn = tk.Button(self.frame, text="Open Frame", command=self.openFrame)
btn.pack()
def openFrame(self):
pass
class1.py can now safely import this file. It can then create the instance of MyApp2 like this:
def call(self):
self.root1.withdraw()
new_window = tk.Toplevel()
class2.MyApp2(new_window)
Or, if you no longer need the main window, you can destroy everything inside the main window and then reuse it for the new class:
def call(self):
for child in self.root1.winfo_children():
child.destroy()
class2.MyApp2(self.root1)
In the code below, app is an instance of mainWindow, which inherits from Tkinter.Frame. I am trying to use the Frame.Configure method to change the background color of the Frame.However, calling self.configure(background="yellow") doesn't work. Can someone help me understand what mistake I am making?
import Tkinter
class mainWindow(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, master=parent)
self.parent=parent
self.button1=Tkinter.Button(master=self.parent, text='ONE', command=self.change)
self.button1.pack()
self.pack()
def change(self):
self.parent.wm_title("Changed")
self.configure(background="yellow")
root = Tkinter.Tk()
root.geometry("600x600+50+50")
app=mainWindow(root)
root.mainloop()
It does not work, because your Frame is "tiny". It does not contain any widgets (button's parent is the top window, not the frame). So to make frame big, thus visible, you need to expand it:
import Tkinter
class mainWindow(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, master=parent)
self.parent=parent
self.button1=Tkinter.Button(master=self.parent,
text='ONE',
command=self.change)
self.button1.pack()
self.pack(fill=Tkinter.BOTH, expand=1) #<--- expand frame
def change(self):
self.parent.wm_title("Changed")
self.configure(background="yellow")
root = Tkinter.Tk()
root.geometry("600x600+50+50")
app=mainWindow(root)
root.mainloop()
Try self.parent.configure(background="yellow")
I'm new to Tkinter (few-minute new), so my guess based on your code is that the frame is not showing at all. The frame's parent is root, which is also the button's parent.
So here, I'm changing the root's (top level widget) background
Edited:
Base on my reasoning above, and Marcin's answer, I deduce that the frame simply just does not have a size. So here's an edited version of your code with the frame expanded, and the frame will contain the button.
import Tkinter
class mainWindow(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, master=parent)
self.parent=parent
self.button1=Tkinter.Button(master=self, text='ONE', command=self.change)
self.button1.pack()
self.pack(fill=Tkinter.BOTH, expand=True)
def change(self):
self.parent.wm_title("Changed")
self.configure(background="yellow")
root = Tkinter.Tk()
root.geometry("600x600+50+50")
app=mainWindow(root)
root.mainloop()
I am very new to Tkinter. I made this "Hello World"-like GUI program in Tkinter. However, every time I click on the quit button, the program crashes. Thanks in advance!
from Tkinter import *
import sys
class Application(Frame):
def __init__(self,master=None):
Frame.__init__(self,master=None)
self.grid()
self.createWidgets()
def createWidgets(self):
self.quitButton = Button(text='Quit',command=self.quit)#Problem here
self.quitButton.grid()
app = Application()
app.master.title("Sample application")
app.mainloop()
In Tkinter the root element is a Tk object. Application should be a subclass of Tk, not Frame:
from Tkinter import *
import sys
class Application(Tk):
def __init__(self):
Tk.__init__(self)
self.grid()
self.createWidgets()
def createWidgets(self):
self.quitButton = Button(text='Quit',command=self.destroy) # Use destroy instead of quit
self.quitButton.grid()
app = Application()
app.title("Sample application")
app.mainloop()
This Code works fine now:
import tkinter
class MyApp(tkinter.LabelFrame):
def __init__(self, master=None):
super().__init__(master, text="Hallo")
self.pack(expand=1, fill="both")
self.createWidgets()
self.createBindings()
def createWidgets(self):
self.label = tkinter.Label(self)
self.label.pack()
self.label["text"] = "Bitte sende ein Event"
self.entry = tkinter.Entry(self)
self.entry.pack()
self.ok = tkinter.Button(self)
self.ok.pack()
self.ok["text"] = "Beenden"
self.ok["command"] = self.master.destroy
def createBindings(self):
self.entry.bind("Entenhausen", self.eventEntenhausen)
self.entry.bind("<ButtonPress-1>", self.eventMouseClick)
self.entry.bind("<MouseWheel>", self.eventMouseWheel)
def eventEntenhausen(self, event):
self.label["text"] = "Sie kennen das geheime Passwort!"
def eventMouseClick(self, event):
self.label["text"] = "Mausklick an Position " \
"({},{})".format(event.x, event.y)
def eventMouseWheel(self, event):
if event.delta < 0:
self.label["text"] = "Bitte bewegen Sie das Mausrad"\
" in die richtige Richtung."
else:
self.label["text"] = "Vielen Dank!"
root = tkinter.Tk()
app = MyApp(root)
app.mainloop()
When you use self.quit() the python interpreter closes down without the tkinter application bieng closed . So try .destroy() command and after .mainloop() use sys.quit(). Hope this helps.
Your using __init__ difficultly. Do this:
from tkinter import *
root = Tk()
btn_quit = Button(root, text='Quit', command=quit()).pack()
root.mainloop()
If you do self.quit, that is the quit command so the thing will crash!
Hope this helps!
try using raise SystemExit
this may be better.
or check out me
In Tkinter, how would look like the code of button that adds a widget when clicked, infinitely if necessary?
Thanks and sorry for bad english.
This is a more "classy" version:
from Tkinter import *
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.number = 0
self.widgets = []
self.grid()
self.createWidgets()
def createWidgets(self):
self.cloneButton = Button ( self, text='Clone', command=self.clone)
self.cloneButton.grid()
def clone(self):
widget = Label(self, text='label #%s' % self.number)
widget.grid()
self.widgets.append(widget)
self.number += 1
if __name__ == "__main__":
app = Application()
app.master.title("Sample application")
app.mainloop()
Note you keep your widgets in self.widgets list, so you can recall them and modify them if you like.
Well it could look something like this (it could look like a lot of different things):
import Tkinter as tk
root = tk.Tk()
count = 0
def add_line():
global count
count += 1
tk.Label(text='Label %d' % count).pack()
tk.Button(root, text="Hello World", command=add_line).pack()
root.mainloop()