Closing windows of tkinter - python

I am new to tkinter and would like to do a UI based on the flags shown.
Basically, i would like to close one windows and open another window with the present state or delete the text and show another text with the present state.
class App(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.start()
def callback(self):
self.root.quit()
def run(self):
self.root = tk.Tk()
self.root.protocol("WM_DELETE_WINDOW", self.callback)
label = tk.Label(self.root, text="Start Initialization")
label.pack()
self.root.mainloop()
class QQQ:
def quit(self):
self.delete(1.0,END)
class Appo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.start()
def callback(self):
self.root.quit()
def run(self):
self.root = tk.Tk()
self.root.protocol("WM_DELETE_WINDOW", self.callback)
label = tk.Label(self.root, text="Initialization ended")
label.pack()
self.root.mainloop()
for i in range(100000):
time.sleep(0.5)
print(i)
if(i==1):
app = App()
time.sleep(1)
qqq=QQQ()
if(i==10):
app=Appo()

If all you want to do is change the text of the label, then use the config method on the label. The App, Appo, and QQQ classes, as well as the for loop can be combined into a single class as:
import Tkinter as tk #Python 2
#import tkinter as tk #Python 3
import threading
import time
class App(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.root = tk.Tk()
self.start()
def callback(self):
self.root.quit()
def run(self):
self.root.protocol("WM_DELETE_WINDOW", self.callback)
label = tk.Label(self.root, text="Initial Text") # You can use text=""
label.pack()
for i in range(100000):
time.sleep(0.5)
print (i)
if i == 1:
label.config(text="Start Initialization")
time.sleep(1)
label.config(text="")
if i == 10:
label.config(text="Initialization ended")
#self.root.mainloop()
app = App()
app.root.mainloop()
It might be better to use the after method of tkinter for time delays instead of time.sleep()

Related

i wana delete a text automatically after few seconds of inactivity

import tkinter as tk
class App():
def __init__(self):
self.root = tk.Tk()
self.root.config(padx=100, pady=50)
self.root.geometry('800x600')
self.text = tk.Text()
self.entry = tk.Entry()
self.text.place(x=0, y=0)
self.text.after(5000, self.clear_text) # 5000ms
self.root.mainloop()
def clear_text(self):
print ("Le text vient d'etre détruit")
self.text.place_forget()
app = App()
Hello to all,
I am trying to create an Tkinter app where i put some text in a box and if i stop typing for few seconds the text should disappear. I am a beginner, i am stuck!! Thank for giving me an idea!!Yours
Use after and bind Key event to the same method. Use an if statement to check if the event parameter of the method is None, if it is None delete the text.
import tkinter as tk
class App():
def __init__(self):
self.root = tk.Tk()
self.root.config(padx=100, pady=50)
self.root.geometry('800x600')
self.delay = 5000
self.after_id = None
self.text = tk.Text(self.root)
self.text.bind("<Key>", self.clear_text)
self.text.place(x=0, y=0)
self.root.mainloop()
def clear_text(self, event=None):
if not event:
self.text.delete("1.0", "end")
else:
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
self.after_id = self.root.after(self.delay, self.clear_text)
app = App()
Try this:
import tkinter as tk
from time import perf_counter
class App():
def __init__(self):
self.root = tk.Tk()
self.text = tk.Text(self.root)
self.text.pack()
self.text.bind("<Key>", self.text_entered)
self.text.after(100, self.check_clear_text)
self.time_last_written = perf_counter()
self.root.mainloop()
def text_entered(self, event):
self.time_last_written = perf_counter()
def clear_text(self):
print("Le text vient d'etre détruit")
# Delete all of the text
self.text.delete("0.0", "end")
def check_clear_text(self):
time_diff = perf_counter() - self.time_last_written
print(f"Last key pressed: {time_diff} sec ago.")
if time_diff > 5: # The 5 is in seconds
self.clear_text()
self.text.after(100, self.check_clear_text)
app = App()
It keeps track of the last time you pressed a key and if 5 seconds have passed, it deletes all of the widget's contents using: self.text.delete("0.0", "end")

How to open subwindows after each other in Tkinter?

I'm trying to open few windows one after the other in tkinter. They are closing itself after set amount of time. Creating first window breaks my loop (it doesn't even reach print instruction). What am I doing wrong? Here is my code:
import tkinter as tk
class Subwindow:
def __init__(self, time):
self.time = time
self.window = tk.Toplevel()
self.window.geometry("300x300+1000+200")
self.window.wm_attributes("-topmost", 1)
tk.Label(self.window, text=time).pack(anchor=tk.CENTER)
self.update_time()
self.window.mainloop()
def update_time(self):
if self.time:
self.window.title(str(self.time))
self.time -= 1
self.window.after(1000, self.update_time)
else:
self.window.destroy()
class Window:
def __init__(self):
self.window = tk.Tk()
self.initialize()
self.window.mainloop()
def initialize(self):
buttons = tk.Frame(self.window)
tk.Button(self.window, text="Start", width=5, command=self.start).pack(in_=buttons, side="left")
tk.Button(self.window, text="Exit", width=5, command=self.close).pack(in_=buttons, side="left")
buttons.place(relx=0.97, rely=0.95, anchor=tk.SE)
def close(self):
self.window.destroy()
quit()
def start(self):
for x in [5,10,15]:
sub = Subwindow(x)
print(x)
Window()
Explain me please how can I fix it to get them opening one by one?
You should not call mainloop more than once. Remove the call to mainloop inside Subwindow.__init__.

What is the best way to repeatedly execute a function every few seconds, without intterupting other functions, for a Python gui?

I want to repeatedly run a function that retrieves data from an API every 60 seconds. However, I've realized that I can't put it to sleep, or use a while loop, without interrupting the other functions.
My question is, how do I repeatedly retrieve the data from the API/rerun the code that gets the data in the first place, without interrupting the other functions?
below a complete script that retrieve ISS position longitude and latitude from Open Notify and print it on a thread.
I' ve set a 1 second time. You can start and stop the thread. Try now you to add your funcions.
Notice that you have to import this modules
import requests
import json
import tkinter as tk
import threading
import queue
import datetime
import time
import requests
import json
class MyThread(threading.Thread):
def __init__(self, queue,):
threading.Thread.__init__(self)
self.queue = queue
self.check = True
def stop(self):
self.check = False
def run(self):
while self.check:
response = requests.get("http://api.open-notify.org/iss-now.json")
data = response.json()
time.sleep(1)
self.queue.put(data)
class App(tk.Frame):
def __init__(self,):
super().__init__()
self.master.title("Hello World")
self.master.protocol("WM_DELETE_WINDOW",self.on_close)
self.queue = queue.Queue()
self.my_thread = None
self.init_ui()
def init_ui(self):
self.f = tk.Frame()
w = tk.Frame()
tk.Button(w, text="Start", command=self.launch_thread).pack()
tk.Button(w, text="Stop", command=self.stop_thread).pack()
tk.Button(w, text="Close", command=self.on_close).pack()
w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)
self.f.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
def launch_thread(self):
if (threading.active_count()!=0):
self.my_thread = MyThread(self.queue)
self.my_thread.start()
self.periodiccall()
def stop_thread(self):
if self.my_thread is not None:
if(threading.active_count()!=1):
self.my_thread.stop()
def periodiccall(self):
self.checkqueue()
if self.my_thread.is_alive():
self.after(1, self.periodiccall)
else:
pass
def checkqueue(self):
while self.queue.qsize():
try:
ret = self.queue.get(0)
print("The ISS is currently over: {0} ".format(ret['iss_position']))
except queue.Empty:
pass
def on_close(self):
if self.my_thread is not None:
if(threading.active_count()!=1):
self.my_thread.stop()
self.master.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()

