Search code examples
pythonpysimplegui

how to stop a thread? Is it possible to tie a thread to a global variable? the thread2 in this script is not visible to elife statment event


import PySimpleGUI as sg
from my_scripts import *
from my_constants import *
import sys
import glob
import yt_dlp
import threading
import time

global thread2

sg.LOOK_AND_FEEL_TABLE['MyCreatedTheme'] = {'BACKGROUND': '#000066', 
                                        'TEXT': '#ffebbf', 
                                        'INPUT': '#354230', 
                                        'TEXT_INPUT': '#ffebbf', 
                                        'SCROLL': '#99CC99', 
                                        'BUTTON': ('#003333', '#FFCC66'), 
                                        'PROGRESS': ('#D1826B', '#CC8019'), 
                                        'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0, } 

# Switch to use your newly created theme 
sg.theme('MyCreatedTheme') 

sg.theme_background_color('#4eae61')
sg.set_options(font=('Fira Code', 16), background_color= '#555f9a')
l1 = sg.Text('Put url here',font=('Fira Code', 16), expand_x=True, justification='center')
t1 = sg.Text('', enable_events=True, font=('Fira Code', 16), justification='left')
t2 = sg.InputText( font=('Fira Code', 16),  justification='left', default_text='5', key='-folder-')

def delete_video_in_D():
        list_of_files = [os.remove(p)  for p in glob.glob(r'D:\\*.*') if (os.path.isfile(p) and is_video(p))]
        

layout = [
    [l1],
    [t1,  sg.InputText(key='-url-')], 
    [t2],
    [sg.Button('Download',  button_color='#b1defb')],
    [sg.Button('Cancel playing',  button_color='#fbceb1')],
    ]


FOLDERS = {'1':Chef_Max_Mariola_PATH,
           '2':JuliaCrossBow_PATH,
           '3':French_Vibes_PATH,
           '4':Studio_Italiano_InClasse_PATH,
           '5':'D:\\'}


window = sg.Window('Main Window', layout)

while True:

    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    elif event == 'Download':
        delete_video_in_D()
        url = values['-url-']
        folder = values['-folder-']
        os.chdir(FOLDERS[folder])
        try:
            with yt_dlp.YoutubeDL() as ydl:
                thread1 = threading.Thread(target=ydl.download, args=(url, ), daemon=True)
                thread1.start()
                while True:
                    if thread1.is_alive():
                        pass
                    else:
                        list_of_files = [x for x in glob.glob(r'*.*') if os.path.isfile(x) and is_video(x)]
                        latest_file = max(list_of_files, key=os.path.getctime)
                        new_name = re.sub(r'\s*\[.*?\]\s*', '', latest_file )
                        os.rename(latest_file, new_name)
                        thread2 = threading.Thread(target=play_video, args=(new_name,), daemon=True).start()
                        break         
            
        except Exception as e:
            print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)

    elif event == 'Cancel playing': # thread2 is not visible here
        thread2.stop()
# the error message I get when click on button 'Cancel playing' is
# AttributeError: 'NoneType' object has no attribute 'stop'       
window.close()

Solution

  • Most of time, I do it by using a flag, or a global variable, to stop the while loop in my sub-thread.

    A simple, short and executable example Code may help people to help.

    import time
    import datetime
    import threading
    import PySimpleGUI as sg
    
    def job(window):
        global running
        while running:
            window.write_event_value('Event', datetime.datetime.now().strftime("%H:%M:%S"))
            time.sleep(0.1)
    
    layout = [
        [sg.Text("00:00:00", font=("Courier New", 20, "bold"), justification='center', expand_x=True, key="TIME")],
        [sg.Push(), sg.Button('Start'), sg.Button('Stop')],
    ]
    window = sg.Window('Threading', layout)
    running, old = False, None
    
    while True:
    
        event, values = window.read()
    
        if event == sg.WIN_CLOSED:
            running = False
            time.sleep(0.5)
            break
    
        elif event == 'Start' and not running:
            running = True
            window['Start'].update(disabled=True)
            threading.Thread(target=job, args=(window, ), daemon=True).start()
    
        elif event == 'Stop':
            running = False
            window['Start'].update(disabled=False)
    
        elif event == 'Event':
            now = values[event]
            if now != old:
                window["TIME"].update(now)
                old = now
    
    window.close()