Skip to content

Table

A data table with a fixed header, optional sorting and row selection. Columns are ui.Column objects whose key is a dict key, an attribute name or a function of the row; render turns a value into any widget. The table sorts the rows itself by the column whose title is sort_by: you only store that title and the direction.

ui.table · Category: Data · Full reference →

TableTable
  • For records with several comparable fields: files, users, processes, results.
  • For a single column of items, a list of List items is lighter.
import pyzed as pz
from pyzed import ui
class Files(pz.App):
def __init__(self):
self.rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}]
self.sort_by, self.descending, self.selected = "Lines", True, None
def sort(self, title):
self.descending = not self.descending if self.sort_by == title else False
self.sort_by = title
def view(self):
return ui.table(
[ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")],
self.rows, sort_by=self.sort_by, descending=self.descending, on_sort=self.sort,
on_row_press=lambda row: setattr(self, "selected", row), selected=self.selected,
)
Table: PlainTable: Plain
Plain
Code
pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")],
[{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}]), width=320)
Table: striped=TrueTable: striped=True
striped=True
Code
pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")],
[{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}], striped=True), width=320)
Table: selected=Table: selected=
selected=
Code
rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}]
pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], rows, selected=rows[1]), width=320)
Table: sort_by=, descending=TrueTable: sort_by=, descending=True
sort_by=, descending=True
Code
pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")],
[{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}], sort_by="Lines", descending=True,
on_sort=on_sort), width=320)
Table: row_height=24Table: row_height=24
row_height=24
Code
pz.container(ui.table([ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")],
[{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}, {"name": "ui.py", "lines": 1290}], row_height=24), width=320)
Table: render=Table: render=
render=
Code
rows = [{"job": "build", "state": "passed"}, {"job": "lint", "state": "failed"}]
tint = {"passed": "success", "failed": "error"}
pz.container(ui.table([ui.Column("Job", "job"),
ui.Column("State", "state", width=110, render=lambda s: ui.badge(s, tint=tint[s]))],
rows), width=320)
Table: key=lambdaTable: key=lambda
key=lambda
Code
people = [("Ana", 31), ("Luis", 27)]
pz.container(ui.table([ui.Column("Name", lambda p: p[0]),
ui.Column("Age", lambda p: p[1], width=70, align="end")], people), width=320)

on_row_double_press(row) opens a row and on_row_context(row) shows a context menu.

Table: Multiple selectionTable: Multiple selection
Multiple selection
Code
rows = [{"name": "app.py", "size": 4}, {"name": "ui.py", "size": 12}, {"name": "README.md", "size": 2}]
ui.table(["name", "size"], rows, selected=[rows[0], rows[2]], on_row_press=on_press,
on_row_double_press=on_open, on_row_context=on_context, height=130)
Table: empty=Table: empty=
empty=
Code
ui.table(["name", "size"], [], empty="No files yet", height=100)

render receives the value and returns a widget, here a badge.

Table: Custom cellsTable: Custom cells

Table has 4 events of its own, listed below. Like every widget it also has the 18 common events (click, double_click, right_click, mouse_enter, drag, key_down, resize…), attached with .on(...): see Events and Events of every component.

Event Handler gets When
on_sort (title) Callable that receives the clicked title.
on_row_press (row) Callable that receives the clicked row.
on_row_double_press (row) Called with the row on a double click (open, edit…).
on_row_context (row) Called with the row on a right click (a context menu).

Handler gets is what Pyzed passes to your callable: () means nothing. Any handler can also be a message (a value that is not callable), which goes to update().

The same events written three ways. Imperative: methods of the app change self. Declarative: the handlers produce messages and one update() decides. Functional: a pure function draws an immutable state and asks for changes with set_state(...). See Imperative, declarative and functional.

class Files(pz.App):
def __init__(self):
self.rows = [{"name": "app.py", "lines": 512}, {"name": "theme.py", "lines": 730}]
self.sort_by, self.descending = "Lines", True
self.selected, self.opened = None, None
def sort(self, title): # on_sort: the clicked column title
self.descending = not self.descending if self.sort_by == title else False
self.sort_by = title
def view(self):
key = "name" if self.sort_by == "File" else "lines"
rows = sorted(self.rows, key=lambda r: r[key], reverse=self.descending)
return ui.table(
[ui.Column("File", "name"), ui.Column("Lines", "lines", width=80, align="end")], rows,
sort_by=self.sort_by, descending=self.descending, on_sort=self.sort, selected=self.selected,
on_row_press=lambda row: setattr(self, "selected", row), # click
on_row_double_press=lambda row: setattr(self, "opened", row), # double click
on_row_context=lambda row: print("menu for", row["name"]), # right click
)
table(
columns,
rows,
*,
sort_by=None,
descending=False,
on_sort=None,
on_row_press=None,
selected=None,
striped=False,
row_height=30,
height=None,
on_row_double_press=None,
on_row_context=None,
empty=None,
theme=None,
)

A data table with a fixed header, optional sorting and row selection. Sorting happens here when sort_by names a column: clicking a header calls on_sort(title) and you update sort_by/descending in your state. Rows are virtualized: only the ones in view are built, so hundreds of thousands of rows scroll smoothly.

Property Default Description
columns required ui.Column or plain keys.
rows required Dicts or objects.
sort_by None Title of the column to sort by.
descending False Descending order.
selected None The row to highlight, or a list or set of rows (multiple selection).
striped False Shaded alternating rows.
row_height 30 Height of each row.
height None Height: pixels, "fill", "shrink" or "fill:N" (proportion).
empty None Text or widget shown in place of the rows when there are none.
theme None Theme to use instead of the current one (pyzed.theme.current()).

Events: on_sort, on_row_press, on_row_double_press, on_row_context (events).

Full reference →

@dataclass
class Column(title, key, width='fill', align='start', render=None, sortable=True)

A column of ui.table. key is a dict key, an attribute name or a function of the row; render (optional) turns the value into a widget. width is "fill", a number or a portion such as "fill:2".

Property Default Description
title required Header (and name used for sorting).
key required How to get the value from each row.
width "fill" Width: pixels, "fill", "shrink" or "fill:N" (proportion).
align "start" "start", "center" or "end".
render None Function value → widget.
sortable True Whether the header can be clicked to sort.

Full reference →