How to get return value of sub process in main process

I want to start a webserver if the user does click on a button. Therefore I have written the following code:
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import messagebox
import time
from multiprocessing import Process
class MainWindow(ttk.Frame):
def __init__(self, parent):
self.parent = parent
ttk.Frame.__init__(self, master=self.parent)
self.parent.grab_set()
self.parent.title("Test_Program")
self.parent.geometry("500x500")
ttk.Button(self.parent, text="Start Web-Server", command=self.start_webserver).pack()
def start_webserver(self):
if __name__ == '__main__':
loading_screen = LoadingScreen(self)
result = [0]
sub_process = Process(target=start_webserver, args=(result,))
sub_process.start()
sub_process.join()
sub_process.terminate()
loading_screen.destroy()
if result[0] == 0:
messagebox.showinfo("Webserver Status", "Webserver is running!")
else:
messagebox.showerror("Webserver Status", "Webserver can't be started an Error occured!")
class LoadingScreen(tk.Toplevel):
def __init__(self, parent):
self.parent = parent
tk.Toplevel.__init__(self, master=self.parent)
self.geometry("200x50")
self.title("Loading Screen")
self.transient(self.parent)
self.grab_set()
ttk.Label(self, text="Copying data!").pack()
status_bar = ttk.Progressbar(self, length=180, mode="indeterminate")
status_bar.start(5)
status_bar.pack()
def __del__(self):
if isinstance(self.parent, tk.Toplevel):
self.parent.grab_set()
def start_webserver(result):
time.sleep(2) # This does represent the time thats necessary to start the webserver
result[0] = 1
def main():
root = tk.Tk()
main_window = MainWindow(root)
main_window.pack()
root.mainloop()
if __name__ == "__main__":
main()
If I click on "start webserver" its two seconds frozen because of time.sleep(2) and no progress bar does get displayed. Afterwards its done. I don't know why there is no progressbar displayed. I have used an array named "result" as parameter to get the return value of start_webserver(result) from sub_process to main_process. Unfortunately this is not working too because the value of "result[0]" stays 0. I don't know what to do. The idea of using an array I have found on stackoverflow too.
Here is the Link:
how to get the return value from a thread in python?
I have found out an answer by my own. Thanks for your help join() wasn't right. I have done it a different way and closing the "loading_screen" as well as opening the messagebox after the job has been done in the second thread.
That's the Code:
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import messagebox
import time
from threading import Thread
class MainWindow(ttk.Frame):
def __init__(self, parent):
self.parent = parent
ttk.Frame.__init__(self, master=self.parent)
self.parent.grab_set()
self.parent.title("Test_Program")
self.parent.geometry("200x50")
ttk.Button(self.parent, text="Start Web-Server", command=self.start_webserver).pack()
def start_webserver(self):
if __name__ == '__main__':
loading_screen = LoadingScreen(self)
thread = Thread(target=start_webserver, args=(loading_screen, ))
thread.start()
class LoadingScreen(tk.Toplevel):
def __init__(self, parent):
self.parent = parent
tk.Toplevel.__init__(self, master=self.parent)
self.geometry("200x50")
self.title("Loading Screen")
self.transient(self.parent)
self.grab_set()
ttk.Label(self, text="Copying data!").pack()
status_bar = ttk.Progressbar(self, length=180, mode="indeterminate")
status_bar.start(2)
status_bar.pack()
def __del__(self):
if isinstance(self.parent, tk.Toplevel):
self.parent.grab_set()
def start_webserver(widget):
return_val = do_some_stuff()
if return_val:
widget.destroy()
messagebox.showinfo("Webserver Status", "Webserver is running!")
else:
widget.destroy()
messagebox.showerror("Webserver Status", "Webserver can't be started an Error occured!\n"
"Please look inside 'Logfiles/logfile' for more details.")
def do_some_stuff():
time.sleep(2) # This does represent the time thats necessary to start the webserver
return True
def main():
root = tk.Tk()
main_window = MainWindow(root)
main_window.pack()
root.mainloop()
if __name__ == "__main__":
main()

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