Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 67 additions & 75 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,65 @@
import PySimpleGUI as sg
from PySimpleGUI.elements.table import Table as SgTable

class EditTable(SgTable):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._editing = False

def _edit_callback(self, event, row, col, text):
widget = event.widget
text = widget.get()
widget.destroy()
widget.master.destroy()

values = list(self.Widget.item(row, "values"))
values[col] = text
self.Widget.item(row, values=values)
self._editing = False

def edit_cell(self, window, row, col):
if self._editing or row <0:
return

self._editing = True

row += 1
root = window.TKroot
table = self.Widget
text = table.item(row, "values")[col]

x, y, width, height = table.bbox(row, col)

# Depending on where in the GUI your table is, you'll have a different offset
# This seems to be just before the toplevel.
# This loops to find the pad_x and y to pad the frame placement
pad_x = 0
pad_y = 0
parent = table.master
while parent.widgetName != "toplevel":
pad_x = parent.winfo_x()
pad_y = parent.winfo_y()
parent = parent.master

x += pad_x
y += pad_y

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="right")
entry.pack()
entry.select_range(0, sg.tk.END)
entry.icursor(sg.tk.END)
entry.focus_force()

# Bind to FocusOut and Return (enter)
# No need to send a key, as this is the only place that calls the callback
entry.bind("<FocusOut>", lambda e, r=row, c=col, t=text:self._edit_callback(e,r,c,t))
entry.bind("<Return>", lambda e, r=row, c=col, t=text:self._edit_callback(e,r,c,t))

def generate_table_data():
headings = ['Name', 'ID', 'Grade1', 'Grade2', 'Grade3']
Expand All @@ -11,80 +72,11 @@ def generate_table_data():

return headings, data

# TKinter function to display and edit value in cell
def edit_cell(window, key, row, col, justify='left'):

global textvariable, edit

def callback(event, row, col, text, key):
global edit
# event.widget gives you the same entry widget we created earlier
widget = event.widget
if key == 'Focus_Out':
# Get new text that has been typed into widget
text = widget.get()
# Print to terminal
print(text)
# Destroy the entry widget
widget.destroy()
# Destroy all widgets
widget.master.destroy()
# Get the row from the table that was edited
# table variable exists here because it was called before the callback
values = list(table.item(row, 'values'))
# Store new value in the appropriate row and column
values[col] = text
table.item(row, values=values)
edit = False

if edit or row <= 0:
return

edit = True
# Get the Tkinter functionality for our window
root = window.TKroot
# Gets the Widget object from the PySimpleGUI table - a PySimpleGUI table is really
# what's called a TreeView widget in TKinter
table = window[key].Widget
# Get the row as a dict using .item function and get individual value using [col]
# Get currently selected value
text = table.item(row, "values")[col]
# Return x and y position of cell as well as width and height (in TreeView widget)
x, y, width, height = table.bbox(row, col)

# Create a new container that acts as container for the editable text input widget
frame = sg.tk.Frame(root)
# put frame in same location as selected cell
frame.place(x=x, y=y, anchor="nw", width=width, height=height)

# textvariable represents a text value
textvariable = sg.tk.StringVar()
textvariable.set(text)
# Used to acceot single line text input from user - editable text input
# frame is the parent window, textvariable is the initial value, justify is the position
entry = sg.tk.Entry(frame, textvariable=textvariable, justify=justify)
# Organizes widgets into blocks before putting them into the parent
entry.pack()
# selects all text in the entry input widget
entry.select_range(0, sg.tk.END)
# Puts cursor at end of input text
entry.icursor(sg.tk.END)
# Forces focus on the entry widget (actually when the user clicks because this initiates all this Tkinter stuff, e
# ending with a focus on what has been created)
entry.focus_force()
# When you click outside of the selected widget, everything is returned back to normal
# lambda e generates an empty function, which is turned into an event function
# which corresponds to the "FocusOut" (clicking outside of the cell) event
entry.bind("<FocusOut>", lambda e, r=row, c=col, t=text, k='Focus_Out':callback(e, r, c, t, k))

def generate_table():
global edit

edit = False

headings, data = generate_table_data()
sg.set_options(dpi_awareness=True)
layout = [[sg.Table(values=data, headings=headings, max_col_width=25,
layout = [[EditTable(values=data, headings=headings, max_col_width=25,
font=("Arial", 15),
auto_size_columns=True,
# display_row_numbers=True,
Expand Down Expand Up @@ -115,11 +107,11 @@ def generate_table():
if isinstance(event[2][0], int) and event[2][0] > -1:
cell = row, col = event[2]
print(row)

# Displays that coordinates of the cell that was clicked on
window['-CLICKED_CELL-'].update(cell)
edit_cell(window, '-TABLE-', row+1, col, justify='right')
# Displays that coordinates of the cell that was clicked on
window['-CLICKED_CELL-'].update(cell)
window['-TABLE-'].edit_cell(window, row, col)

window.close()

generate_table()
generate_table()