Home > OS >  How to schedule a task once a week from a date decided by the user with tkinter?
How to schedule a task once a week from a date decided by the user with tkinter?

Time:09-24

I need to download some files weekly at a time and day specified by the user as shown in the screenshot. I am struggling with integrating an inner loop with respect to root.mainloop(). So far I have tried with .after and with a while structured like this:

def scaricaAuto(myDay, myHour, myMinute):
    while True:
    day = datetime.datetime.now().strftime("%A")
    hour = datetime.datetime.now().strftime("%H")
    minute = datetime.datetime.now().strftime("%M")
    if day == myDay and str(int(hour)) == myHour and str(int(minute)) == myMinute:
       DownloadButton.invoke()
       break
    root.after(60000, scaricaAuto(clickedDays.get(), HourSpin.get(), MinSpin.get()))

Using only .after leads to Python: maximum recursion depth exceeded while calling a Python object and the while loop doesn't behave properly, when the if is true it gets stucked there and keeps invoking DownloadButton.

Also OS X shows my script to be "not responding" when a button function last longer than a few seconds, is there a solution for this to?

Thanks in advance to those that took the time to read my question and might be able to help me!

CodePudding user response:

There are a couple of problems in your code. First, you need to remove while True. That serves no purpose. Tkinter is already running an infinite loop by way of mainloop.

Second, after requires a function. You're calling a function and passing the result to after.

In other words, this:

root.after(60000, scaricaAuto(clickedDays.get(), HourSpin.get(), MinSpin.get()))

... is functionally identical to this:

result = scaricaAuto(clicedDays.get(), HourSpin.get(), MinSpin.get())
root.after(60000, result)

Instead, you either need to pass scaricaAuto as an argument, or you need to create a new function that calls your function. In the case of the former, you can pass arguments to the function by passing those arguments to after.

For example,

root.after(60000, scaricaAuto, clickedDays.get(), HourSpin.get(), MinSpin.get())

Note that this calls the .get() functions immediately rather than waiting the full 60 seconds.

A better solution is to not pass any arguments to scaricaAuto and instead have it call the .get() methods right when it needs the values:

def scaricaAuto():
    myDay = clickedDays.get()
    myHour = HourSpin.get()
    myMinute = MinSpin.get()

    now = datetime.datetime.now()
    day = now.strftime("%A")
    hour = now.strftime("%H")
    minute = now.strftime("%M")

    if day == myDay and str(int(hour)) == myHour and str(int(minute)) == myMinute:
       DownloadButton.invoke()
    root.after(60000, scaricaAuto)

The above code will run for as long as the GUI itself is running, assuming you've called mainloop at some point.

  • Related