2

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.

Profcrab
  • 21
  • 3
  • You don't need the `schedule` module at all; Tkinter's `.after()` method can delay the function call by a minute, without blocking anything (and then the function will use `.after()` again to call itself the next minute). – jasonharper May 17 '19 at 17:41
  • Is your mainloop not being interrupted by your function? [Read here](https://stackoverflow.com/questions/42422139/how-to-easily-avoid-tkinter-freezing) about threading and tkinter – Matt M May 17 '19 at 17:45
  • @jasonharper I think ```.after()``` would work for this one that is running on a regular interval. I was planning on adding another schedule that would run every Sunday at a designated time. I should have included an example. I think ```.after()``` will be good to use if I don't use a specified day, though. Thanks! @MattM I'll try that method. That sounds like a good way to make it flexible. – Profcrab May 17 '19 at 17:56
  • 1
    Creating a thread solved the problem. I changed ```command=self.check_email_request``` in the for the button action to ```command=threading.Thread(group=None, target=self.check_email_request).start```. The main window stays active and the schedule runs. I get an exception when I close the window, but this is a smaller problem to solve. – Profcrab May 17 '19 at 18:30
  • Great. You're going to always want any functions to be in a thread that is different from tkinter's, else it will freeze up during execution. Feel free to post that exception if you dont figure it out – Matt M May 17 '19 at 18:53
  • @Profcrab *"I get an exception when I close the window"*: You have to stop your `Thread` before `.destroy()` the `.mainloop()`. – stovfl May 18 '19 at 05:56

0 Answers0