Any one help me code finish this by PySimpleGUI - python

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>

Related

How to make progress bar work using PySimpleGUI in Python?

I am using PySimpleGui's one-line progress meter to show the files processed while my main function is running. It is working for the most part, however when I change the parameter from value of 1000 to my variable total_files it just flickers and never stays on screen. It's only when I keep the parameter to a value of 1000 does the screen stay put...but I want to just show the progress of the true amount of files processed.
For example, I have 8 files I am processing as a test. I want the progress bar to stay on the screen and just show those 8 files processed. Does anyone know what I'm doing wrong?
Documentation on progress meter:
https://www.pysimplegui.org/en/latest/#progress-meters
for i in range(1,total_files):
sg.one_line_progress_meter('Loading...', i+1, 1000, 'key','Files Processed', orientation="horizontal")
Below is my code:
import PySimpleGUI as sg, pandas as pd, os, time
from pathlib import (
Path,
)
def convert_to_csv(input_folder, output_folder, dataframe2, dataframe3):
start = time.time()
# Parentsupplierbrand mapping file. Change the filepath to where the file is stored on your computer.
df2 = pd.read_csv(rf"{dataframe2}", sep="|")
# KCS Section Codes mapping file. Change the filepath to where the file is stored on your computer.
df3 = pd.read_excel(rf"{dataframe3}")
# loop through only text files in the input folder and convert data
for files in os.listdir(input_folder):
if files.endswith(".txt"):
df1 = pd.read_csv(rf"{input_folder}/{files}", sep="\t", encoding="latin-1")
df1["BrandName"] = df1["Comp_Brand"].apply(
xlookup, args=(df2["BrandID"], df2["BrandName"])
)
# map columns to the desired headers
df1.rename(
columns={
"BrandName": "Competitor_Name",
"Comp_PN": "Competitor_PartNumber",
"CQ_Brand": "AAIA_Code",
"CQ_PN": "PartNumber",
},
inplace=True,
)
remove_columns = df1.loc[
:, ~df1.columns.isin(["Comp_Brand", "CQ_Desc", "PartID"])
]
new_columns = [
"Competitor_Name",
"Competitor_PartNumber",
"AAIA_Code",
"PartNumber",
]
table_output = remove_columns[new_columns]
# below code for constructing file name convention
kcs_section_codes = df3.values.tolist()
stringtwo = table_output.loc[0][2] # stringtwo is the AAIA_Code
for code in kcs_section_codes:
if code[0] == stringtwo:
# stringone is the matching value under BrandName in the KCS_Section_Codes file
# by looking up AAIA_Code from the initial file in the BrandCode column from the KCS_Section_Codes file
stringone = "".join(
e for e in code[1] if e.isalnum()
) # replace any character that is not a letter or number with an empty character.
filename = rf"{stringone}-{stringtwo}_Interchanges.txt"
outputfile = rf"{output_folder}/{filename}"
table_output.to_csv(
outputfile,
sep="\t",
index=False,
columns=[
"Competitor_Name",
"Competitor_PartNumber",
"AAIA_Code",
"PartNumber",
],
)
# progress bar
total_files = sum([len(files) for r, d, files in os.walk(output_folder)])
for i in range(1, total_files):
sg.one_line_progress_meter(
"Loading...",
i + 1,
1000,
"key",
"Files Processed",
orientation="horizontal",
)
# code below for returning stats of main function in a popup window
total_files = sum([len(files) for r, d, files in os.walk(output_folder)])
end = time.time()
result_time = end - start
time_formatted = time.strftime("%H:%M:%S", time.gmtime(result_time))
sg.popup_no_titlebar(
f"Done! :)\nTotal Files Processed: {total_files}\nExecution Time (hh:mm:ss): {time_formatted}"
)
def xlookup(lookup_value, lookup_array, return_array, if_not_found: str = ""):
match_value = return_array.loc[lookup_array == lookup_value]
if match_value.empty:
return f'"{lookup_value}" not found!' if if_not_found == "" else if_not_found
else:
return match_value.tolist()[0]
def is_valid_path(filepath):
if filepath and Path(filepath).exists():
return True
sg.popup_error("Filepath not correct")
return False
def gui():
sg.theme("DarkBlue3") # Add a touch of color
# All the stuff inside your window.
layout = [
[
sg.Text("Input Folder: "),
sg.Input(key="-IN-"),
sg.FolderBrowse(),
],
[sg.Text("Output Folder: "), sg.Input(key="-OUT-"), sg.FolderBrowse()],
[
sg.Text("Data Mapping File: Parent Supplier Brand"),
sg.Input(key="-DF2-"),
sg.FileBrowse(),
],
[
sg.Text("Data Mapping File: KCS Section Codes"),
sg.Input(key="-DF3-"),
sg.FileBrowse(),
],
[sg.Exit(), sg.Button("Convert to CSV")],
]
# Create the Window
window = sg.Window("Data Conversion", layout)
# Event Loop to process "events" and get the "values" of the inputs
while True:
event, values = window.read()
if (
event == sg.WIN_CLOSED or event == "Cancel"
): # if user closes window or clicks cancel
break
if event in (sg.WIN_CLOSED, "Exit"):
break
if (
event == "Convert to CSV"
): # if user clicks covert to csv button then call convert_to_csv function using inputs
if (is_valid_path(values["-IN-"])) and (is_valid_path(values["-OUT-"])):
convert_to_csv(
input_folder=values["-IN-"],
output_folder=values["-OUT-"],
dataframe2=values["-DF2-"],
dataframe3=values["-DF3-"],
)
window.close()
if __name__ == "__main__":
gui()
Following code update the progressbar without any time delay, so it will show in short time and reach the maximum value immediately, then the window for progressbar closed.
for i in range(1, total_files):
sg.one_line_progress_meter(
"Loading...",
i + 1,
1000,
"key",
"Files Processed",
orientation="horizontal",
)
Reduce your code to ask question, it will help people to help.
Demo code:
from time import sleep
import PySimpleGUI as sg
from threading import Thread
def job(window):
window.write_event_value("Update", 0)
for i in range(1, 11):
sleep(0.2) # Simulate each step in the job
window.write_event_value("Update", i) # Cannot update GUI not in the main thread
window.write_event_value("Done", None)
sg.theme("DarkBlue3")
layout = [[sg.Button("Submit"), sg.Button("Exit")],]
window = sg.Window("Title", layout)
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, "Exit"):
break
elif event == "Submit":
thread = Thread(target=job, args=(window, ), daemon=True)
thread.start()
elif event == "Update":
i = values[event]
sg.one_line_progress_meter("Loading...", i, 10, "key", "Files Processed", orientation="horizontal")
elif event == "Done":
print('Job done !')
window.close()

