Update Values in PySimpleGui from external script - python

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.

Related

table rows not showing properly, only one row is displayed after running

i have written the right code in python simple gui, but after running the code, only one row is displayed and the whole table is not shown i dont know why.this is what is displayed after running the code.
import PySimpleGUI as sg
rows=[
["CULTUS","4","3500","300","550"],
["SONATA","3","5000","350","750"],
["KIA Sportage","3","6000","500","700"],
["Yaris","5","4000","300","600"],
["HONDA CIVIC","5","5500","300","600"],
["Pajero","2","7000","500","700"]
]
header =[
["Model", "Available", "Price/Day","Liability Insurance/Day", "Comprehensive Insurance/Day"]
]
layout=[[sg.Table(
values=rows,
headings=header,
size=(500,300),
key="-TABLE-",)
],
[sg.OK(),sg.Cancel()]
]
window = sg.Window('TG Enterprises', layout ,size=(600,400))
event, values = window.read()
if event == 'Cancel':
window.close()
print(event,values)
this is my code ,can anyone please help me what is wrong with this code and what can i do to make it right?
I cut out some of the text to make it easier to comprehend, but basically it turns out that your attempt was very close.
The main error was the header was a list containing a list. whereas it should just have been a list.
so using boilerplate i made a working example for you like this:
import PySimpleGUI as sg
rows=[
["CULTUS","4","3500","300","550"],
["SONATA","3","5000","350","750"],
["KIA Sportage","3","6000","500","700"],
["Yaris","5","4000","300","600"],
["HONDA CIVIC","5","5500","300","600"],
["Pajero","2","7000","500","700"]
]
header =["Model", "Available", "Price","Liability", "Comprehensive"]
layout = [[sg.Text(x) for x in header],
[sg.Table(values=rows,
headings=header,
max_col_width=25,
auto_size_columns=True,
justification='right',
alternating_row_color='lightblue',
key='table')],
[sg.Button('Add'), sg.Button('Delete')]]
window = sg.Window('Table example').Layout(layout)
while True:
event, values = window.Read()
if event is None:
break
print(event, values)
window.Close()
and the result looks like this:
note: I didnt try out the buttons or any other logic. I just provided an example of the correct formatting example.

hide_row() in pysimplegui work only one time?

I use hide_row() element or feature in my code to hide row but it work only one time when i connected to Retreat button or Retreat key, when i clicked again or in the 2nd time it's not work (see the code or try it to understand what i mean) how make it work continuously not only one time or is there another way to undo or delete section or row.
import PySimpleGUI as sg
layout = [
[sg.Col([[sg.T('Enter your name:'),sg.In()],[sg.Btn('Ok'), sg.Btn('Exit'),
sg.Btn('Add new row')]],k='col_key')]
]
window = sg.Window('Test', layout)
while True:
event, values = window.read()
if event in ('Exit' ,sg.WIN_CLOSED):
break
if event == ('Add new row'):
window.extend_layout(window['col_key'],[[sg.T('Enter your name:', key='new_raw'),(sg.In())]])
window.extend_layout(window['col_key'],[[sg.Btn('Retreat', key='re')]])
if event == ('re'):
window['new_raw'].hide_row()
window['re'].hide_row()
window.close()
It is caused by new element with duplicate key when add new row again, so it wll always find the first element when you call window[new_key].
Should use different key for different element when you create a new element.
Key of new element will be replace by
element.Key = str(element.Key) + str(self.UniqueKeyCounter)
So key for new elements will be
'new_raw', 're', 'new_raw0', 're1', 'new_raw2', 're3', 'new_raw4', 're5', ...
you can check it by
>>> window.key_dict
{
...
'new_raw': <PySimpleGUI.PySimpleGUI.Text object at 0x000001D3A5B80FA0>,
'new_raw0': <PySimpleGUI.PySimpleGUI.Text object at 0x000001D3A6FA1280>,
'new_raw2': <PySimpleGUI.PySimpleGUI.Text object at 0x000001D3A6FA1220>,
're': <PySimpleGUI.PySimpleGUI.Button object at 0x000001D3A6FA1CD0>,
're1': <PySimpleGUI.PySimpleGUI.Button object at 0x000001D3A6FA1340>,
're3': <PySimpleGUI.PySimpleGUI.Button object at 0x000001D3A6FA11F0>}
After new row generated, the key of button Retreat is not 're', but starts with 're' and ends with an index.
Update code as following
import PySimpleGUI as sg
layout = [
[sg.Col([[sg.T('Enter your name:'),sg.In()],[sg.Btn('Ok'), sg.Btn('Exit'),
sg.Btn('Add new row')]],k='col_key')]
]
window = sg.Window('Test', layout)
index = 0
while True:
event, values = window.read()
if event in ('Exit' ,sg.WIN_CLOSED):
break
if event == ('Add new row'):
window.extend_layout(window['col_key'],[[sg.T('Enter your name:', key=f'new_raw {index}'),(sg.In(key=f'input {index}'))]])
window.extend_layout(window['col_key'],[[sg.Btn('Retreat', key=f're {index}')]])
index += 1
if event.startswith('re'):
i = event.split(' ')[-1]
window[f'new_raw {i}'].hide_row()
window[f're {i}'].hide_row()
window.close()
There's still problem for old rows hidden will still be kept in memory, so occupied memory will grow higher and higher if you add new row again and again, but it's not question to be discussed here.

