I'm trying to add an alarm sound to my timer program, however whenever the function for the sound gets called, the program times out, and you have to wait until the sound file finishes. I've tried using asyncio and right now I'm trying to use multiprocessing modules to resolve this issue, however I've kept on hitting my head against a brick wall.
Here is my code right now for the program
import PySimpleGUI as sg
import time
from pydub import AudioSegment
from pydub.playback import play
import multiprocessing
duration = 500 # milliseconds
freq = 440 # Hz
sg.theme('DarkBrown4')
song = AudioSegment.from_mp3("alarm.mp3")
quiet_song = song - 40
def sound():
play(quiet_song)
def main():
centered_column = [[sg.T(('Set Time to Study'), font=('Consolas', 20))],
[sg.T((''), font=('Consolas', 20), key='countdown')],
[sg.B('Exit'),
sg.B('Start/Stop')], # Buttons For Timer
[sg.B('Pomodoro'),
sg.B('Short Break'),
sg.B('Long Break')
]]
layout = [[sg.Text(key='-EXPAND-', font='ANY 1', pad=(0, 0))], # the thing that expands from top
[sg.Text('', pad=(0, 0), key='-EXPAND2-'), # the thing that expands from left
sg.Column(centered_column, vertical_alignment='center', justification='center', k='-C-')]]
window = sg.Window('StudyWare Timer', layout, size=(400, 200), grab_anywhere=True, resizable=True, finalize=True)
window['-C-'].expand(True, True, True)
window['-EXPAND-'].expand(True, True, True)
window['-EXPAND2-'].expand(True, False, True)
active = False
value = 0
while True:
event, values = window.Read(timeout=1000)
# print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
m, s = divmod(value, 60)
timerx = "%02d:%02d" % (m, s)
if event == 'Pomodoro':
# active = not active
value = 1
window.Element('countdown').Update(value=timerx)
if event == 'Short Break':
# active = not active
value = 300
window.Element('countdown').Update(value=timerx)
if event == 'Long Break':
# active = not active
value = 900
window.Element('countdown').Update(value=timerx)
if event == 'Start/Stop':
active = not active
if event == '__TIMEOUT__' and active:
window.Element('countdown').Update(value=timerx)
value -= 1
if value == -1:
active = not active
window.refresh()
if __name__ == '__main__':
p2 = multiprocessing.Process(target=main())
p = multiprocessing.Process(target=sound())
p2.start()
p.start()
p2.join()
p.join()
Any suggestions would be greatly appreciated! )))
Related
I want to create a progress bar using PySimpleGUI but I want the user to put the maximum of the progress bar.
this is my code:
import PySimpleGUI as sg
import random, time
sg.theme("LightBlue")
progress_value=input()
layout = [[sg.Text("Enter a number out of 50", font='Lucida'),
sg.InputText(key='-PROGRESS_VALUE-', font='Lucida, 20', size=(20, 40))],
[sg.ProgressBar(progress_value, orientation='h', size=(100, 20), border_width=4, key='-PROGRESS_BAR-',
bar_color=("Blue", "Yellow"))],
[sg.Button('Change Progress'), sg.Exit(),sg.Button('Stop Progress')]]
window = sg.Window("Progress Bar", layout)
while True:
event, values = window.read()
if event == 'Exit' or event == sg.WIN_CLOSED:
break
progress_value = int(values['-PROGRESS_VALUE-'])
if event == "Change Progress":
for i in range(progress_value):
event, values = window.read(1000)
if event == "Stop Progress":
window['-PROGRESS_BAR-'].update(i-1)
break
window['-PROGRESS_BAR-'].update(max=progress_value)
window['-PROGRESS_BAR-'].update(i+1)
window.close()
as you can see the maximum which is "progress_value" is given by an input (progress_value=input())
but i want it to come from the input text of the user (sg.InputText(key='-PROGRESS_VALUE-', font='Lucida, 20', size=(20, 40))) and that value will be set to progress_value
Here's one way of doing what you're after using a single event loop
When changing the max value of a ProgressBar, you must set a current value too (in the same update call).
import PySimpleGUI as sg
sg.theme("LightBlue")
progress_value = 50
layout = [[sg.Text("Enter a number out of 50", font='Lucida'),
sg.InputText(key='-PROGRESS_VALUE-', font='Lucida, 20', size=(20, 40))],
[sg.ProgressBar(progress_value, orientation='h', size=(100, 20), border_width=4, key='-PROGRESS_BAR-',
bar_color=("Blue", "Yellow"))],
[sg.Button('Change Progress'), sg.Button('Start Progress'), sg.Button('Stop Progress')]]
window = sg.Window("Progress Bar", layout)
progress_started, counter, timeout = False, 0, None
while True:
event, values = window.read(timeout=timeout)
if event == 'Exit' or event == sg.WIN_CLOSED:
break
if event == "Change Progress":
progress_value = int(values['-PROGRESS_VALUE-'])
# NOTE - must set a current count when changing the max value
window['-PROGRESS_BAR-'].update(current_count= 0, max=progress_value)
elif event == 'Start Progress':
progress_started = True
counter = 0
timeout = 1000
elif event == 'Stop Progress':
progress_started = False
timeout = None
if progress_started:
window['-PROGRESS_BAR-'].update(counter)
counter += 1
if counter > progress_value:
progress_started = False
window.close()
I have a couple programs I am trying this on here is a smaller one. I have a right click set up I want to change keep_on_top=True to keep_on_top=False
as you can see I am able to change the Alpha level but not able to figure out how to make this change here is the code of a simple local and Zulu time clock
import PySimpleGUI as sg
import pytz
from datetime import datetime
Cur_Time_Date=''
Cur_Time_DateUTC=''
ALPHA = 0.9 # Initial alpha until user changes
def update_window():
current_datetime = datetime.now()
Cur_Time_Date = current_datetime.strftime("%H:%M:%S (L) %m/%d/%y")
utc_time = datetime.now(pytz.utc)
Cur_Time_DateUTC = utc_time.strftime("%H:%M:%S (Z) %m/%d/%y")
window['-LCL-'].update(Cur_Time_Date + '(L)')
window['-UTC-'].update(Cur_Time_DateUTC + '(Z)')
def create_window():
right_click_menu = [[''],['keep_on_top', 'Alpha', [str(x) for x in range(1, 11)], 'Exit', ]]
layout = [
[sg.Text(Cur_Time_Date, key = '-LCL-')],
[sg.Text(Cur_Time_DateUTC, key = '-UTC-')]
]
return sg.Window('Local/UTC time', layout, alpha_channel=ALPHA, no_titlebar=True, grab_anywhere=True, right_click_menu=right_click_menu, keep_on_top=True)
window = create_window()
while True:
event, values = window.read(timeout=1000)
if event in (sg.WIN_CLOSED, '-CLOSE-'):
break
elif event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
break
elif event == 'keep_on_top':
sg.popup( title = 'Keep On Top', keep_on_top=True)
elif event in [str(x) for x in range(1, 11)]:
window.set_alpha(int(event) / 10)
#window.close
update_window()
I figured it out if anyone else is looking
First, I set the variable and setup my own popup box:
keepOnTop = True
def My_popup():
layout = [[sg.Text('Keep On Top')],
[sg.Push(), sg.Yes(),sg.No(), sg.Push()]]
window = sg.Window('', layout, keep_on_top=True)
event, values = window.read()
window.close()
return (event)
I set the variable to start and used it to set at the beginning.
Then I used this when selecting option from right clicking
elif event == 'keep_on_top':
ans=My_popup()
print(ans)
if ans == 'Yes':
keepOnTop=True
else:
keepOnTop=False
print(keepOnTop)
window.close()
window = create_window()
I also needed to add, finalize=True to the window
I've created an application to run a query and download some files from a database. I want to indicate the application is still running while the query resolves. Currently, the loading animation popup appears over the main window. However, when I minimize the main window, the popup remains. I want to popup to appear, disappear (minimize), and move relative to the main window.
I have not delved into the Tkinter documentation yet. I'm not sure how it would interact with PySimpleGUI. I'm hoping to just use PySimpleGUI, but I am open to other solutions.
I'd like to also use the modal functionality for it. The main window shouldn't support interaction while the download script is running.
import PySimpleGUI as psg
def download_thread():
pass
psg.theme('GrayGrayGray')
layout = [
[psg.Frame("Query",[
[psg.Button('Open File'), psg.Button('Save File'), psg.Text('Untitled.sql', key = '-DOCNAME-')],
[psg.Multiline(size = (120,30), key = '-TEXTBOX-', font='Consolas 12', no_scrollbar=True, expand_x=True)],
])],
[psg.Column([[psg.Button('Download Files'),psg.Cancel()]], justification='right')]
]
window = psg.Window('File Download Tool', layout)
loading = False
while True:
event, values = window.read(timeout = 10)
if event == psg.WIN_CLOSED or event == 'Exit':
break
if loading:
psg.popup_animated(psg.DEFAULT_BASE64_LOADING_GIF, time_between_frames=100)
else:
psg.popup_animated(None)
if event == 'Download Files':
loading = True
download_thread() # pretend this is threaded
if event == 'Cancel':
loading = False
It won't work if you use the popup_animated provided by PySimpleGUI, try to design one by yourself if you need something different or special.
Following code demo the way by binding event '<Configure>' to popup window to move main window with same delta position, also with option modal=True of popup window to have this window be the only window a user can interact with until it is closed.
from time import sleep
import threading
import PySimpleGUI as sg
def popup(main_window, window=None, duration=0, image=sg.DEFAULT_BASE64_LOADING_GIF):
global x0, y0, x1, y1, user_event
if window is None:
layout = [[sg.Image(data=image, enable_events=True, key='-IMAGE-')]]
x0, y0 = main_window.current_location(more_accurate=True)
w0, h0 = main_window.current_size_accurate()
window = sg.Window('Title', layout, no_titlebar=True, grab_anywhere=True,
background_color='blue', element_padding=(0, 0), margins=(0, 0), finalize=True, modal=True)
w1, h1 = window.current_size_accurate()
x1, y1 = x0+(w0-w1)//2, y0+(h0-h1)//2
window.move(x1, y1)
window.refresh()
window.bind("<Configure>", 'Configure')
else:
window['-IMAGE-'].update_animation(image, time_between_frames=duration)
event, values = window.read(1)
if event == 'Configure':
if user_event:
user_event = False
else:
x11, y11 = window.current_location(more_accurate=True)
x00, y00 = main_window.current_location(more_accurate=True)
if (x11, y11) != (x1, y1):
x0, y0 = x0+x11-x1, y0+y11-y1
main_window.move(x0, y0)
x1, y1 = x11, y11
elif (x00, y00) != (x0, y0):
x1, y1 = x1+x00-x0, y1+y00-y0
window.move(x1, y1)
x0, y0 = x00, y00
user_event = True
return window
def download(window):
sleep(5)
window.write_event_value('Done', None)
sg.theme('GrayGrayGray')
layout = [
[sg.Frame("Query",[
[sg.Button('Open File'), sg.Button('Save File'), sg.Text('Untitled.sql', key = '-DOCNAME-')],
[sg.Multiline(size = (120,30), key = '-TEXTBOX-', font='Consolas 12', no_scrollbar=True, expand_x=True)],
])],
[sg.Column([[sg.Button('Download Files'),sg.Cancel()]], justification='right')]
]
window = sg.Window('File Download Tool', layout, finalize=True)
loading, popup_win, x1, y1, user_event = False, None, None, None, False
x0, y0 = window.current_location(more_accurate=True)
while True:
event, values = window.read(timeout = 10)
if event == sg.WIN_CLOSED or event == 'Exit':
break
elif event == sg.TIMEOUT_EVENT and loading:
popup_win = popup(window, popup_win, duration=100)
elif event == 'Download Files':
loading = True
threading.Thread(target=download, args=(window, ), daemon=True).start()
elif event == 'Done':
popup_win.close()
loading, popup_win = False, None
window.close()
I have 2 columns and I want to reveal them on a button press by using the visibility parameter. However, it seems that columns that go from invisible to visible stop being next to each other and are instead arranged like rows.
Here is the code without the reveal, and the columns work fine:
import PySimpleGUI as sg
left_col = sg.Column([[sg.Frame('',[],background_color = '#FF0000',size = (60,40))]])
right_col = sg.Column([[sg.Frame('',[],background_color = '#00FF00',size = (60,40))]])
layout = [
[sg.Button('reveal')],
[left_col,right_col]]
window = sg.Window('Converter', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
window.close()
And here is the same code with the columns being revealed:
import PySimpleGUI as sg
left_col = sg.Column([[sg.Frame('',[],background_color = '#FF0000',size = (60,40))]],visible = False, key = 'left')
right_col = sg.Column([[sg.Frame('',[],background_color = '#00FF00',size = (60,40))]],visible = False, key = 'right')
layout = [
[sg.Button('reveal')],
[left_col,right_col]]
window = sg.Window('Converter', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
if event == 'reveal':
window['left'].update(visible = True)
window['right'].update(visible = True)
window.close()
I guess my question is whether there is a workaround for this (or whether I did something wrong).
Elements after visible=False will miss it's location in the window, so use function pin to keep the location for element if you want to set it to be invisible.
layout = [
[sg.Button('reveal')],
[sg.pin(left_col), sg.pin(right_col)]]
By default, the background is the background color of theme. Of course, you can built one by yourself which with one more option bg as background_color.
Don't forget to set the background color of the Column in your layout at the same time.
def pin(elem, vertical_alignment=None, shrink=True, expand_x=None, expand_y=None, bg=None):
if shrink:
return sg.Column([[elem, sg.Column([[]], pad=(0,0), background_color=bg)]], background_color=bg, pad=(0, 0), vertical_alignment=vertical_alignment, expand_x=expand_x, expand_y=expand_y)
else:
return sg.Column([[elem]], pad=(0, 0), vertical_alignment=vertical_alignment, expand_x=expand_x, expand_y=expand_y, background_color=bg)
Then you code maybe something like this
import PySimpleGUI as sg
def pin(elem, vertical_alignment=None, shrink=True, expand_x=None, expand_y=None, bg=None):
if shrink:
return sg.Column([[elem, sg.Column([[]], pad=(0,0), background_color=bg)]], background_color=bg, pad=(0, 0), vertical_alignment=vertical_alignment, expand_x=expand_x, expand_y=expand_y)
else:
return sg.Column([[elem]], pad=(0, 0), vertical_alignment=vertical_alignment, expand_x=expand_x, expand_y=expand_y, background_color=bg)
left_col = sg.Column([[sg.Frame('', [], background_color = '#FF0000', size = (60,40))]], background_color='blue')
right_col = sg.Column([[sg.Frame('', [], background_color = '#00FF00', size = (60,40))]], background_color='blue')
layout = [
[sg.Button('reveal')],
[pin(left_col, bg='blue'), pin(right_col, bg='blue')]]
window = sg.Window('Converter', layout, background_color='blue')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
window.close()
I am using a GUI to display a countdown timer which will be activated when user click start countdown.
Using another thread to compute the countdown timer , however i only require the latest thread to write on the display, instead of multiple thread writing on the display.
*Button can be clicked multiple time(or used to reset the countdown), just need to show the newest thread data.
import time
import logging
import threading
import PySimpleGUI as sg
cp = sg.cprint
def main():
sg.theme('DarkAmber')
col1 = [[sg.Button('start countdown', button_color='white on green', size=(18, 5), font=('Arial', 30, 'bold'))],
[sg.Button('Buzzer Stop', button_color='red', font=('Arial', 30, 'bold'), size=(18, 5))
]]
col2 = [[sg.Multiline(size=(100, 2), key='-AB-', font=('Arial', 50, 'bold'), reroute_stdout=True, write_only=True,
reroute_cprint=False)],
[sg.Multiline(size=(100, 6), key='-ML-', autoscroll=True, reroute_stdout=True, write_only=True,
reroute_cprint=True)]
]
layout_test = [[sg.Column(col1, element_justification='c'), sg.Column(col2, element_justification='c')]]
window = sg.Window('Counter', layout_test, size=(800, 480))
while True:
event, values = window.read()
cp(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event.startswith('start countdown'):
t = 900
t1 = threading.Thread(target=countdown, args=(t, window), daemon=True).start()
if event.startswith('Buzzer Stop'):
threading.Thread(target=Samplingthread, args=(window,), daemon=True).start()
Buzzerflag = 60
window.close()
def countdown(t, window):
while t:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
window['-AB-'].print(timer)
time.sleep(1)
t -= 1
if __name__ == '__main__':
main()
Not to update GUI in your thread.
from time import sleep
import threading
import PySimpleGUI as sg
def count_down(window):
count = 100
while count and countdown:
window.write_event_value("COUNT", count)
count -= 1
sleep(1)
def count_up(window):
count = 0
while not countdown:
window.write_event_value("COUNT", count) # CANNOT update GUI in thread
count += 1
sleep(1)
sg.theme('DarkBlue3')
layout = [
[sg.Button('COUNTDOWN'), sg.Button('TIMER')],
[sg.Text('', size=(20, 1), key='LABEL')],
]
window = sg.Window('TITLE', layout, finalize=True)
label = window['LABEL']
countdown = False
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event == 'COUNTDOWN':
countdown = True
threading.Thread(target=count_down, args=(window,), daemon=True).start()
elif event == 'TIMER':
countdown = False
threading.Thread(target=count_up, args=(window,), daemon=True).start()
elif event == 'COUNT':
label.update(value=values[event])
countdown = not countdown
sleep(1)
window.close()