Tkinker window not responding when clicked on the "Exit" - python

I created a GUI using Python, Tkinter. Everything seems to be fine. I have added several options to my Menu tab. In the File section I have added a feature to exit the GUI by clickinh onto the Exit button(not the button though, but a menu option). Here is the code that I have written.
from tkinter import *
from tkinter import filedialog, RIGHT
class Filedialog:
def directory(self):
content = filedialog.askdirectory()
return content
class Main(Frame):
def __init__(self):
self.opening_times = 0
self.current_image = 0
self.images = []
self.root = Tk()
self.root.title("Y")
self.root.configure(bg='pale turquoise')
self.root.geometry("800x800")
self.frame = Frame(self.root)
self.frame.pack(side=RIGHT)
self.frame = Frame.__init__(self, self.root)
self.widgets()
self.root.mainloop()
def widgets(self):
self.menu = Menu(self.root)
self.root.config(menu=self.menu)
self.filemenu = Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="File", menu=self.filemenu)
self.filemenu.add_separator()
self.filemenu.add_command(label="Save")
self.filemenu.add_separator()
self.filemenu.add_command(label="Exit", command=self.onExit)
#self.editmenu = Menu(self.menu, tearoff=0)
#self.menu.add_cascade(label='Edit', menu=self.editmenu)
#self.editmenu.add_command(label="Undo")
#self.editmenu.add_command(label="Redo")
def onExit(self):
self.root.quit()
if __name__ == "__main__":
Main()
I have almost succeeded. But the problem arises when I click on the exit. The function does what it has to. But the GUI window was not closing, also it freezes there. There was no response at all until I force the window to close externally.
I also tried doing:
self.quit()
/
self.exit()
But the response is the same as the GUI freezes and not letting me do any other activities. I had to close complete program to get the access again.
I am not getting the error at least, to know what is wrong.
Please help me find out what is wrong/solve this problem.
Thank you for your time.

Let me correct your code
from sys import exit
from tkinter import *
from tkinter import filedialog, RIGHT
class Filedialog:
def directory(self):
content = filedialog.askdirectory()
return content
class Main(Frame):
def __init__(self):
self.opening_times = 0
self.current_image = 0
self.images = []
self.root = Tk()
self.root.title("Y")
self.root.configure(bg='pale turquoise')
self.root.geometry("800x800")
self.frame = Frame(self.root)
self.frame.pack(side=RIGHT)
self.frame = Frame.__init__(self, self.root)
self.widgets()
self.root.mainloop()
def widgets(self):
self.menu = Menu(self.root)
self.root.config(menu=self.menu)
self.filemenu = Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="File", menu=self.filemenu)
self.filemenu.add_separator()
self.filemenu.add_command(label="Save")
self.filemenu.add_separator()
self.filemenu.add_command(label="Exit", command=self.onExit)
#self.editmenu = Menu(self.menu, tearoff=0)
#self.menu.add_cascade(label='Edit', menu=self.editmenu)
#self.editmenu.add_command(label="Undo")
#self.editmenu.add_command(label="Redo")
def onExit(self):
self.root.destroy()
exit()
if __name__ == "__main__":
Main()
You need to use destroy() instead of quit() and you should use exit to quit from the console

The method you have to use is destroy. For example:
def onExit(self):
self.root.destroy()

Use destroy() method instead of quit.

You can use the method tk.destroy() to close a window. The built-in functions exit() and quit() close the Python console.
Working example
from tkinter import *
tk = Tk()
tk.title("Closing window demonstration")
def close_window():
tk.destroy()
quit = Button(tk, text = "Quit", command = close_window)
quit.pack()
tk.mainloop()

Related

Changing the root window of embedded Vlc instance in Tkinter

