Skip to content

Instantly share code, notes, and snippets.

@thegamecracks
Created January 8, 2025 02:36
Show Gist options
  • Select an option

  • Save thegamecracks/ea55e13e6414ceeebc05d9a9de65102c to your computer and use it in GitHub Desktop.

Select an option

Save thegamecracks/ea55e13e6414ceeebc05d9a9de65102c to your computer and use it in GitHub Desktop.
A basic Tkinter table widget using frames, labels, and native relief styles
from tkinter import Tk
from tkinter.ttk import Frame, Label, Style
class Table(Frame):
"""Presents tabular data in a self-contained widget."""
def __init__(self, parent, rows, *, title):
super().__init__(parent)
self.title = Label(self, text=title)
self.title.pack()
self.contents = Frame(self)
self.contents.pack(expand=True, fill="both")
self._configure_weights(rows)
self._create_cells(rows)
def _configure_weights(self, rows):
"""Configure the table content's row and column weights.
This allows each cell to expand when the table is resized.
See also:
https://tkdocs.com/tutorial/grid.html#resize
"columnconfigure", "rowconfigure"
"""
n_rows = len(rows)
n_cols = len(rows[0]) # May raise IndexError
for y in range(n_rows):
self.contents.grid_rowconfigure(y, weight=1)
for x in range(n_cols):
self.contents.grid_columnconfigure(x, weight=1)
def _create_cells(self, rows):
"""Create label widgets for each value in the given rows."""
for y, row in enumerate(rows):
row_style = "TableEvenRow.TLabel" if y % 2 == 0 else "TableOddRow.TLabel"
for x, value in enumerate(row):
label = Label(
self.contents,
text=str(value),
anchor="center",
borderwidth=1,
relief="solid",
style=row_style,
)
label.grid(row=y, column=x, sticky="nesw")
def main():
app = Tk()
style = Style(app)
style.configure(".", background="white")
style.configure("TableEvenRow.TLabel", background="#FFFFFF")
style.configure("TableOddRow.TLabel", background="#F3F3F3")
# Put our tables inside a content frame so we can make the background pure white.
content = Frame()
content.pack(expand=True, fill="both")
Table(
content,
title="Transport Mode Comparison",
rows=[
("Mode", "Distance (km)", "CO2 (t)", "CO2 Saved (t)"),
("Air", "294.5", "5.32", ""),
("Rail", "353.3", "0.52", "4.80"),
("Bus", "382.8", "0.40", "4.92"),
],
).grid(
row=0,
column=0,
padx=20,
pady=20,
# Use internal padding to expand the table beyond its compact form
ipadx=20,
ipady=20,
)
Table(
content,
title="Carbon Price Analysis (DE)",
rows=[
("Mode", "Price"),
("Air", "€239.39"),
("Rail", "€23.47"),
("Bus", "€18.14"),
],
).grid(
row=0,
column=1,
padx=(0, 20),
pady=20,
ipadx=20,
ipady=20,
)
Table(
content,
title="Social Cost Analysis",
rows=[
("Mode", "Cost Type", "Low", "Median", "Mean", "High"),
("Air", "Synthetic", "€516", "€984", "€1505", "€1963"),
("Air", "EPA", "", "€835", "", ""),
("Air", "IWG", "", "€277", "", ""),
("Rail", "Synthetic", "€51", "€96", "€148", "€192"),
("Rail", "EPA", "", "€82", "", ""),
("Rail", "IWG", "", "€27", "", ""),
("Bus", "Synthetic", "€39", "€75", "€114", "€149"),
("Bus", "EPA", "", "€63", "", ""),
("Bus", "IWG", "", "€21", "", ""),
],
).grid(
row=1,
column=0,
padx=20,
pady=(0, 20),
# Give the table both columns under the previous two tables,
# and stretch the table out horizontally.
columnspan=2,
sticky="ew",
)
# By default, grid aligns all widgets on the top-left of their cells
# if they don't use any sticky= option. Let's override this to center
# the first two tables.
content.grid_anchor("center")
app.mainloop()
if __name__ == "__main__":
main()
@thegamecracks
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment