[ Enhancement] Table: setting selected_row_colors programmatically
Type of Issue (Enhancement, Error, Bug, Question)
Enhancement
Operating System
Windows
PySimpleGUI Port (tkinter, Qt, Wx, Web)
tkinter
Versions
Version information can be obtained by calling sg.main_get_debug_data()
Or you can print each version shown in ()
Python version (sg.sys.version)
'3.10.2 (tags/v3.10.2:a58ebcc, Jan 17 2022, 14:12:15) [MSC v.1929 64 bit (AMD64)]'
PySimpleGUI Version (sg.__version__)
'4.60.1'
GUI Version (tkinter (sg.tclversion_detailed), PySide2, WxPython, Remi)
'8.6.12'
Your Experience In Months or Years (optional)
Years Python programming experience
Years Programming experience overall
Have used another Python GUI Framework? (tkinter, Qt, etc) (yes/no is fine)
Anything else you think would be helpful?
Troubleshooting
These items may solve your problem. Please check those you've done by changing - [ ] to - [X]
- [ x] Searched main docs for your problem www.PySimpleGUI.org
- [x ] Looked for Demo Programs that are similar to your goal Demos.PySimpleGUI.org
- [ ] If not tkinter - looked for Demo Programs for specific port
- [ ] For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
- [ ] Run your program outside of your debugger (from a command line)
- [x ] Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org
- [x ] Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released
Detailed Description
To be able to set the color of the selected table row programmatically would be very helpful for my current app. Background: The table shows a list of parameter sets for a material processing machine. If the user changes a parameter below the table related to the parameter set, the selected row should be colored to indicate that the parameter set is outdated. I cannot recalculate as the user changes parameters. This would block the user interface for a few seconds. And therefore the user should press a button for recalculation after his changes.
Code To Duplicate
Screenshot, Sketch, or Drawing
Watcha Makin?
Thanks for your great project. It saved me a lot of time so far!
I'll get you some code this weekend that will do this. There should be enough information in the element for you to change the selected row colors by using some of the member variables to directly change the tkinter style. I think it should work out OK. I'll know more tomorrow once I spend some time with it.
You will need to get version 4.60.0.40 from GitHub (the latest posted PySimpleGUI.py file)
This is a modified Table Demo Program that includes:
- A button to change the select colors
- Two functions that implement the capability:
- change_select_row_color
- _fixed_map
Your code should call the change_select_row_color function to change the colors of the selection.
#!/usr/bin/env python
import PySimpleGUI as sg
import random
import string
"""
Basic use of the Table Element
Copyright 2022 PySimpleGUI
"""
def _fixed_map(style, style_name, option, highlight_colors=(None, None)):
default_map = [elm for elm in style.map("Treeview", query_opt=option) if '!' not in elm[0] and 'selected' not in elm[0]]
custom_map = [elm for elm in style.map(style_name, query_opt=option) if '!' not in elm[0] and 'selected' not in elm[0]]
if option == 'background':
custom_map.append(('selected', highlight_colors[1] if highlight_colors[1] is not None else sg.ALTERNATE_TABLE_AND_TREE_SELECTED_ROW_COLORS[1]))
elif option == 'foreground':
custom_map.append(('selected', highlight_colors[0] if highlight_colors[0] is not None else sg.ALTERNATE_TABLE_AND_TREE_SELECTED_ROW_COLORS[0]))
new_map = custom_map + default_map
return new_map
def change_select_row_color(table_element:sg.Table, background_color=None, foreground_color=None):
if background_color is not None:
table_element.ttk_style.map(table_element.table_ttk_style_name, background=_fixed_map(table_element.ttk_style, table_element.table_ttk_style_name, 'background', (foreground_color, background_color)))
if foreground_color is not None:
table_element.ttk_style.map(table_element.table_ttk_style_name, foreground=_fixed_map(table_element.ttk_style, table_element.table_ttk_style_name, 'foreground', (foreground_color, background_color)))
# ------ 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(1, num_rows):
data[i] = [word(), *[number() for i in range(num_cols - 1)]]
return data
# ------ Make the Table Data ------
data = make_table(num_rows=15, num_cols=6)
headings = [str(data[0][x])+' ..' for x in range(len(data[0]))]
# ------ Window Layout ------
layout = [[sg.Table(values=data[1:][:], headings=headings, max_col_width=25,
auto_size_columns=True,
# cols_justification=('left','center','right','c', 'l', 'bad'), # Added on GitHub only as of June 2022
display_row_numbers=True,
justification='center',
num_rows=20,
alternating_row_color='lightblue',
key='-TABLE-',
selected_row_colors='red on yellow',
enable_events=True,
expand_x=False,
expand_y=True,
vertical_scroll_only=False,
enable_click_events=True, # Comment out to not enable header and other clicks
tooltip='This is a table')],
[sg.Button('Read'), sg.Button('Double'), sg.Button('Change Colors'), sg.Button('Select Blue on Green')],
[sg.Text('Read = read which rows are selected')],
[sg.Text('Double = double the amount of data in the table')],
[sg.Text('Change Colors = Changes the colors of rows 8 and 9'), sg.Sizegrip()]]
# ------ Create Window ------
window = sg.Window('The Table Element', layout, resizable=True)
# ------ Event Loop ------
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED:
break
if event == 'Double':
for i in range(1,len(data)):
data.append(data[i])
window['-TABLE-'].update(values=data[1:][:])
elif event == 'Change Colors':
window['-TABLE-'].update(row_colors=((8, 'white', 'red'), (9, 'green')))
elif event == 'Select Blue on Green':
change_select_row_color(window['-TABLE-'], background_color='green', foreground_color='blue')
window.close()
Here is the sample code running. After clicking the "Select Blue on Green", the selection colors become blue text on a green background.

Dear Mike
This is fantastic! I was hoping to get an answer or hint after some time but I'd never thought that I'd get a solution ready to use so quickly. That really helps a lot. Thank you very much!
Jürg
You're quite welcome!

I take it that it worked OK.
Let's leave it open as an enhancement.
YES, it worked perfectly fine. Thanks again.

Nice! And you're very welcome again. Thank you for the "thanks"! 
Hi I would be glad if there is a way to do the same for the Tree element but instead of changing the color of the selected row, I want to change the color of every single row programmatically, An example of what I mean is shown below
Below GUI representation program taken from https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Tree_Element.py
This is actually pretty similar to issue referenced here https://github.com/PySimpleGUI/PySimpleGUI/issues/1026 but i am concerned about the Tree element - something like row_numbers method to tree data element kind of
Use Case: to change the color of each row based on the values in the respective row in another column @jason990420 @PySimpleGUI your inputs are much appreciated
There's no such function for Tree element, so I define a function to do the job.
from random import choice
import PySimpleGUI as sg
def set_row_colors(self, row_colors=None):
if row_colors is not None: # individual row colors
self.RowColors = row_colors
for row_def in self.RowColors:
iid = self.KeyToID[row_def[0]]
if len(row_def) == 2: # only background is specified
self.TKTreeview.tag_configure(iid, background=row_def[1])
else:
self.TKTreeview.tag_configure(iid, background=row_def[2], foreground=row_def[1])
sg.theme("DarkBlue")
sg.set_options(font=('Courier New', 12))
# Add tree data
treedata = sg.TreeData()
for i in range(20):
parent = choice(list(treedata.tree_dict.keys()))
treedata.insert(parent, i, f'Node {i:0>2d}', values=[f'Data {i:0>2d}'])
# Get keys for all nodes, except root of tree
keys = list(treedata.tree_dict.keys())
keys.remove('')
layout = [
[sg.Tree(data=treedata, headings=['Data', ], auto_size_columns=False,
num_rows=10, col0_width=30, col_widths=[10], justification='center',
show_expanded=True, enable_events=True, col0_heading='Node', key='-TREE-')],
[sg.Push(), sg.Button('Change Colors')],
]
window = sg.Window('Tree Element', layout, finalize=True)
tree = window['-TREE-']
# Define the tag for each node
for key in range(20):
iid = tree.KeyToID[key]
tree.widget.item(iid, tags=iid)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == "Change Colors":
# format of item in row_colors: (key_of_node, foreground_color, background_color) or (key_of_node, background_color)
set_row_colors(window['-TREE-'], row_colors=((0, 'white', 'red'), (1, 'white', 'blue'), (2, 'white', 'black'), (3, 'grey')))
window.close()