Tkinter - The Root Window hides itself after close its Toplevel window - python

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()

Related

Tkinter window backend coding

import pyupbit
from tkinter import *
class Main(Frame):
def __init__(self, window):
Frame.__init__(self, window)
self.window = window
self.price = Label(self.window, text='hello')
self.price.place(x=20,y=20)
self.get_price()
def get_price(self):
self.after(100, self.get_price)
price = pyupbit.get_current_price('KRW-BTC')
self.price.configure(text=price)
if __name__ == '__main__':
root = Tk()
root.geometry('300x300')
Main(root)
root.mainloop()
I'm trying to show bitcoin price every ms. I guess, because of api delay, the window looks have lags. I want to get the price in the backend and show it on frontend. How can I ? Can I get examples?
Try this:
import pyupbit
from tkinter import *
from threading import Thread
class Main(Frame):
def __init__(self, window):
super().__init__(window)
self.window = window
self.price = 0
self.price_label = Label(self.window, text='hello')
self.price_label.place(x=20,y=20)
thread = Thread(target=self.get_price_loop, daemon=True)
thread.start()
self.show_price()
def show_price(self):
self.price_label.configure(text=self.price)
self.after(30, self.show_price)
def get_price_loop(self):
while True:
self.price = pyupbit.get_current_price('KRW-BTC')
# Here you can add a bit of delay using `time.sleep(0.1)`
if __name__ == '__main__':
root = Tk()
root.geometry('300x300')
Main(root)
root.mainloop()
I has 2 loops. The tkinter loop displays whatever is in the self.price variable and the while True loop in the other thread updates that value by using self.price = pyupbit.get_current_price('KRW-BTC').

I am getting errors in this script and nothing is visible on tkinter display

from tkinter import *
root=Tk()
class menu_w:
def nothing(self):
pass
def __init__(self,root):
self.menubar= Menu(root)
root.config(menu=self.menubar)
self.filemenu= Menu(root,tearoff=0)
self.filemenu.add_command(label="New",command=self.nothing)
self.filemenu.add_command(label="open",command=self.nothing)
self.filemenu.add_command(label="save",command=self.nothing)
self.filemenu.add_command(label="save as",command=self.nothing)
self.menubar.add_cascade(label=File,menu=self.filemenu)
k=menu_w(root)
root.mainloop()
You forgot to define two objects in self.menubar.add_cascade, notably File and the method filemenu, below script will work.
from tkinter import Tk, Menu
class menu_w:
def __init__(self, root):
self.menubar = Menu(root)
root.config(menu=self.menubar)
self.filemenu = Menu(root, tearoff=0)
self.filemenu.add_command(label="New", command=self.nothing)
self.filemenu.add_command(label="open", command=self.nothing)
self.filemenu.add_command(label="save", command=self.nothing)
self.filemenu.add_command(label="save as", command=self.nothing)
self.menubar.add_cascade(label="File", menu=self.filemenu)
def nothing(self):
pass
def filemenu(self):
pass
def main():
root = Tk()
k = menu_w(root)
root.mainloop()
if __name__ == '__main__':
main()
Some suggestions:
do not use wildcard import, instead from tkinter import * do from tkinter import Tk, Menu
Use the if __name__ == '__main__': construct
bring root = Tk() to the main function

How to close the whole GUI when toplevel is closed tkinter

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()

tkinter quit crash

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

Application hangs after deiconify(), Tkinter

I'm trying to do Hide/Show for my application with withdraw()/deiconify() in Tkinter, but after deiconify() method call my app hangs. Run this code on Win7.
What do I do wrong?
import Tkinter as tk
import threading
class MyApp(object):
def __init__(self, parent):
self.root = parent
self.root.geometry('400x300')
self.root.title('My Application')
btn = tk.Button(parent, text='Hide', command=self.onClick)
btn.pack()
def onClick(self):
self.hide()
self.t = threading.Timer(3, self.show)
self.t.start()
def hide(self):
print 'hide()'
print 'state: ', self.root.state()
print 'withdraw()'
self.root.withdraw()
print 'state: ', self.root.state()
def show(self):
print 'show()'
print 'state: ', self.root.state()
print 'deiconify()'
self.root.deiconify()
print 'state: ', self.root.state()
print 'show end'
if __name__ == '__main__':
root = tk.Tk()
app = MyApp(root)
root.mainloop()
UPD: there is a working sample:
import Tkinter as tk
import sched
import time
class MyApp(object):
def __init__(self, parent):
self.root = parent
self.root.geometry('400x300')
btn = tk.Button(parent, text='Hide', command=self.onClick)
btn.pack()
self.scheduler = sched.scheduler(time.time, time.sleep)
def onClick(self):
self.hide()
self.scheduler.enter(3, 1, self.show, ())
self.scheduler.run()
def hide(self):
self.root.withdraw()
def show(self):
self.root.deiconify()
if __name__ == '__main__':
root = tk.Tk()
app = MyApp(root)
root.mainloop()
Tkinter is not thread safe, and you are calling self.root.deiconify() from a thread. That is most likely the source of your problem. You'll have to re-architect your solution to have the thread use a thread-safe queue to request that the main loop make calls into Tkinter.
There's a whole lot you can do with Tkinter without using threads. Are you certain you need them?

Categories

Resources