【问题标题】:Stop Thread without closing GUI window在不关闭 GUI 窗口的情况下停止线程
【发布时间】:2020-04-10 20:41:47
【问题描述】:

我正在自学python,我的水平可能是“脚本小子”的一个糟糕的借口,因为我有点理解,并且最终大多是借用不同的脚本并将其混搭在一起,直到它达到我想要的效果。然而,这是我第一次尝试为我拥有的一个脚本创建 GUI。我正在使用 PySimpleGUI,而且我已经能够很好地理解它。除了一件事之外,所有事情都按照我想要的方式工作。

问题是我想在不退出 GUI 的情况下停止正在运行的守护线程。如果我让停止按钮工作,则 GUI 关闭,如果 GUI 没有关闭,它不会停止线程。问题在'64-68'行之间。我已经尝试了一些事情,只是在“65”行上放置了一个占位符,以记住我试图让 GUI(我的头脑中的“主线程”)运行。脚本将在此状态下运行,但“停止”按钮不起作用。

注意:我在脚本中放置了很多 cmets,因此我记得每个部分是什么、它的作用以及我需要清理什么。如果我打算共享脚本,我不知道这是否是一个好习惯。另外,如果重要的话,我会使用 Visual Studio Code。

#!/usr/local/bin/python3

import PySimpleGUI as sg
import pyautogui
import queue
import threading
import time
import sys
from datetime import datetime
from idlelib import window

pyautogui.FAILSAFE = False
numMin = None

# ------------------ Thread ---------------------

def move_cursor(gui_queue):
    if ((len(sys.argv)<2) or sys.argv[1].isalpha() or int(sys.argv[1])<1):
        numMin = 3
    else:
        numMin = int(sys.argv[1])
    while(True):
        x=0
        while(x<numMin):
            time.sleep(5)                   # Set short for debugging (will set to '60' later)
            x+=1
        for i in range(0,50):
            pyautogui.moveTo(0,i*4)
        pyautogui.moveTo(1,1)
        for i in range(0,3):
            pyautogui.press("shift")
        print("Movement made at {}".format(datetime.now().time()))  

# --------------------- GUI ---------------------

def the_gui():
    sg.theme('LightGrey1')                  # Add a touch of color
    gui_queue = queue.Queue()               # Used to communicate between GUI and thread


    layout = [  [sg.Text('Execution Log')],
             [sg.Output(size=(30, 6))],
             [sg.Button('Start'), sg.Button('Stop'), sg.Button('Click Me'), sg.Button('Close')]  ]
    window = sg.Window('Stay Available', layout)

# -------------- EVENT LOOP ---------------------
    # Event Loop to process "events"

    while True:
        event, values = window.read(timeout=100)
        if event in (None,'Close'):
          break
        elif event.startswith('Start'):     # Start button event
            try:
                print('Starting "Stay Available" app')
                threading.Thread(target=move_cursor,
                                 args=(gui_queue,), daemon=True).start()
            except queue.Empty:
                print('App did not run')
        elif event.startswith('Stop'):      # Stop button event
            try:
                print('Stopping "Stay Available" app')
                threading.main_thread       # To remind me I want to go back to the original state
            except queue.Empty:
                print('App did not stop')
        elif event == 'Click Me':           # To see if GUI is responding (will be removed later)
            print('Your GUI is alive and well')

    window.close(); del window

if __name__ == '__main__':
    gui_queue = queue.Queue()               # Not sure if it goes here or where it is above
    the_gui()
    print('Exiting Program')

【问题讨论】:

  • while True: 循环可能是while running:,其中running 最初是True,当线程应该关闭时,您将其设置为False

标签: python multithreading pysimplegui


【解决方案1】:

从此answer:创建类stoppable_thread

然后:将线程存储在全局变量中:

# [...]
# store the threads on a global variable or somewhere

all_threads = []

# Create the function that will send events to the ui loop

def start_reading(window, sudo_password = ""):
    While True:
        window.write_event_value('-THREAD-', 'event')
        time.sleep(.5)
        
# Create start and stop threads function

def start_thread(window):
    t1 = Stoppable_Thread(target=start_reading,  args=(window,), daemon=True)
    t1.start()
    all_threads.append(t1)

def stop_all_threads():
    for thread in all_threads:
        thread.terminate()

最后,在主窗口循环中,处理启动、停止或从线程获取信息的事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    相关资源
    最近更新 更多