Text not updating in PySimpleGui

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

Button Non-Event-Driven Model

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

Maya window adding a row dynamically with python

I've been working on this for a while and I can't find any information about adding a row to a window. I seen it done with pyside2 and qt, witch would work but the users are using multiple versions of Maya (2016 = pyside, 2017=pyside2).
I want it like adding a widget in in pyside. I done it where adding a row is a function like add row 1, add row 2, and add row 3 but the script get to long. I need to parent to rowColumnLayout and make that unique in order to delete that later. Also I have to query the textfield in each row. Maybe a for loop that adds a number to the row? I really don't know but this is what I have so far:
from maya import cmds
def row( ):
global fed
global info
item=cmds.optionMenu(mygroup, q=True, sl=True)
if item == 1:
cam=cmds.optionMenu(mygroup, q=True, v=True)
fed=cmds.rowColumnLayout(nc = 1)
cmds.rowLayout(nc=7)
cmds.text(l= cam )
cmds.text(l=u'Frame Range ')
start = cmds.textField('textField3')
cmds.text(l=u' to ')
finish = cmds.textField('textField2')
cmds.button(l=u'render',c='renderTedd()')
cmds.button(l=u'delete',c='deleteRow()')
cmds.setParent (fed)
def deleteRow ():
cmds.deleteUI(fed, layout=True)
if item == 2:
print item
global red
cam1=cmds.optionMenu(mygroup, q=True, v=True)
red = cmds.rowColumnLayout()
cmds.rowLayout(nc=7)
cmds.text(l= cam1 )
cmds.text(l=u'Frame Range ')
start = cmds.textField('textField3')
cmds.text(l=u' to ')
finish = cmds.textField('textField2')
cmds.button(l=u'render',c='renderTedd()')
cmds.button(l=u'delete',c='deleteRow2()')
cmds.setParent (red)
def deleteRow2 ():
cmds.deleteUI(red, control=True)
def cameraInfo():
info=cmds.optionMenu(mygroup, q=True, sl=True)
print info
def deleteRow ():
cmds.deleteUI(fed, control=True)
def getCamera():
layers=pm.ls(type="renderLayer")
for layer in layers:
pm.editRenderLayerGlobals(currentRenderLayer=layer)
cameras=pm.ls(type='camera')
for cam in cameras:
if pm.getAttr(str(cam) + ".renderable"):
relatives=pm.listRelatives(cam, parent=1)
cam=relatives[0]
cmds.menuItem(p=mygroup,label=str (cam) )
window = cmds.window()
cmds.rowColumnLayout(nr=10)
mygroup = cmds.optionMenu( label='Colors', changeCommand='cameraInfo()' )
getCamera()
cmds.button(l=u'create camera',aop=1,c='row ()')
cmds.showWindow( window )
This is totally doable with cmds. The trick is just to structure the code so that the buttons in each row know and can operate on the widgets in that row; once that works you can add rows all day long.
To make it work you want to do two things:
Don't use the string form of callbacks. It's never a good idea, for reasons detailed here
Do use closures to make sure your callbacks are referring to the right widgets. Done right you can do what you want without the overhead of a class.
Basically, this adds up to making a function which generates both the gui items for the row and also generates the callback functions -- the creator function will 'remember' the widgets and the callbacks it creates will have access to the widgets. Here's a minimal example:
def row_test():
window = cmds.window(title='lotsa rows')
column = cmds.columnLayout()
def add_row(cameraname) :
cmds.setParent(column)
this_row = cmds.rowLayout(nc=6, cw6 = (72, 72, 72, 72, 48, 48) )
cmds.text(l= cameraname )
cmds.text(l=u'Frame Range')
start = cmds.intField()
finish = cmds.intField()
# note: buttons always fire a useless
# argument; the _ here just ignores
# that in both of these callback functions
def do_delete(_):
cmds.deleteUI(this_row)
def do_render(_):
startframe = cmds.intField(start, q=True, v=True)
endframe = cmds.intField(finish, q=True, v=True)
print "rendering ", cameraname, "frames", startframe, endframe
cmds.button(l=u'render',c=do_render)
cmds.button(l=u'delete',c=do_delete)
for cam in cmds.ls(type='camera'):
add_row(cam)
cmds.showWindow(window)
row_test()
By defining the callback functions inside of add_row(), they have access to the widgets which get stored as start and finish. Even though start and finish will be created over and over each time the function runs, the values they store are captured by the closures and are still available when you click a button. They also inherit the value of cameraname so the rendering script can get that information as well.
At the risk of self-advertising: if you need to do serious GUI work using cmds you should check out mGui -- a python module that makes working with cmds gui less painful for complex projects.

Categories

Resources