Created
January 8, 2025 02:36
-
-
Save thegamecracks/ea55e13e6414ceeebc05d9a9de65102c to your computer and use it in GitHub Desktop.
A basic Tkinter table widget using frames, labels, and native relief styles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() |
Author
thegamecracks
commented
Jan 8, 2025

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