How can I pass multiple user input values from PySimpleGUI to a function, then output result to PySimpleGUI?

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)

Arduino extract data from serial monitor

I wrote a simple controller for my robot in Python and now I want to send the data over the serial monitor to the Arduino. I managed to send the values but now I want to know how I can extract the data from the monitor with the Arduino. My Python code:
import PySimpleGUI as sg
import serial
import time
import math
ArmLänge = 205
TextX = 10
TextY = 10
TextZ = 10
font = ("Courier New", 11)
sg.theme("DarkBlue3")
sg.set_options(font=font)
ser = serial.Serial("COM6")
ser.flushInput()
layout = [
[sg.Text("Forward Kinematics:", font=("Helvetica", 12)), sg.Text(" Inverse Kinematics:", font=("Helvetica", 12))],
[sg.Text("X"), sg.Slider((0, 360), orientation='horizontal', key='SLIDER_X'), sg.Text("X"),sg.InputText(size=(10, 10), key="InputX")],
[sg.Text("Y"), sg.Slider((0, 360), orientation='horizontal', key='SLIDER_Y'), sg.Text("Y"),sg.InputText(size=(10, 10), key="InputY")],
[sg.Text("Z"), sg.Slider((0, 360), orientation='horizontal', key='SLIDER_Z'), sg.Text("Z"),sg.InputText(size=(10, 10), key="InputZ")],
[sg.Push(), sg.Button('Exit'), sg.Button("Move")],
]
window = sg.Window("Controller", layout, finalize=True)
window['SLIDER_X'].bind('<ButtonRelease-1>', ' Release')
window['SLIDER_Y'].bind('<ButtonRelease-1>', ' Release')
window['SLIDER_Z'].bind('<ButtonRelease-1>', ' Release')
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, 'Exit'):
break
elif event == 'SLIDER_X Release':
print("X Value:", values["SLIDER_X"])
elif event == 'SLIDER_Y Release':
print("Y Value:", values["SLIDER_Y"])
elif event == 'SLIDER_Z Release':
print("Z Value:", values["SLIDER_Z"])
#elif event == "Move":
#print("IK X:", values['InputX'])
#print("IK Y:", values['InputY'])
#print("IK Z:", values['InputZ'])
valX = int(values["SLIDER_X"]/2)
valY = int(values["SLIDER_Y"]/2)
valZ = int(values["SLIDER_Z"]/2)
Data = [1,valX,valY,valZ]
print(Data)
ser.write(Data)
if values['InputX'] >= str(1):
x = float(values['InputX'])
y = float(values['InputY'])
z = float(values['InputZ'])
h = round(math.sqrt(x ** 2 + y ** 2))
joint2 = round(math.degrees(math.atan(y / x)))
joint3 = round(math.degrees(math.acos((h / 2) / (ArmLänge / 2))))
print("----Ergebnis:----")
print("Höhe:", h)
print("Joint2:", joint2,"°")
print("Joint3:", joint3,"°")
IKData = [2, h, joint2, joint3]
print(IKData)
ser.write(IKData)
window.close()
ser.close()
It may not be the best code but it works. I need to extract every number for example [1, 20, 45, 30]. How can I do that?
I am assuming that the data goes to Serial in this Format as String:
[1,valX,valY,valZ]
After reading the data from Serial and converting the data line to String with String() function, you can assign the values to desired variables using sscanf() function.
The function works like this -
sscanf(const char *str, const char *format, ...)
So, here it would work like this -
int data_val1, data_val2, data_val3;
sscanf(Your_SerialData_String, [1,%d,%d,%d], data_val1, data_val2, data_val3);

Is there a way to clear a tree element in PySimpleGUI before adding new data?

I have a window with a tree element that shows files and folders when I enter a path. I need this tree to clear if I enter a new path. At the moment the tree appends the files/folders from each path I enter. Is there a way to refresh the tree element before entering new information into it?
My code is similar to this:
import PySimpleGUI as sg
import os
starting_path = os.getcwd()
treedata = sg.TreeData()
folder_icon = b'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAABnUlEQVQ4y8WSv2rUQRSFv7vZgJFFsQg2EkWb4AvEJ8hqKVilSmFn3iNvIAp21oIW9haihBRKiqwElMVsIJjNrprsOr/5dyzml3UhEQIWHhjmcpn7zblw4B9lJ8Xag9mlmQb3AJzX3tOX8Tngzg349q7t5xcfzpKGhOFHnjx+9qLTzW8wsmFTL2Gzk7Y2O/k9kCbtwUZbV+Zvo8Md3PALrjoiqsKSR9ljpAJpwOsNtlfXfRvoNU8Arr/NsVo0ry5z4dZN5hoGqEzYDChBOoKwS/vSq0XW3y5NAI/uN1cvLqzQur4MCpBGEEd1PQDfQ74HYR+LfeQOAOYAmgAmbly+dgfid5CHPIKqC74L8RDyGPIYy7+QQjFWa7ICsQ8SpB/IfcJSDVMAJUwJkYDMNOEPIBxA/gnuMyYPijXAI3lMse7FGnIKsIuqrxgRSeXOoYZUCI8pIKW/OHA7kD2YYcpAKgM5ABXk4qSsdJaDOMCsgTIYAlL5TQFTyUIZDmev0N/bnwqnylEBQS45UKnHx/lUlFvA3fo+jwR8ALb47/oNma38cuqiJ9AAAAAASUVORK5CYII='
file_icon = b'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAABU0lEQVQ4y52TzStEURiHn/ecc6XG54JSdlMkNhYWsiILS0lsJaUsLW2Mv8CfIDtr2VtbY4GUEvmIZnKbZsY977Uwt2HcyW1+dTZvt6fn9557BGB+aaNQKBR2ifkbgWR+cX13ubO1svz++niVTA1ArDHDg91UahHFsMxbKWycYsjze4muTsP64vT43v7hSf/A0FgdjQPQWAmco68nB+T+SFSqNUQgcIbN1bn8Z3RwvL22MAvcu8TACFgrpMVZ4aUYcn77BMDkxGgemAGOHIBXxRjBWZMKoCPA2h6qEUSRR2MF6GxUUMUaIUgBCNTnAcm3H2G5YQfgvccYIXAtDH7FoKq/AaqKlbrBj2trFVXfBPAea4SOIIsBeN9kkCwxsNkAqRWy7+B7Z00G3xVc2wZeMSI4S7sVYkSk5Z/4PyBWROqvox3A28PN2cjUwinQC9QyckKALxj4kv2auK0xAAAAAElFTkSuQmCC'
def add_files_in_folder(parent, dirname):
files = os.listdir(dirname)
for f in files:
fullname = os.path.join(dirname, f)
if os.path.isdir(fullname): # if it's a folder, add folder and recurse
treedata.Insert(parent, fullname, f, values=[], icon=folder_icon)
add_files_in_folder(fullname, fullname)
else:
treedata.Insert(parent, fullname, f, values=[os.stat(fullname).st_size], icon=file_icon)
def main_window():
column_one = sg.Column([
[sg.Tree(data=treedata,
headings=['Size', ],
auto_size_columns=True,
select_mode=sg.TABLE_SELECT_MODE_EXTENDED,
num_rows=20,
col0_width=40,
key='-TREE-',
show_expanded=False,
enable_events=True,
expand_x=True,
expand_y=True,
), ],
[sg.B('Open', k='-OPEN-'), sg.B('Add', k='-ADD-')],
])
layout = [
[sg.T('Some text')],
[sg.HorizontalSeparator()],
[sg.T('Select the files / folders')],
[column_one],
[sg.B('Cancel', k='-EXIT-')]
]
return sg.Window('some window', layout, resizable=True, finalize=True)
window = main_window()
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, '-EXIT-'):
break
print(event, values)
if event == '-OPEN-':
starting_path = sg.popup_get_folder('Folder to display')
add_files_in_folder('', starting_path)
window['-TREE-'].update(values=treedata)
window.close()
Any help is appreciated!
Following code demo how to create/clear/append data to treedata for Table element. Here all item added as children of root ''.
import PySimpleGUI as sg
def add_data(treedata, offset):
default = [[str((i+1)*(j+offset+1)) for i in range(9)] for j in range(9)]
for i, value in enumerate(default):
treedata.insert('', i+offset+1, i+offset+1, value)
return treedata
treedata = sg.TreeData()
treedata = add_data(treedata, 0)
index = 10
layout = [
[sg.Tree(
data=treedata,
headings=[str(i+1) for i in range(9)],
col0_heading='9x9',
col0_width=5,
num_rows=20,
key='-TREE-',
)],
[sg.Button('Clear'), sg.Button('Reset'), sg.Button('Append')],
]
window = sg.Window('Title', layout, finalize=True)
tree = window['-TREE-']
tree.Widget.column('#0', anchor='e')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == 'Clear':
treedata = sg.TreeData()
tree.update(values=treedata)
index = 0
elif event == 'Reset':
treedata = add_data(sg.TreeData(), 0)
tree.update(values=treedata)
index = 10
elif event == 'Append':
treedata = add_data(treedata, index)
tree.update(values=treedata)
index += 10
window.close()

Make an editable table in PySimpleGUI?

Hello I am using a Table element from PySimpleGUI. I would like for the user to be able to edit the data inside it.
I have seen some mentions of it. Is it possible? This guy was using PySimpleGUIQt, while I am using the PySimpleGUI on top of tkinter.
It's much difficult for me to build it by pure PySimpleGUI code.
If go it with new class inherited from sg.Table, some variables as argument or global variables not required.
Here, colors of cell not considered in Entry.
All tkinter code in function edit_cell of following example.
import PySimpleGUI as sg
import random, string
# ------ Some functions to help generate data for the table ------
def word():
return ''.join(random.choice(string.ascii_lowercase) for i in range(10))
def number(max_val=1000):
return random.randint(0, max_val)
def make_table(num_rows, num_cols):
data = [[j for j in range(num_cols)] for i in range(num_rows)]
data[0] = [word() for _ in range(num_cols)]
for i in range(0, num_rows):
data[i] = [i, word(), *[number() for i in range(num_cols - 1)]]
return data
def edit_cell(window, key, row, col, justify='left'):
global textvariable, edit
def callback(event, row, col, text, key):
global edit
widget = event.widget
if key == 'Return':
text = widget.get()
print(text)
widget.destroy()
widget.master.destroy()
values = list(table.item(row, 'values'))
values[col] = text
table.item(row, values=values)
edit = False
if edit or row <= 0:
return
edit = True
root = window.TKroot
table = window[key].Widget
text = table.item(row, "values")[col]
x, y, width, height = table.bbox(row, col)
frame = sg.tk.Frame(root)
frame.place(x=x, y=y, anchor="nw", width=width, height=height)
textvariable = sg.tk.StringVar()
textvariable.set(text)
entry = sg.tk.Entry(frame, textvariable=textvariable, justify=justify)
entry.pack()
entry.select_range(0, sg.tk.END)
entry.icursor(sg.tk.END)
entry.focus_force()
entry.bind("<Return>", lambda e, r=row, c=col, t=text, k='Return':callback(e, r, c, t, k))
entry.bind("<Escape>", lambda e, r=row, c=col, t=text, k='Escape':callback(e, r, c, t, k))
def main_example1():
global edit
edit = False
# ------ Make the Table Data ------
# sg.Print('Creating table...')
data = make_table(num_rows=1_000, num_cols=6)
# headings = [str(data[0][x])+' ..' for x in range(len(data[0]))]
headings = [f'Col {col}' for col in range(len(data[0]))]
# sg.Print('Done creating table. Creating GUI...')
sg.set_options(dpi_awareness=True)
layout = [[sg.Table(values=data, headings=headings, max_col_width=25,
auto_size_columns=True,
# display_row_numbers=True,
justification='right',
num_rows=20,
alternating_row_color=sg.theme_button_color()[1],
key='-TABLE-',
# selected_row_colors='red on yellow',
# enable_events=True,
# select_mode=sg.TABLE_SELECT_MODE_BROWSE,
expand_x=True,
expand_y=True,
enable_click_events=True, # Comment out to not enable header and other clicks
)],
[sg.Button('Read'), sg.Button('Double'), sg.Button('Change Colors')],
[sg.Text('Cell clicked:'), sg.T(k='-CLICKED-')]]
window = sg.Window('Table Element - Example 1', layout, resizable=True, finalize=True)
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
elif isinstance(event, tuple):
cell = row, col = event[2]
window['-CLICKED-'].update(cell)
edit_cell(window, '-TABLE-', row+1, col, justify='right')
window.close()
main_example1()
I would strongly suggest use MutiLine for showing table, which is much simpler to manage and can be easily updated etc. The Same table effects can be achieved by less lines of code. Giving a sample code here from my own database program with uses Sqlite3 table.
def ViewTable (TableNme):
try: # LOAD TABLE FROM Sqlite3 Database
txt2="SELECT * FROM {} ".format(TableNme)
cursor.execute(txt2)
##Include headers###
txt2='S.No '
for j in fields: txt2=txt2+j +" "
txt2=txt2+'\n'
#converts the table into string separated by Comma
#fine as long as table is not very massive running more than 3 Mbs, having more than 1000 records
while True:
h1=cursor.fetchone()
if not h1: break
for j in h1:txt2=txt2+str(j)+" "
txt2=txt2+'\n'
#sg.popup('Archieved table', txt2)
#Define text to load by text= before calling me
layout2 = [[sg.Multiline(txt2,size=(28,28),key='-Items-'),],[sg.Ok()] ]
sg.Window('Scroll to see the whole database', layout2,finalize=True).read(close=True)
except:
sg.popup_error('Failed','Access denied or Memory full.')

Categories