如何与另一个调度程序一起运行Tkinter GUI?

时间:2019-07-12 08:31:09

标签: python multithreading tkinter

我已经将一个Tkinter GUI编码为控制台来控制某些内容。而且,我还想从APScheduler模块运行一个调度程序来完成一项工作,该工作每20秒执行一次操作。 但是,这两个线程似乎无法一起运行。

我尝试使用multi-threading,但似乎不起作用。

import tkinter as tk
from tkinter import *
import time
import pyHook
import winreg
import webbrowser
import os
import pyautogui
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.schedulers.background import  BackgroundScheduler
import threading

def initialization():
    webbrowser.open('AutoRefreshSCMOutbound.HTML', 1)
    time.sleep(2)


def autoClick():
    x, y = pyautogui.size()
    pyautogui.click(x/2, y/2, button='left')
    time.sleep(1)
    pyautogui.click(x/2, y/2, button='left')
    return True

root = tk.Tk()
root.geometry('700x100')
root.resizable(height = True, width = True)
root.overrideredirect(False)

OneBtn = Button(root, command = initialization, text = "One Button", width = '30')
OneBtn.grid(row = 1 ,column = 0)   

if __name__ == "__main__":
    th01 = threading.Thread(target=root.mainloop())
    scheduler = BackgroundScheduler
    scheduler.add_job(autoClick, 'interval', seconds=20)
    threads = []
    th01.start()
    scheduler.start()
    threads.append(th01)
    threads.append(scheduler)
    for t in threads:
        t.join()
    print("End all process")

这2个线程应该在同一时间运行,但是调度程序总是需要等到Tkinter结束。

1 个答案:

答案 0 :(得分:0)

tkinter中,您可以使用root.after(time_in_millisecond, function_name)来延迟执行功能。 root.after仅执行一次功能,因此您必须在此功能内再次使用root.after

import tkinter as tk
import time
import webbrowser
import pyautogui

def initialization():
    webbrowser.open('AutoRefreshSCMOutbound.HTML', 1)
    time.sleep(2)

def autoClick():
    # run again after 20000ms (20s)
    root.after(20000, autoClick)

    x, y = pyautogui.size()
    pyautogui.click(x/2, y/2, button='left')
    time.sleep(1)
    pyautogui.click(x/2, y/2, button='left')

if __name__ == "__main__":
    root = tk.Tk()
    root.geometry('700x100')
    root.resizable(height = True, width = True)
    root.overrideredirect(False)

    OneBtn = tk.Button(root, command=initialization, text="One Button", width='30')
    OneBtn.grid(row=1, column=0)   

    # run first time after 20000ms (20s)
    root.after(20000, autoClick)

    root.mainloop() 

或将其他功能与after()一起使用来执行您不想修改的功能。

import tkinter as tk
import time
import webbrowser
import pyautogui

def initialization():
    webbrowser.open('AutoRefreshSCMOutbound.HTML', 1)
    time.sleep(2)

def autoClick():
    x, y = pyautogui.size()
    pyautogui.click(x/2, y/2, button='left')
    time.sleep(1)
    pyautogui.click(x/2, y/2, button='left')

def repeate():
    # run again after 20000ms (20s)
    root.after(20000, repeate)
    autoclick()

if __name__ == "__main__":
    root = tk.Tk()
    root.geometry('700x100')
    root.resizable(height = True, width = True)
    root.overrideredirect(False)

    OneBtn = tk.Button(root, command=initialization, text="One Button", width='30')
    OneBtn.grid(row=1, column=0)   

    # run first time after 20000ms (20s)
    root.after(20000, repeate)

    root.mainloop() 

但是after()仅在执行的函数不能运行太长时间时才有用,因为此时它仍然阻塞mainloop()(和程序的其余部分)。因为autoClick使用sleep(1),所以它会停止所有程序1秒钟。

如果其他函数的运行时间不长,则after()很有用,因为它可能会阻塞mainloop()来执行由after()添加的函数。 initialization使用sleep(2),因此可能会阻塞执行autoClick 2秒钟。


要在没有sleep(1)的情况下运行它,可以将函数分为两个函数,然后使用after(1000, second_part)执行第二部分

def repeate():
    # run again after 20000ms (20s)
    root.after(20000, repeate)
    autoclick()

def autoClick():
    x, y = pyautogui.size()
    pyautogui.click(x/2, y/2, button='left')

    root.after(1000, autoClick_second_part) # 1000ms (1s)

def autoClick_second_part():
    pyautogui.click(x/2, y/2, button='left')