I'm having trouble trying to make pysimplegui work as I want.
I would like to open the program, enter my information, run "Extract",
let the script finish (it shows details in the output). Then on the same window, I would like to run another one using the same button "Extract" once the first script has finished running.
The best I can do is loop it and it opens a new window and closes the first.
How do I get it to just stay open and allow me to do another search without closing when the script is finished?
In other words, I want to open 1 GUI window and run multiple scripts using different parameters "keywords" or start/end dates. One after the other.
guivalues = ['', '', '', "localhost", "root", 'PASSWORD', '', ''];
while True:
sg.theme('Dark2')
layout = [
[sg.Text('Enter multiple Keywords, comma to separate')],
[sg.Text('Keywords', size=(20, 1)), sg.InputText()],
[sg.Text('Start Date YYYY-MM-DD: ', size=(20, 1)), sg.InputText(guivalues[1])],
[sg.Text('End Date YYYY-MM-DD: ', size=(20, 1)), sg.InputText(guivalues[2])],
[sg.Text('Host (usually localhost): ', size=(20, 1)), sg.InputText(guivalues[3])],
[sg.Text('User (usually root): ', size=(20, 1)), sg.InputText(guivalues[4])],
[sg.Text('mySQL password: ', size=(20, 1)), sg.InputText(guivalues[5])],
[sg.Text('Database: ', size=(20, 1)), sg.InputText(guivalues[6])],
[sg.Text('Table: ', size=(20, 1)), sg.InputText(guivalues[7])],
[sg.Output(size=(70, 15))],
[sg.Button('Extract'), sg.Button('Close')]
]
window = sg.Window('Python to SQL', layout)
event, guivalues = window.read()
if event == 'Close':
break
window.Close()
if event == 'Extract':
XXX EXTRACTION CODE XXXXX
window.read()
window.Close()
ISSUE RESOLVED
sg.theme('Dark2')
layout = [
[sg.Text('Enter multiple Keywords, comma to separate')],
[sg.Button('Extract', bind_return_key=True ), sg.Button('Close')]
]
window = sg.Window('Python to SQL', layout)
while True:
event, guivalues = window.read()
if event in (None, 'Quit'):
break
if event == 'Close':
break
if event == 'Extract':
mydb = mysql.connector.connect(
The key is not looping the GUI window. Use the "While True" loop for the script doing the backend work. And within the while loop, you "read" the window for conditional "event" statements. THEN you put the conditionals within the loop. In other words
#GUI Stuff#
then
While True:
event, guivalues = window.read()
then
Conditionals
Related
I have a project where I'm trying to build a simple time-clock using Python 3 on a Raspberry Pi. The Pi is running 64-bit Bullseye.
In my script, I create a window with two columns, one for entry and one for display. The entry side is working (as far as I have gone). The display side sorta works, and this is the issue.
The user will enter their code, press "Enter" to see their information, and then press "In" or "Out" for clocking in or out. When the user presses "In", I want to display a message that says either "Clocked In" or "Already Clocked in".
The issue is that the clocked-in message does not display. The statement that fails is the msg_elem.Update( .... If I run the Python debugger, the message is displayed, but not in "normal" running.
My question is What am I doing wrong?
This is a working example...
import sys, os, platform
import PySimpleGUI as sg
from PIL import Image, ImageTk
from time import sleep
import io
#
# Elements
# create the Elements we want to control outside the form
out_elem = sg.Text('', size=(55, 1), font=('Helvetica', 18), text_color='black',justification='center')
in_elem = sg.Input(size=(10,1), do_not_clear=True)
img_elem = sg.Image(size=(240,240),key="-IMAGE-")
msg_elem = sg.Text('', size=(65, 1), font=('Helvetica', 18), text_color='black',justification='center',key='-MSG-')
#
# Columns
button_column = [
[sg.Text("User Input"),in_elem],
[sg.ReadFormButton('1', size=(3,3)),
sg.ReadFormButton('2', size=(3,3)),
sg.ReadFormButton('3', size=(3,3)),
sg.ReadFormButton('Clear', size=(6,3))],
[sg.ReadFormButton('4', size=(3,3)),
sg.ReadFormButton('5', size=(3,3)),
sg.ReadFormButton('6', size=(3,3)),
sg.ReadFormButton('Enter', size=(6,3))],
[sg.ReadFormButton('7', size=(3,3)),
sg.ReadFormButton('8', size=(3,3)),
sg.ReadFormButton('9', size=(3,3)),
sg.ReadFormButton('Quit', size=(6,3))],
[sg.T(''), sg.T(' ' * 8),
sg.ReadFormButton('0', size=(3,3))],
[sg.T('')],
[sg.ReadFormButton('In', size=(13,3)),
sg.ReadFormButton('Out', size=(13,3)),]
]
display_column = [
[sg.Text("User Details")],
[out_elem],
[sg.T(' ' * 30), img_elem],
[msg_elem],
]
#
layout = [
[sg.Column(button_column),
sg.VSeperator(),
sg.Column(display_column,justification='center',vertical_alignment='top')]
]
form = sg.Window('Time Clock', layout, auto_size_buttons=False, size=(800,480))
keys_entered = ''
while True:
button, values = form.Read()
if button is None:
form["-IMAGE-"].update()
out_elem.Update( " " )
break
elif button == 'Clear':
keys_entered = ''
pcpid = ''
empid = ''
form["-IMAGE-"].update()
in_elem.Update(keys_entered)
out_elem.Update( " " )
msg_elem.Update( " " )
elif button in '1234567890':
keys_entered = in_elem.Get()
keys_entered += button
elif button == 'Enter':
keys_entered = '123'
first_name = 'Mike'
last_name = 'Retiredguy'
empid = 12345
im1 = Image.open( 'mike.png' )
im1.thumbnail((240,240))
bio = io.BytesIO()
im1.save( bio, format="PNG")
empimage = bio.getvalue()
form["-IMAGE-"].update( empimage )
dsplAns = f"{empid} - {last_name}, {first_name}"
out_elem.Update( dsplAns )
elif button == 'In':
# import pdb; pdb.set_trace()
sqlAns = 1 # User already clocked in
if sqlAns > 0:
msg_elem.Update( "...is already clocked in! (A)" ) # <=== THIS IS WHAT FAILS
else:
msg_elem.Update( "...is clocked in! (B)" ) # <=== THIS IS WHAT FAILS
sleep(10)
# Clear input
keys_entered = ''
pcpid = ''
empid = ''
form["-IMAGE-"].update()
in_elem.Update(keys_entered)
out_elem.Update( " " )
msg_elem.Update( " " )
elif button == 'Quit':
sys.exit(0)
in_elem.Update(keys_entered)
#
# ###EOF###
I have tried this on the RPi, and on a Virtual system with Debian (not Pi) linux. Both give me the same result. I've searched here on Stack Overflow, and Google in general, and I think I'm doing it correctly, but failing.
The method msg_elem.Update just update the architecture of PySimpleGUI, not the GUI. Need to call window.refresh() before sleep(10) if you want the GUI updated immediately, not until back to window.read(). sleep(10) take long time for GUI to wait, so it will show "Not Responding".
Demo Code
from time import sleep
import threading
import PySimpleGUI as sg
def func(window, value):
global running
message = f'You clicked the button "{value}", this message will be cleared after 3s !'
window.write_event_value('Update', message)
sleep(3)
window.write_event_value('Update', '')
running = False
sg.set_options(font=('Courier New', 12))
layout = [
[sg.Button('Hello'), sg.Button('World')],
[sg.Text('', size=80, key='State')],
]
window = sg.Window('Title', layout)
running = False
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event in ('Hello', 'World') and not running:
running = True
threading.Thread(target=func, args=(window, event), daemon=True).start()
elif event == 'Update':
message = values[event]
window['State'].update(message)
window.close()
I am new to PySimpleGui and wonder if the following concept can be applied.
I have to work with two scripts, one related to a GUI and a second one that it is a "Do Something Script".
I am interested in printing the status of an external loop in a window of my GUI Script
The GUIScript that I have coded as an example is the following:
import PySimpleGUI as sg
import MainScript
### GUI Script ###
layout = [
[sg.Text('My text 1 is: '), sg.Text('{}'.format('foo1'), key='-text1-')],
[sg.Text('My text 2 is: '), sg.Text('{}'.format('foo2'), key='-text2-')],
[sg.Text('Sweep number: '), sg.Text('{}'.format('0'), key='-SWEEP-')],
[sg.ProgressBar(max_value=40, orientation='horizontal', size=(50,20), key='-PRO_BAR-')],
[sg.Button("OK"), sg.Button("Cancel")],
]
window =sg.Window("Progress Bar",layout)
while True:
event, values = window.read()
if event == 'Cancel' or event == sg.WIN_CLOSED:
break
if event == "OK":
for s in range(50):
event, values = window.read(1000)
if event == 'Cancel':
break
window['-PRO_BAR-'].update(s+1)
window['-text1-'].update('my new text1')
window['-text2-'].update('my new text2')
window['-SWEEP-'].update(s)
window.refresh()
window.close()
The previous script works as "what I would like to have". I mean that the window['-PRO_BAR-'].update(s+1) and window['-SWEEP-'].update(s) update according to the s value of its own for-loop.
However, I would like to pick up the variable=i from the MainScript (which is the following), and use it back in the GUIScript.
##### MainScript ####
SWEEPS = 50
SWEEPS_LEN = list(range(1, SWEEPS+1))
for i in enumerate(SWEEPS_LEN):
print('sweep: {}'.format(i))
# Do something
# Save Data
Here, it is obvious that i=0, i=1, i=2.... I want to use these variables (that change in the loop) them as:
window['-PRO_BAR-'].update(i+1) and window['-SWEEP-'].update(i), such as the values update.
The GUIScript would show:
Sweep: 1
then i=2, updates and shows
Sweep: 2
then updates and...
Thanks.
I have OPEN and SAVE options on the right click menu which enables users to open or save selected multiple files in the ListBox output using PySimpleGui.. I am having errors to trigger those events.. Can you please help? Please refer to the code below I scripted but having errors.
import PySimpleGUI as sg
from tkinter.filedialog import asksaveasfile
from tkinter import *
import os
import threading
from time import sleep
from random import randint
def search(values, window):
"""Perform a search based on term and type"""
os.chdir('G:\MOTOR\DataExtracts/')
global results
# reset the results list
results.clear()
results = []
matches = 0 # count of records matched
records = 0 # count of records searched
window['-RESULTS-'].update(values=results)
window['-INFO-'].update(value='Searching for matches...')
# search for term and save new results
for root, _, files in os.walk(values['-PATH-']):
for file in files:
records +=1
if values['-ENDSWITH-'] and file.lower().endswith(values['-TERM-'].lower()):
results.append(f'{file}')
window['-RESULTS-'].update(results)
if values['-STARTSWITH-'] and file.lower().startswith(values['-TERM-'].lower()):
results.append(f'{file}')
window['-RESULTS-'].update(results)
if values['-CONTAINS-'] and values['-TERM-'].lower() in file.lower():
results.append(f'{file}')
window['-RESULTS-'].update(results)
matches += 1
window['-INFO-'].update('Enter a search term and press `Search`')
sg.PopupOK('Finished!') # print count of records of matched and searched in the popup(*)
def open_file(file_name):
# probably should add error handling here for when a default program cannot be found.(*)
# open selected files with read-only mode (check box or right click option)(*)
pass
def save_file(file_name):
# download selected files - one file or multiple files download at the same time (*)
# print downloading time or progress bar with downloaded files(*)
# print downloaded files logging info(*)
# create the main file search window
results = []
sg.change_look_and_feel('Black')
command = ['Open', 'Save']
cmd_layout = [[sg.Button(cmd, size=(10, 1))] for cmd in command]
layout = [
[sg.Text('Search Term', size=(11, 1)), sg.Input('', size=(40, 1), key='-TERM-'),
sg.Radio('Contains', group_id='search_type', size=(10, 1), default=True, key='-CONTAINS-'),
sg.Radio('StartsWith', group_id='search_type', size=(10, 1), key='-STARTSWITH-'),
sg.Radio('EndsWith', group_id='search_type', size=(10, 1), key='-ENDSWITH-')],
[sg.Text('Search Path', size=(11, 1)), sg.Combo(['ShdwProd/','Other/'],readonly=True, size=(38, 1), key='-PATH-', ), #display only folder name where files are located such as 'ShadowProd' and 'Ohter' in Combo
sg.Button('Search', size=(20, 1), key='-SEARCH-'),
sg.Button('Download', size=(20, 1), key='-DOWNLOAD-')],
[sg.Text('Enter a search term and press `Search`', key='-INFO-')],
[sg.Listbox(values=results, size=(100, 28), bind_return_key = True, enable_events=True, key='-RESULTS-', right_click_menu=['&Right', command])],
[sg.Help(key='-HELP-')]]
window = sg.Window('File Search Engine', layout=layout, finalize=True, return_keyboard_events=True)
window['-RESULTS-'].Widget.config(selectmode = sg.LISTBOX_SELECT_MODE_EXTENDED)
window['-RESULTS-'].expand(expand_x=True, expand_y=True)
# main event loop
while True:
event, values = window.read()
if event is None:
break
if event == '-SEARCH-':
search(values, window)
if event == '-RESULTS-' and len(values['-RESULTS-']):
if event == '-OPEN-': # need to code(*)
pass
if event == '-DOWNLOAD-': # need to code(*)
pass
if event == '-HELP-':
sg.Popup("My help message")
the (*) marks are what I am not sure about and having errors from..
Code revised as following
import os
import threading
from time import sleep
from random import randint
import PySimpleGUI as sg
def search(values, window):
"""Perform a search based on term and type"""
os.chdir("G:/MOTOR/DataExtracts/")
global results
# reset the results list
results = []
matches = 0 # count of records matched
records = 0 # count of records searched
window['-RESULTS-'].update(values=results)
window['-INFO-'].update(value='Searching for matches...')
window.refresh()
# search for term and save new results
for root, _, files in os.walk(values['-PATH-']): # path information of file missed here
for file in files:
records +=1
if any([values['-ENDSWITH-'] and file.lower().endswith(values['-TERM-'].lower()),
values['-STARTSWITH-'] and file.lower().startswith(values['-TERM-'].lower()),
values['-CONTAINS-'] and values['-TERM-'].lower() in file.lower()]):
results.append(f'{file}')
matches += 1
window['-RESULTS-'].update(results)
window['-INFO-'].update('Enter a search term and press `Search`')
window.refresh()
sg.PopupOK('Finished!') # print count of records of matched and searched in the popup(*)
def open_files(filenames):
"""
probably should add error handling here for when a default program cannot be found.(*)
open selected files with read-only mode (check box or right click option)(*)
"""
def save_files(filenames):
"""
download selected files - one file or multiple files download at the same time (*)
print downloading time or progress bar with downloaded files(*)
print downloaded files logging info(*)
"""
# create the main file search window
results = []
sg.theme('Black')
command = ['Open', 'Save']
cmd_layout = [[sg.Button(cmd, size=(10, 1))] for cmd in command]
layout = [
[sg.Text('Search Term', size=(11, 1)),
sg.Input('', size=(40, 1), key='-TERM-'),
sg.Radio('Contains', group_id='search_type', size=(10, 1), key='-CONTAINS-', default=True),
sg.Radio('StartsWith', group_id='search_type', size=(10, 1), key='-STARTSWITH-'),
sg.Radio('EndsWith', group_id='search_type', size=(10, 1), key='-ENDSWITH-')],
[sg.Text('Search Path', size=(11, 1)),
sg.Combo(['ShdwProd/','Other/'], default_value='ShdwProd/', readonly=True, size=(38, 1), key='-PATH-', ), #display only folder name where files are located such as 'ShadowProd' and 'Ohter' in Combo
sg.Button('Search', size=(20, 1), key='-SEARCH-'),
sg.Button('Download', size=(20, 1), key='-DOWNLOAD-')],
[sg.Text('Enter a search term and press `Search`', key='-INFO-')],
[sg.Listbox(values=results, size=(100, 28), select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, bind_return_key = True, enable_events=True, key='-RESULTS-', right_click_menu=['&Right', command], expand_x=True, expand_y=True)],
[sg.Help(key='-HELP-')]]
window = sg.Window('File Search Engine', layout=layout, finalize=True, return_keyboard_events=True)
# main event loop
while True:
event, values = window.read()
print(event, values)
if event == sg.WINDOW_CLOSED:
break
elif event == '-SEARCH-':
search(values, window)
elif event == '-RESULTS-' and len(values['-RESULTS-']):
pass
elif event == 'Open': # need to code(*)
open(values['-RESULTS-'])
elif event == 'Save': # need to code(*)
save(values['-RESULTS-'])
elif event == '-DOWNLOAD-': # need to code(*)
print(values['-RESULTS-'])
elif event == '-HELP-':
sg.Popup("My help message")
window.close()
In my code, Im trying to make a calculator. So there is a 1 button which when pressed, updates the Question: text by adding 1 to it's text. So when I press 1, the text will convert from Question: to Question: 1. But its not updating. I have faced this problem before too. I think when I do the .update, it will only update the value till its the same number of letters as the text already has. If it has 2 letters and I try to .update('123'), it will only update to 12. Is there any way to get around this???
import PySimpleGUI as sg
layout = [
[sg.Text('Question: ', key='-IN-')],
[sg.Text('Answer will be shown here', key='-OUT-')],
[sg.Button('1'), sg.Button('2'), sg.Button('3')],
[sg.Button('4'), sg.Button('5'), sg.Button('6')],
[sg.Button('7'), sg.Button('8'), sg.Button('9')],
[sg.Button('Enter'), sg.Button('Exit')]
]
window = sg.Window('calculator', layout)
while True:
event, values = window.read()
if event is None or event == 'Exit':
break
elif event == '1':
bleh = window['-IN-'].get()
teh = f'{bleh}1'
window['-IN-'].update(value=teh)
window.close()
As above comment, Example like this,
import PySimpleGUI as sg
layout = [
[sg.InputText('Question: ', readonly=True, key='-IN-')],
[sg.Text('Answer will be shown here', key='-OUT-')],
[sg.Button('1'), sg.Button('2'), sg.Button('3')],
[sg.Button('4'), sg.Button('5'), sg.Button('6')],
[sg.Button('7'), sg.Button('8'), sg.Button('9')],
[sg.Button('Enter'), sg.Button('Exit')]
]
window = sg.Window('calculator', layout)
input = window['-IN-']
while True:
event, values = window.read()
if event is None or event == 'Exit':
break
elif event in '1234567890':
bleh = window['-IN-'].get()
teh = f'{bleh}{event}'
input.update(value=teh)
input.Widget.xview("end") # view end if text is too long to fit element
window.close()
First, I have read the docs. I understand that the information is stored in Key= x. My issue is when I call a function from another file it does not recognize x.
I have read the docs, but failing to understand how to use the key
I tried putting x into a variable and passing it to the function.
File 1
def add_details():
today1 = date.today()
today2 = today1.strftime("%Y/%m/%d")
create = str(today2)
name = str(_name_)
reason = str(_reason_)
startDate = str(_startDate_)
endDate = str(_endDate_)
add_data(create,name,reason,startDate, endDate)
def add_data(create,name,reason,startDate, endDate):
engine.execute('INSERT INTO schedule(Created_On, Fullname, reason, Start_Date, End_Date ) VALUES (?,?,?,?,?)',(create,name,reason,startDate,endDate))
File 2
while True:
event, values = window.Read()
print(event, values)
if event in (None, 'Exit'):
break
if event == '_subdate_': #subdate is the button Submit
sf.add_details()
My expected results are that the inputs of the GUI are passed to the function, then off to a SQLite db.
Error: name 'name' not defined
(or any key variable)
This is an example that you'll find running on Trinket (https://pysimplegui.trinket.io/demo-programs#/demo-programs/design-pattern-2-persistent-window-with-updates)
It shows how keys are defined in elements and used after a read call.
import PySimpleGUI as sg
"""
DESIGN PATTERN 2 - Multi-read window. Reads and updates fields in a window
"""
# 1- the layout
layout = [[sg.Text('Your typed chars appear here:'), sg.Text(size=(15,1), key='-OUTPUT-')],
[sg.Input(key='-IN-')],
[sg.Button('Show'), sg.Button('Exit')]]
# 2 - the window
window = sg.Window('Pattern 2', layout)
# 3 - the event loop
while True:
event, values = window.read()
print(event, values)
if event in (None, 'Exit'):
break
if event == 'Show':
# Update the "output" text element to be the value of "input" element
window['-OUTPUT-'].update(values['-IN-'])
# In older code you'll find it written using FindElement or Element
# window.FindElement('-OUTPUT-').Update(values['-IN-'])
# A shortened version of this update can be written without the ".Update"
# window['-OUTPUT-'](values['-IN-'])
# 4 - the close
window.close()