Python - PySimpleGUI - Lock Relative Position of Windows (or Loading Animation Overlay) - python

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()

Related

Switch window in PySimpleGUI with keyboard input (left/right arrow)

I have 3 windows in terms of sg.Frame and would like to switch the windows via keyboard input. However the window does not respones while the buttons work well.
layout = [
[
sg.Column(layout1, key='-COL1-'), # layoutX is a page interms of sg.Frame
sg.Column(layout2, visible=False, key='-COL2-'),
sg.Column(layout3, visible=False, key='-COL3-')
],
[
# sg.Button('Cycle Layout'),
sg.Button('-PREV-'),
sg.Button('1'),
sg.Button('2'),
sg.Button('3'),
sg.Button('-NEXT-'),
# sg.Button('Exit')
]
]
window = sg.Window('Swapping the contents of a window', layout) #, size = (1024, 800)
layout = 1 # The currently visible layout
while True:
event, values = window.read()
print(event, values)
if event in (None, 'Exit'):
break
window.bind('<Right>', '-NEXT-')
window.bind('<Left>', '-PREV-')
window.bind('<Down>', 'Exit')
if event == '-NEXT-' and layout < 3:
window[f'-COL{layout}-'].update(visible=False)
layout = layout + 1
window[f'-COL{layout}-'].update(visible=True)
elif event == '-PREV-' and layout > 1:
window[f'-COL{layout}-'].update(visible=False)
layout -= 1
window[f'-COL{layout}-'].update(visible=True)
elif event in '123':
window[f'-COL{layout}-'].update(visible=False)
layout = int(event)
window[f'-COL{layout}-'].update(visible=True)
window.close()
How can I modify? Thanks very much!
The statements for binding the keyboards should be placed after window finalized and before your event loop, then it will work before your event loop start.
window = sg.Window('Swapping the contents of a window', layout, finalize=True) #, size = (1024, 800)
window.bind('<Right>', '-NEXT-')
window.bind('<Left>', '-PREV-')
window.bind('<Down>', 'Exit')

Selenium and pyautogui does not seem to work together

I have script where you write information in pyautogui and it launches a window of selenium. The problem is that when the selenium window is open pyautogui lags to the extent that it is not usable.
I have tried removing all code related to selenium but it seems that just launching the window makes the pyautogui stop working
Here is my current code. Most of the pyautogui stuff was taken from a example at github.
Any help would be appreciated
def start_script(information):
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.maximize_window()
# defines the url
print(information)
#coordinates = pd.read_excel('Companies.xlsx', header=None)
#coordinates = str(coordinates.iloc[0, 0])
coordinates = '67, 67'
url = 'https://www.google.se/maps/search/AB/#' + coordinates + ',12.5z'
# opens the website
driver.get(url)
fail = True
while fail == True:
try:
driver.find_element(
By.XPATH, "//div[#class='VtwTSb']//form[1]").click()
except:
fail == True
else:
fail = False
while True:
pass
def make_window(theme):
sg.theme(theme)
menu_def = [['&Application', ['E&xit']]]
input_layout = [
# [sg.Menu(menu_def, key='-MENU-')],
[sg.Button("Open File")],
[sg.Text('Search (ab, ltd, etc)')],
[sg.Input(key='-INPUT-')],
[sg.Text('Coordinates')],
[sg.Input(key='-INPUT-')],
[sg.Spin([i for i in range(1, 11)], initial_value=10,
k='-SPIN-'), sg.Text('The level of zoom')],
[sg.OptionMenu(values=('Right', 'Left', 'Up'),
k='-Direction-'), sg.Text('Direction')],
[sg.Button('Start'), sg.Button('Skip'), sg.Button('Add')]]
logging_layout = [[sg.Text("Anything printed will display here!")],
[sg.Multiline(size=(60, 15), font='Courier 8', expand_x=True, expand_y=True, write_only=True,
reroute_stdout=True, reroute_stderr=True, echo_stdout_stderr=True, autoscroll=True, auto_refresh=True)]
# [sg.Output(size=(60,15), font='Courier 8', expand_x=True, expand_y=True)]
]
layout = [[sg.MenubarCustom(menu_def, key='-MENU-', font='Courier 15', tearoff=True)],
[sg.Text('Specify the information below and press start', size=(38, 1), justification='center', font=("Helvetica", 16), relief=sg.RELIEF_RIDGE, k='-TEXT HEADING-', enable_events=True)]]
layout += [[sg.TabGroup([[sg.Tab('Input Elements', input_layout),
sg.Tab('Output', logging_layout)]], key='-TAB GROUP-', expand_x=True, expand_y=True),
]]
layout[-1].append(sg.Sizegrip())
window = sg.Window('Google maps webscraper', layout,
grab_anywhere=True, resizable=True, margins=(0, 0), use_custom_titlebar=True, finalize=True, keep_on_top=True)
window.set_min_size(window.size)
return window
def main():
window = make_window(sg.theme())
# This is an Event Loop
while True:
event, values = window.read(timeout=100)
# keep an animation running so show things are happening
if event not in (sg.TIMEOUT_EVENT, sg.WIN_CLOSED):
print('============ Event = ', event, ' ==============')
print('-------- Values Dictionary (key=value) --------')
for key in values:
print(key, ' = ', values[key])
if event in (None, 'Exit'):
print("[LOG] Clicked Exit!")
break
elif event == "Open File":
print("[LOG] Clicked Open File!")
folder_or_file = sg.popup_get_file(
'Choose your file', keep_on_top=True)
sg.popup("You chose: " + str(folder_or_file), keep_on_top=True)
print("[LOG] User chose file: " + str(folder_or_file))
elif event == "Start":
thread_selenium = threading.Thread(target=start_script, args=(values,))
thread_selenium.start()
elif event == "Skip":
print('Skip')
elif event == "Add":
print('test')
window.close()
exit(0)
if __name__ == '__main__':
sg.theme('system default for real')
sg.theme('DefaultNoMoreNagging')
main()

python pysimpleGUI changing keep on Top

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

How do I utilize multiprocessing module in Python?

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! )))

PySimpleGUI changing visibility breaks columns(?)

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()

Categories