I am creating a GUI with tkinter and I need help.
I have two buttons, one for starting my code and another one for exit the GUI and stop the code running. Here is part of my code:
def close_app():
window.destroy()
def run_app():
.... do something...
window = tk.Tk() #start of the app
button_run = tk.Button(frame_bottom, text = "Search", command = run_app)
button_run.grid(column=0, row=0, sticky='w', padx=100, pady=2)
button_close = tk.Button(frame_bottom, text = "Exit", command = close_app)
button_close.grid(column=1, row=0, sticky='e', padx=100, pady=2)
window.mainloop() #end of the app
The problem is that when I press "Exit" button the GUI does not respond anymore and the code still continues in the background. How can I stop the execution of the program with my Exit button?
I tried also to delete the Exit button and to stop the code simply closing the GUI, but the problem is the same, after a while "not respondind" appears. How can I solve it?
From the code you posted it's hard to tell, but if run_app is doing something that takes very long the function won't be stopped - that's why your GUI is freezing.
If run_app contains a loop, setting a global variable in close_app then checking inside the loop if that variable is set and if it is stopping the loop would be the solution:
import time
import tkinter as tk
exit_app = False
def close_app():
exit_app = True
window.destroy()
def run_app():
for i in range(100):
if exit_app:
break
time.sleep(1)
window = tk.Tk()
button_run = tk.Button(frame_bottom, text = "Search", command = run_app)
button_run.grid(column=0, row=0, sticky='w', padx=100, pady=2)
button_close = tk.Button(frame_bottom, text = "Exit", command = close_app)
button_close.grid(column=1, row=0, sticky='e', padx=100, pady=2)
window.mainloop()
(Not tested as your code does not define frame_bottom)
If it doesn't run in a loop, the last solution would be to call sys.exit in close_app which should exit yur script immediately.
Related
unfortunately previous examples which come close to my question have not helped me in resolving my issue.
I have two buttons:
self.button_one = tk.Button(self,
image=anything_flag,
command=lambda: main(set_language,"anything"),
padx=5,
pady=5,
text="Anything")
self.button_one.grid(row = 2, column = 3,padx=5, pady=5)
self.button_exit = tk.Button(self,
command=lambda: self.controller.show_frame(FrameOne),
padx=5,
pady=5,
text="Back")
self.button_exit.grid(row = 3, column = 3,padx=5, pady=5)
Button_one starts a chatbot in another python scrip chatbot.py which was imported using from chatbot import main which is actively listening in a forever running while loop and button exit exits the selection and returns to the first page (language selection).
def main(language, attribute):
feedback=listen(language_country_id)
while "stop" not in feedback.lower():
print("hello:",feedback.lower())
x=chat(answer,start_chat_log)
log += [x[1].lstrip()]
speak(english_to(x[1].lstrip(),language),language_voice_id)
start_chat_log=x[0]+x[1]
feedback=listen(language_country_id)
while feedback == None:
speak(english_to("Sorry, i did not understand you, could you please repeat that?",language),language_voice_id)
feedback=listen(language_country_id)
answer=to_english(feedback,language)
log += [answer]
However, because the chatbot listens within a while loop, the Tkinter application remains unresponsive.
Is there a way to allow the back button to be pressed while the chatbot listens to the person?
Somehow, my Tkinter code is calling the function before displaying the label, however, the label should have come first.
def doAction():
global e
text = tk.Label(root, text="Processing.")
text.grid(row=2, columns=1)
main()
import tkinter as tk
root = tk.Tk()
root.title("App")
e = tk.Entry(root)
e.grid(row=0, column=0, padx=10, pady=10)
e.focus_set()
button = tk.Button(root, text="Go", command=doAction)
button.grid(row=0, column=3)
root.mainloop()
The idea behind is to display first "Processing" and then let the function "main()" do its thing.
Once it enters main(), something there is blocking the main thread, hence mainloop() cannot update. You will have to force update it before it calls main().
def doAction():
.....
text.grid(row=2, columns=1)
root.update() # Now the event loop will start processing before the function ends
main()
It is not a good idea to freeze the GUI with whatever you are doing inside main(), if it does not have code related to tkinter you could start a new thread for main().
I'm creating a tkinter gui that I would like to run. This app will do some house cleaning of sorts. It would check files, check for updates, give the user some information etc. Then I would like it to start another tkinter application and then close it self.
import tkinter as tk
import os
def StartProgram():
os.startfile("C:/WINDOWS/system32/notepad.exe")
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame, text="QUIT", fg="red", command= lambda: quit())
button.pack( side=tk.LEFT)
button2 = tk.Button(frame,text="Start my exe", command=lambda: StartProgram())
button2.pack(side=tk.LEFT)
root.maxsize(200,200)
root.minsize(200,200)
root.mainloop()
The problem I have so far is when I attempt to close the original app it closes the one it started as well.
EDIT: I also tried root.destroy(), root.quit()
Any suggestion how I might correct this?
So, I made a small canvas window with tkinter which has 2 buttons, One is a start button, the other is a stop button. (I'll attach the GUI tkinter code down below. I wont add the Selenium part because I don't want to confuse anyone with mushed up code.) The start button calls a function thats threaded and that launches my "Reporting_Backbone.py" which is a selenium/pyautogui bot that does a bunch of stuff. My problem is that the stop button does not stop the "Reporting_Backbone.py". In the stop button function I've tried sys.exit() but the selenium and the GUI stay open (and running), I've tried daemons (which I might not have been using them correctly because that did nothing)I've tried setting the stop button function to a lambda (which just freezes the GUI, but not the selenium part) and I've tried setting up some kind of a killswitch as a last resort but honestly this thing wont die, its like Thanos fused with Majin Buu. It just keeps running. How do I make it so that the stop button works? I I'm hoping someone can help me with a solution and explanation. I am still new to coding but I am really loving it, if possible I would really like to understand what I am doing wrong. Thank you.
enter code here
import tkinter as tk
from PIL import Image, ImageTk
import time
import os
import threading
import sys
root = tk.Tk()
#Canvas for GUI
canvas = tk.Canvas(root, width=600, height=800)
canvas.grid(columnspan=3, rowspan=4)
canvas.configure(bg="#b9be9c")
#Button Starting
def start_report():
time.sleep(0.5)
start_text.set("Armed!")
os.system("python Reporting_Backbone.py")
#Button Stopping
def stop_craigslist():
stop_text.set('Stopped')
time.sleep(3)
sys.exit()
#Logo
logo = Image.open('Logo.png')
logo = ImageTk.PhotoImage(logo)
logo_label = tk.Label(image=logo)
logo_label.image = logo
#playing logo in window
logo_label.grid(column=1, row=0)
logo_label.configure(bg="#b9be9c")
#instructions
instructions = tk.Label(root, text="Click the 'Start' Button to begin.")
instructions.grid(columnspan=3, column=0, row=1)
instructions.configure(font=("Helvetica", 25) ,bg="#b9be9c")
#Start Button
start_text = tk.StringVar()
start_btn = tk.Button(root, textvariable=start_text, command=threading.Thread(target=start_report).start, font=("Helvetica", 18), fg="black", height=2, width=15)
start_text.set("Start")
start_btn.grid(column=1, row=2)
#Stop Button
stop_text = tk.StringVar()
stop_btn = tk.Button(root, textvariable=stop_text, command=threading.Thread(target=stop_craigslist).start, font=("Helvetica", 18), fg="black", height=2, width=15) #If I set this to a lambda function the Tkinter GUI Freezes up on me
stop_text.set("Stop")
stop_btn.grid(column=1, row=3)
root.mainloop()
You cannot stop the task created by threading.Thread(). Use subprocess instead:
import subprocess
...
proc = None
def start_report():
global proc
if proc and not proc.poll():
print("process is still running")
return
proc = subprocess.Popen([sys.executable, "Reporting_backbone.py"])
start_text.set("Armed!")
def stop_craigslist():
global proc
if proc:
proc.terminate()
proc = None
stop_text.set('Stopped')
...
start_btn = tk.Button(root, ..., command=start_report, ...)
...
stop_btn = tk.Button(root, ..., command=stop_craigslist, ...)
...
I am creating a scheduler for a few different python scripts and I am using a tkinter window to take in the usernames and passwords for the servers I am accessing.
I seem to be able to get the scheduler to work, but when it does, it now breaks the mainloop so the window no longer responds.
I have tried putting the mainloop inside the loop that keeps the schedule running, but that causes the scheduler to stop functioning.
import tkinter as tk
import subprocess
import schedule
import time
class MainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.e_user_label = tk.Label(self, text="Email Username")
self.e_pw_label = tk.Label(self, text="Email Password")
self.e_account_label = tk.Label(self, text="Email Account")
self.email_user = tk.Entry(self, width=30)
self.email_pw = tk.Entry(self, show="*", width=30)
self.email_account = tk.Entry(self, width=30)
self.start_scheduler = tk.Button(self, text="Start Scheduler",
command=self.check_email_request)
self.e_user_label.pack()
self.email_user.pack()
self.e_pw_label.pack()
self.email_pw.pack()
self.e_account_label.pack()
self.email_account.pack()
self.start_scheduler.pack()
def check_email_request(self):
call_email_script = 'call python email_monitor.py {} {} {}'.format(self.email_user.get(),
self.email_pw.get(), self.email_account.get())
completed = subprocess.run(call_email_script, shell=True)
print('returncode:', completed.returncode)
def print_stuff(self):
schedule.every(1).minutes.do(self.check_email_request)
while True:
schedule.run_pending()
time.sleep(1)
w.mainloop() #my failed attempt to solve this problem
w = MainWindow()
w.mainloop()
Expected the scheduler to keep calling my check_email_request function every 1 minute. If I don't include the main loop in schedule loop, the window no longer functions. When I include the mainloop, the scheduler no longer functions.