import random
import PySimpleGUI as sg
def password_generator(pw_len):
password = "".join(random.sample(chars, pw_len))
return password
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|!\"£$%&/()=?^é*ç°§;:_è+òàù,.-[]##{}"
sg.theme('DarkPurple3')
layout = [[sg.Text('Password Generator', font=('Roboto', 20), justification='center')],
[sg.Text('Set password length: ', size=(15, 1)), sg.InputText(size=(15, 1), key='length')],
[sg.Text(size=(40,1), key='-OUTPUT-'), ],
[sg.Button('Generate', size=(15, 1)), sg.Button('Exit', size=(15, 1))]]
window = sg.Window('Password Generator', layout)
while(True):
event, values = window.read()
if event == 'Exit':
break
elif event == 'Generate' or sg.WINDOW_CLOSED:
pw_len = int(values['length'])
window['-OUTPUT-'].update('Your password: ' + password_generator(pw_len))
window.close()
Code Output: password generator
Im trying to make a password generator that generate a passoword from the length chosen by the user. Everything works but i cant make the output text copyable, can someone explain me how to do it? Thank you in advance
The content of Text element cannot be selected and not copyable.
Using Input or Multiline element for it and set disabled=True.
For example
sg.Input(size=(10,1), disabled=True, text_color=sg.theme_text_color(), disabled_readonly_background_color=sg.theme_text_element_background_color(), key='-OUTPUT-')
Related
GitHub for this project
I am building a financial trading profit/loss calculator. I have built the script to function in the command line interface (main_cli.py).
Now, I am trying to convert to a desktop GUI via PySimpleGUI, but am having difficulty with passing multiple user input values from PySimpleGUI (main_gui.py) to the calculator function (functions.py), to then output the result in the same PySimpleGUI window.
When I run the main_gui.py script, it still asks for user_input in the CLI.
Just pass values to your function, then convert all fields into your data for the function to calculate the result, and return it back to event loop to update the GUI.
Note: No any entry validation in the code.
import PySimpleGUI as sg
def calculate(values):
ticker = ticker_list[[values[("Ticker", i)] for i in range(len(tickers))].index(1)]
tick_size, contract_amount = tickers[ticker]
position = "Long" if values[("Position", 0)] else "Short"
purchase_price = float(values['Entry'])
selling_price = float(values['Exit'])
contract_size = float(values['Contract'])
tick_value = (((purchase_price - selling_price)*contract_size)/tick_size)
dollar_value = (tick_value*contract_amount)
if position == "Long":
tick_value = abs(tick_value)
dollar_value = abs(dollar_value)
return tick_value, dollar_value
tickers = {
'ES' : (0.25, 12.50),
'NQ' : (0.25, 5.00),
'RTY': (0.10, 5.00),
'YM' : (1.00, 5.00),
'GC' : (0.10, 10.00),
'CL' : (0.01, 10.00),
}
ticker_list = list(tickers.keys())
positions = ['Long', 'Short']
keys = {
'Entry':'Entry price',
'Exit':'Exit price',
'Contract':'Contract size',
}
sg.theme('Dark')
sg.set_options(font=('Helvetica', 10))
layout = [
[sg.Text("Ticker:", size=10)] + [sg.Radio(tick, "Radio 1", key=("Ticker", i)) for i, tick in enumerate(tickers)],
[sg.Text("Position:", size=10)] + [sg.Radio(pos, "Radio 2", key=("Position", i)) for i, pos in enumerate(positions)]] + [
[sg.Text(text, size=10), sg.InputText(size=10, expand_x=True, key=key)] for key, text in keys.items()] + [
[sg.Text("Result"), sg.Text(text_color="white", key="Output")],
[sg.Push(), sg.Button("Reset"), sg.Button("Calculate", button_color=('white', '#007339'))],
]
window = sg.Window('Futures Profit/Loss Calculator', layout=layout)
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED:
break
elif event == "Calculate":
tick_value, dollar_value = calculate(values)
result = f"ticks: {tick_value} | profit/loss: ${dollar_value}"
window['Output'].update(result)
elif event == "Reset":
for key in keys:
window[key].update('')
window.close()
If this function take long time to finish the caluclation, you can call method window.perform_long_operation to run your function, Lambda expression can help to pass the arguments here, then update your GUI when the event '-FUNCTION COMPLETED-' generated, like
elif event == "Calculate":
window.perform_long_operation(lambda x=values:calculate(x), '-FUNCTION COMPLETED-')
elif event == '-FUNCTION COMPLETED-':
tick_value, dollar_value = values[event]
result = f"ticks: {tick_value} | profit/loss: ${dollar_value}"
window['Output'].update(result)
I made a little barcode making GUI project for fun and when the "clear" function takes place it deletes the text in the "SaveAs" button. All other buttons have no issues with this and I was trying to avoid putting a line of code for each key to clear. I made some minor changes to the code before pasting it here so I know that the if len(values['Area']) > 0: window.perform_long_operation(lambda: get_barcode(),'Saved Pop') needs to be updated as of now this would always be true. I forgot when I added the combo box and set a default value you this would be true. Also if anyone could tell me why I have to have "lambda" above although I'm not passing a parameter?
Update 10:45 CT - I compiled the program and and the program is not saving correctly/not at all. If I put in a name like "test1" it should be saved as test1.pdf at the location I specified. When I go to the location the file does not exist but if I search the C drive it shows up but it cannot be located almost as if it is deleted the moment it is created. This only happens when I compile the program.
import PySimpleGUI as sg
import string
pixel_size = [64,128,192,256]
tab1_layout = [
[sg.Text('Area Letter:', size=(28,1)), sg.Combo(list(string.ascii_uppercase[:]), default_value= 'A',key='Area')],
[sg.Text('Start Number Range:', size=(28,1)), sg.InputText(key='start_number')],
[sg.Text('End Number Range:', size=(28,1)), sg.InputText(key='end_number')],
]
tab2_layout = [
[sg.Text('Single Barcode ABC123:', size=(28,1)), sg.InputText(key='single_bc')],
[sg.Text('Number of Single Barcode Replicas:', size=(28,1)), sg.InputText(default_text= 1,key='number_of_barcodes')],
]
layout = [
[sg.Text('Barcode Font Size in Pixels'), sg.Combo(pixel_size, default_value=64, s=(15,22), enable_events=True, readonly=True, key='PIXEL')],
[sg.TabGroup([[sg.Tab('Range of Barcodes', tab1_layout), sg.Tab('Single Barcodes', tab2_layout)]])],
[[sg.Input(key = 'input_loc'), sg.SaveAs(target= 'input_loc' , default_extension= '.pdf')]],
[sg.Submit(),sg.Button('Clear'), sg.Exit(),]
]
def get_barcode():
print('get barcode')
window = sg.Window('Barcode Maker', layout, font=("Helvetica", 12))
def clear_input():
for key in values:
window[key]('')
window['Area']('A')
window['PIXEL'](64)
window['number_of_barcodes'](1)
return None
while True:
event, values = window.read(timeout = 10)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Clear':
clear_input()
if event == 'Submit':
save_location = values['input_loc']
if len(values['Area']) > 0:
window.perform_long_operation(lambda: get_barcode(),'Saved Pop')
elif len(values['single_bc']) >=1:
bc_size = values['PIXEL']
single_code = values['single_bc'].upper()
replicas = values['number_of_barcodes']
replicas = int(replicas)
start_rep = 0
while start_rep < replicas:
layout_borb1.add(Barcode(data=single_code, type=BarcodeType.CODE_128, width=Decimal(bc_size), height=Decimal(bc_size),))
with open(save_location, 'wb') as pdf_file_handle:
PDF.dumps(pdf_file_handle, doucment)
start_rep +=1
clear_input()```
Following code in your function clear_input clear the value of all the elements which with the key in values.
for key in values:
window[key]('')
The key of element in values not only Input, Combo elements, also Tab, TabGroup and Button elements.
>>> values
{'PIXEL': 64, 'Area': 'A', 'start_number': '', 'end_number': '', 'single_bc': '', 'number_of_barcodes': '1', 0: 'Range of Barcodes', 'input_loc': '', 'Save As...': ''}
The key in values include the key of button Save As..., that's why the text of this button also cleared.
There should be a rule to specify which elements to be cleared, like
for key, element in window.key_dict.items():
if isinstance(element, (sg.Input, sg.Combo)):
element.update(value='')
Using lambda to define a function without arguments is almost the same as the function name.
window.perform_long_operation(get_barcode,'Saved Pop')
If possible, reduce your code to only with related issues and an executable code, like
import PySimpleGUI as sg
import string
pixel_size = [64,128,192,256]
tab1_layout = [
[sg.Text('Area Letter:', size=(28,1)), sg.Combo(list(string.ascii_uppercase[:]), default_value= 'A',key='Area')],
[sg.Text('Start Number Range:', size=(28,1)), sg.InputText(key='start_number')],
[sg.Text('End Number Range:', size=(28,1)), sg.InputText(key='end_number')],
]
tab2_layout = [
[sg.Text('Single Barcode ABC123:', size=(28,1)), sg.InputText(key='single_bc')],
[sg.Text('Number of Single Barcode Replicas:', size=(28,1)), sg.InputText(default_text= 1,key='number_of_barcodes')],
]
layout = [
[sg.Text('Barcode Font Size in Pixels'), sg.Combo(pixel_size, default_value=64, s=(15,22), enable_events=True, readonly=True, key='PIXEL')],
[sg.TabGroup([[sg.Tab('Range of Barcodes', tab1_layout), sg.Tab('Single Barcodes', tab2_layout)]])],
[[sg.Input(key = 'input_loc'), sg.SaveAs(target= 'input_loc' , default_extension= '.pdf')]],
[sg.Submit(),sg.Button('Clear'), sg.Exit(),]
]
def get_barcode():
print("get bar_code function called")
window = sg.Window('Barcode Maker', layout, font=("Helvetica", 12))
def clear_input():
for key, element in window.key_dict.items():
if isinstance(element, (sg.Input, sg.Combo)):
element.update(value='')
window['Area']('A')
window['PIXEL'](64)
window['number_of_barcodes'](1)
return
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Clear':
clear_input()
elif event == 'Submit':
save_location = values['input_loc']
if len(values['Area']) > 0:
window.perform_long_operation(get_barcode,'Saved Pop')
clear_input()
elif event == 'Saved Pop':
print("get_barcode complete")
window.close()
For some conditions, like element.taget==(None, None) or element.Key is not None, "chooser" Buttons will hold the information of selection in the dictionary values which returned from window.read().
"chooser" Buttons with any one of following button_type:
BUTTON_TYPE_COLOR_CHOOSER
BUTTON_TYPE_SAVEAS_FILE
BUTTON_TYPE_BROWSE_FILE
BUTTON_TYPE_BROWSE_FILES
BUTTON_TYPE_BROWSE_FOLDER
BUTTON_TYPE_CALENDAR_CHOOSER
Function SaveAs defined as a Button element with file_types=FILE_TYPES_ALL_FILES.
How do you distinguish between multiple elements on the same window when using right_click_menu in PySimpleGUI? For example, with the code below, how do I tell which one of the two InputText elements I am trying to use the right_click_menu with? If I copy something to the clipboard and then right-click 'Paste' on one of the Input fields, the same data will appear in both fields. When I right-click on one of the InputText fields, how can I write the code to identify which one I'm on?:
import PySimpleGUI as sg
INPUT1 = 'INPUT1'
INPUT2 = 'INPUT2'
right_click_menu = ['',['Paste']]
layout = [
[sg.Text('Input1'), sg.InputText('', key='INPUT1', right_click_menu = right_click_menu)],
[sg.Text('Input2'), sg.InputText('', key='INPUT2', right_click_menu = right_click_menu)],
[sg.Button(' OK '), sg.Button(' Exit ')]
]
window = sg.Window('Multiple Elements', layout)
input1:sg.InputText = window[INPUT1]
input2:sg.InputText = window[INPUT2]
while True:
event, values = window.read()
if event in (' Exit ', None):
break
if event == 'Paste':
# How to tell whether I am right-clicking on INPUT1 or INPUT2?
# With just one Input element, I could just do this:
input1.Widget.insert(sg.tk.INSERT, window.TKroot.clipboard_get())
# What do I do when there is a second InputText field?
# Below won't work because I'll get the same text pasted into both fields.
input2.Widget.insert(sg.tk.INSERT, window.TKroot.clipboard_get())
if event == ' OK ':
pass
#Do blah
window.close()
Refer https://pysimplegui.readthedocs.io/en/latest/#keys-for-menus
A key is indicated by adding :: after a menu entry, followed by the key.
import PySimpleGUI as sg
INPUT1 = 'INPUT1'
INPUT2 = 'INPUT2'
right_click_menu = [['',[f'Paste::Paste {i}']] for i in range(2)]
layout = [
[sg.Text('Input1'), sg.InputText('', key='INPUT1', right_click_menu = right_click_menu[0])],
[sg.Text('Input2'), sg.InputText('', key='INPUT2', right_click_menu = right_click_menu[1])],
[sg.Button(' OK '), sg.Button(' Exit ')]
]
window = sg.Window('Multiple Elements', layout)
input1:sg.InputText = window[INPUT1]
input2:sg.InputText = window[INPUT2]
while True:
event, values = window.read()
if event in (' Exit ', None):
break
if event.startswith('Paste'):
element = input1 if event.split()[1] == '0' else input2
element.Widget.insert(sg.tk.INSERT, window.TKroot.clipboard_get())
window.close()
I have to make a program to teach children multipliers, this is the core code of the assignment.
#include <stdio.h>
#define MIN 1
#define MAXINDEX 10
#define MAXTABLE 10
#define STEP 1
void main(void)
{
int i,j ;
for (j = MIN; j <MAXTABLE; j += STEP) {
for (i = MIN; i <= MAXINDEX; i += STEP)
printf(“%3d * %3d = %3d\n”, i, j, i*j);
printf(“\n---------------\n\n”);
}
for (i = MIN; i <= MAXINDEX; i += STEP)
printf(“%3d * %3d = %3d\n”, i, MAXTABLE, i*MAXTABLE);
}
After I have to rewrite it to a next generation language so I designed to write it in python.
Like this
j=1
i=1
for j in range(1,11):
for i in range(1,11):
print('%3d * %3d =%3d' % (i, j, i *j))
if j!=10:
print("\n---------------\n")
else:
print("\n")
And after that I have to make a UI for it so this image is what I designed to do like this This is the design of me
Since I just study python for 3 days, so I try my best to write this:
import PySimpleGUI as sg
import os.path
def Corecode():
j=1
i=1
for j in range(1,11):
for i in range(1,11):
print('%3d * %3d =%3d' % (i, j, i *j))
if j!=10:
print("\n---------------\n")
else:
print("\n")
from PySimpleGUI.PySimpleGUI import R, Image, Multiline
showrobot_column = [
[sg.Image('E:\img\robot.png',size = (300,300))],
],
show_Textbox_selectbox = [
[sg.Multiline(size=(50,20),key='-def-')],
[sg.Listbox(values=['a','b','c','d'], enable_events=True, size=(50,20), key="")]
]
layout = [
[sg.Column(showrobot_column),
sg.VSeparator(),
sg.Column(show_Textbox_selectbox)
]
]
window = sg.Window("First Test",layout)
while True:
event, value = window.read()
if event == sg.WIN_CLOSED:
break
window.close()
I designed to make it like a robot is talking and let the children interact by buttonBut, but I find out I can't insert the image, and also I can't find a way to print the Multiplier table by the core code that on the front, so someone can help me to finish the code or tell me why the sg.image get error. TY
Try this,
import PySimpleGUI as sg
def corecode(base):
return ("\n"+"-"*13+"\n").join([f'{i+1:>2d} * {base:>2d} = {(i+1)*base:>3d}' for i in range(10)])
sg.theme('DarkBlue3')
sg.set_options(font=("Courier New", 12))
showrobot_column = [
[sg.Image('E:/img/robot.png', size = (300, 300))],
]
list_values = [f'{i+1:>2d}' for i in range(10)]
show_Textbox_selectbox = [
[sg.Multiline(size=(15, 20), expand_y=True, key='-MULTILINE-')],
[sg.Listbox(values=list_values, enable_events=True, size=(15, 10), key="-LISTBOX-")],
]
layout = [
[sg.Column(showrobot_column),
sg.VSeparator(),
sg.Column(show_Textbox_selectbox),],
]
window = sg.Window("First Test", layout, finalize=True)
multiline = window['-MULTILINE-']
multiline.update(value=corecode(1))
listbox = window['-LISTBOX-']
listbox.update(set_to_index=0)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == '-LISTBOX-':
base = int(values[event][0])
multiline.update(value=corecode(base))
window.close()
This is a shameless small tweak to Jason's answer (choose his as it's correct).
Wanted to include a couple of capabilities that may be helpful to some. One is that almost all elements have an initial value that you can set in your layout instead of finalizing it and then setting them. It reduces code.
I'm also including a "Trinket" embedded in this answer as a test. This way you can run the example on this StackOverflow page.
import PySimpleGUI as sg
def corecode(base):
return ("\n"+"-"*13+"\n").join([f'{i+1:>2d} * {base:>2d} = {(i+1)*base:>3d}' for i in range(10)])
sg.theme('DarkBlue3')
list_values = [f'{i+1:>2d}' for i in range(10)]
show_Textbox_selectbox = [[sg.Multiline(default_text=corecode(1), size=(15, 20), expand_y=True, key='-MULTILINE-')],
[sg.Listbox(values=list_values, default_values=[list_values[0]], enable_events=True, size=(15, 10), key="-LISTBOX-")]]
layout = [
[sg.Image(sg.EMOJI_BASE64_HAPPY_THUMBS_UP), sg.VSeparator(), sg.Column(show_Textbox_selectbox)]
]
window = sg.Window("First Test", layout, font='Courier 12')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == '-LISTBOX-':
base = int(values[event][0])
window['-MULTILINE-'].update(value=corecode(base))
window.close()
Here is a link to the Trinket should it not embed correctly - https://trinket.io/pygame/d59ef3b352
<iframe src="https://trinket.io/embed/pygame/d59ef3b352" width="100%" height="600" frameborder="0" marginwidth="0" marginheight="0" allowfullscreen></iframe>
I am trying to dynamically assign keys using pysimplegui. A simple example is updating a text field when a folder is selected.
When the layout contains two elements in each row, the text field updates correctly. However adding a third element results in the text box not updating.
import PySimpleGUI as sg
layout = []
elements = ["one", "two", "three"]
for element in elements:
text = f"text_{element}"
folder = f"folder_{element}"
check = f"check_{element}"
layout.append([sg.FolderBrowse(key = folder), sg.Text(key = text, size=(50, 1))])
#layout.append([sg.FolderBrowse(key = folder), sg.Text(key = text, size=(50, 1)), sg.Checkbox(element, key=check)])
#layout.append([sg.FolderBrowse(key = folder), sg.Text(key = text, size=(50, 1)), sg.Text(element, key=check)])
layout.append([sg.Button('Show'), sg.Cancel()])
window = sg.Window("GUI", layout)
while(True):
event, values = window.read()
if event in (None, 'Cancel'):
break
print(values)
for element in elements:
text = f"text_{element}"
folder = f"folder_{element}"
values[text] = values[folder]
window.close()
Thanks to MikefromPSG, using the target param worked:
layout.append([sg.FolderBrowse(target = text), sg.Text(key = text, size=(50, 1)), sg.Checkbox(element, key=check)])