I want to be able to switch a VLC Instance between frames. The purpose is to toggle fullscreen mode. In fullscreen mode, the Instance should be embedded into a toplevel, otherwise it should be embedded into root.
I have code that does this, but it stops te video when switching between full screen and non-full screen. This would interrupt the playing. So I'm wondering if there's ways to do it without interrupting this playing, i.e. without the player.stop() command.
Here's my code:
from tkinter import (
Tk, Menu, Frame, Label, Button, Scale, Toplevel,
BOTH, Entry, DISABLED, END, HORIZONTAL, VERTICAL
)
from vlc import Instance
class Test:
def __init__(self):
self.Instance = Instance()
self.player = self.Instance.media_player_new()
self.root = Tk()
self.root.geometry("800x800")
self.frame = Frame(self.root, width=700, height=600)
self.frame.pack()
Button(
self.root, text="OK",
command=self.play).pack(side='left')
Button(
self.root, text="FS",
command=self.FS).pack(side='left')
self.display = Frame(self.frame, bd=5)
self.display.place(relwidth=1, relheight=1)
self.root.mainloop()
def play(self):
Media = self.Instance.media_new('test.webm')
self.player.stop()
self.player.set_xwindow(self.display.winfo_id())
self.player.set_media(Media)
self.player.play()
def FS(self):
self.top = Toplevel(self.root)
self.top.geometry("200x200")
self.player.stop()
Media = self.Instance.media_new('test.webm')
self.player.set_xwindow(self.top.winfo_id())
self.player.play()
self.player.set_media(Media)
self.player.play()
self.top.attributes("-fullscreen", True)
def main():
Test()
if __name__ == '__main__':
main()

Open a new window with the button

I am building a real time monitoring project where information is given in the first window and that's keep on updating in the second window. I am trying to monitor the updated information in parallel from a different window using the same code, but as I pressed the new button and given the new information it is updating in the previous window also but I wanted monitor window to be completely different, so that I can monitor the different information in parallel using the same code. Please have a look at the sample code and help me with the ideas.
The sample code:
import time
import threading
import tkinter.messagebox
from tkinter import ttk
import queue
from tkinter import *
class Demo1:
data=[]
def __init__(self, master):#Python scrollbar on text widget
self.master = master
self.t=tkinter.Text(self.master,height=20,width=50)
self.t.grid(row=1, column=1)
self.button = tkinter.Button(self.master,height=3,width=10, text="OK", command = self.new_window)
self.button.grid(row=2,column=1)
def new_window(self):
self.inputValue=self.t.get("1.0",'end-1c')
Demo1.data1=self.inputValue.split("\n")
self.master.destroy() # close the current window
self.master = tkinter.Toplevel() # create another Tk instance
self.app = Demo2(self.master) # create Demo2 window
self.master.mainloop()
class Demo2:
t1 = []
s1 = True
display = []
display1 = []
i=0
kas = True
num=0
j1=0
def __init__(self, master):
self.master = master
self.button = tkinter.Button(self.master,height=2,width=11, text="new",command=self.new).place(x=0,y=0)
self.label = tkinter.Label(self.master, text="monitor", font=("Arial",20)).grid(row=0, columnspan=3)
cols = ('aa','bb')
self.listBox = ttk.Treeview(self.master, columns=cols)
for col in cols:
self.listBox.heading(col, text=col)
self.listBox.column(col,minwidth=0,width=170)
self.listBox.grid(row=1, column=0)
self.a()
def a(self):
self._img=tkinter.PhotoImage(file="green1.gif")
a=Demo1.data1
for i,(a) in enumerate(a): #here I have some function which runs repeatedlly
self.listBox.insert('', 'end',image=self._img, value=(a))
threading.Timer(1.0, self.a).start()
def new(self):
main()
def main():
root = tkinter.Toplevel()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
I have given the pppp information to monitor but as a pressed new button and added the xx information its updating in the previous window also. Please help me with the idea so that the link between these window will be vanished.
Output:
You have some major issues with your program. Including how you are trying to use your classes. The Toplevel() object was giving me issue, so I used Tk(). This should show you how to properly use the classes with the window. Most importantly your second window needs to be created from global not the first window. Also Demo1.data is a reference to your class definition not the actual data you loaded. I hope this example is helpful.
from tkinter import *
# your second window should be created in global
def create_demo2():
global app, app2
root2 = Tk()
app2 = Demo2(root2, app)
class Demo1:
def __init__(self, window):
self.window = window
self.data = ""
self.button = Button(self.window, text="New Window",
command=create_demo2)
self.button.pack()
def set_data(self):
self.data = "data"
class Demo2:
# you could just use app from global scope, but I like to pass so that it is explicit.
def __init__(self, window, app1):
self.window = window
self.button_set = Button(self.window, text="Set", command=app1.set_data)
self.button_use = Button(self.window, text="Use", command=self.use_data)
self.app = app1
self.label = Label(self.window)
self.button_set.pack()
self.button_use.pack()
self.label.pack()
def use_data(self):
self.label.configure(text=self.app.data)
root = Tk()
app = Demo1(root)
app2 = None
root.mainloop()

Loop triggered by Tkinter button and ended by another

The following code will show a small Tkinter user interface, however my buttons will not trigger the loop called copy_loop. I have been trying for several hours and I cannot figure out how to fix this. Any help will be very appreciated.
import tkinter as tk
import threading
class App():
def __init__(self, master):
self.isrunning = False
self.button1 = tk.Button(main, text='start')
self.button1.bind = ("<Button-1>", self.startrunning)
self.button1.pack()
self.button2 = tk.Button(main, text='stop')
self.button2.bind = ("<Button-1>", self.stoprunning)
self.button2.pack()
def startrunning(self, event):
self.isrunning = True
t = threading.Thread(target=self.copy_loop)
t.start()
def stoprunning(self, event):
self.isrunning = False
def copy_loop(self):
while self.isrunning:
print("Running...")
main = tk.Tk()
app = App(main)
main.mainloop()
bind is a function, not an attribute. Where you have:
self.button1.bind = ("<Button-1>", self.startrunning)
you are actually overwriting the bind function on your instance. It is now a tuple.
Instead, do:
self.button1.bind("<Button-1>", self.startrunning)
And likewise for button2.
You have an equals sign where there shouldn't be one. The command should be:
self.button1 = tk.Button(main, text='start')
self.button1.bind("<Button-1>", self.startrunning)
Or the much neater:
self.button1 = tk.Button(main, text='start', command=self.startrunning)
And your method signatures should have event=None:
def startrunning(self, event=None):
Or even more flexible:
def startrunning(self, *args):

import a python file that create a window when main window button clicks

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

Execute Button Method

I am trying to execute a Tkinter ttk Button method while the button is pressed, meaning I want the method to keep executing when the button is pressed and stop when I release it, but i can't quite figure it out. Here is the code.
from tkinter import *
from tkinter import ttk
class stuff (object):
def __init__(self, master):
master.title("Grid Master")
master.frame_1 = ttk.Frame(master)
master.frame_1.pack()
master.configure(background = "#FFFFFF")
self.button = ttk.Button(master, text = 'Press', command = self.callback)
self.button.pack()
def callback(self):
print ("Hello world")
def main():
root = Tk()
loop = stuff(root)
root.mainloop()
if __name__ == '__main__':
main()
You can see in the code that the method only prints "Hello world" and I want this function to execute and keep going, printing Hello world until I release the button.
You can use root.after() to repeatedly schedule a job to perform the required task. Note that I have changed the button event to activate when the button is pressed, and to terminate the "after" job when the button is released.
try:
from tkinter import *
from tkinter import ttk
except ImportError:
# Python 2, probably
from Tkinter import *
import ttk
class stuff (object):
def __init__(self, master):
self._master = master
master.title("Grid Master")
master.frame_1 = ttk.Frame(master)
master.frame_1.pack()
master.configure(background = "#FFFFFF")
self.button = ttk.Button(master, text = 'Press')
self.button.bind("<Button-1>", self.button_pressed)
self.button.bind("<ButtonRelease-1>", self.button_released)
self.button.pack()
self.hello_world_frequency = 1 # milliseconds
def hello_world(self):
print ("Hello world")
self._job = self._master.after(self.hello_world_frequency, self.hello_world)
def button_pressed(self, event):
print ("Button down")
self.hello_world()
def button_released(self, event):
print ("Button released")
self._master.after_cancel(self._job)
def main():
root = Tk()
loop = stuff(root)
root.mainloop()
if __name__ == '__main__':
main()
You can make a custom repeating ttk button class that inherits from ttk.Button but adds basic repeating functionality.
Try this. you can use it like
self.button = RepeatButton(master, text='Press', command=self.callback)
and you can set the repeatdelay and repeatinterval arguments, which default to 300 and 100.
class RepeatButton(ttk.Button):
def __init__(self, *args, **kwargs):
self.callback = kwargs.pop('command', None)
self.repeatinterval = kwargs.pop('repeatinterval', 100)
self.repeatdelay = kwargs.pop('repeatdelay', 300)
ttk.Button.__init__(self, *args, **kwargs)
if self.callback:
self.bind('<ButtonPress-1>', self.click)
self.bind('<ButtonRelease-1>', self.release)
def click(self, event=None):
self.callback()
self.after_id = self.after(self.repeatdelay, self.repeat)
def repeat(self):
self.callback()
self.after_id = self.after(self.repeatinterval, self.repeat)
def release(self, event=None):
self.after_cancel(self.after_id)

Categories