The simplest "select a row from a table" implementation I could come up with #1785
Unanswered
llimllib
asked this question in
Show and tell
Replies: 3 comments
-
Here's an improved version using a live table: from datetime import datetime
import os
from rich import box
from rich.live import Live
from rich.table import Table
from rich.style import Style
from getchar import getchar
SELECTED = Style(color="blue", bgcolor="white", bold=True)
UP = "\x1b[A"
DOWN = "\x1b[B"
ENTER = "\r"
def generate_table(headers, rows, selected) -> Table:
table = Table(box=box.MINIMAL)
for h in headers:
table.add_column(h)
for i, row in enumerate(rows):
table.add_row(*row, style=SELECTED if i == selected else None)
return table
def format_ts(ts):
return datetime.utcfromtimestamp(ts).strftime("%Y-%m-%d")
# get the first 10 items from os.listdir to show in the table
headers = ["filename", "size (bytes)", "modified"]
items = [
(fname, str(stat.st_size), format_ts(stat.st_mtime))
for fname, stat in [(f, os.stat(f)) for f in os.listdir()[:5]]
][:10]
selected = 0
with Live(generate_table(headers, items, selected), auto_refresh=False) as live:
while True:
ch = getchar(False)
if ch == UP:
selected = max(0, selected - 1)
elif ch == DOWN:
selected = min(len(items) - 1, selected + 1)
elif ch == ENTER:
live.stop()
print("you selected: ", items[selected])
break
live.update(generate_table(headers, items, selected), refresh=True) One thing to note is that it doesn't handle the table being larger than the available vertical screen space. |
Beta Was this translation helpful? Give feedback.
0 replies
-
And, finally a version that uses readchar ( from datetime import datetime
import os
from rich.console import Console
from rich.live import Live
from rich.table import Table
from rich.style import Style
from rich import box
# pip install readchar
# https://github.com/magmax/python-readchar seems low-overhead and simple
from readchar import readkey, key
SELECTED = Style(color="blue", bgcolor="white", bold=True)
def generate_table(console, headers, rows, selected) -> Table:
table = Table(box=box.MINIMAL)
for h in headers:
table.add_column(h)
size = console.height - 4
if len(rows) + 3 > size:
if selected < size / 2:
rows = rows[:size]
elif selected + size / 2 > len(items):
rows = rows[-size:]
selected -= len(items) - size
else:
rows = rows[selected - size // 2 : selected + size // 2]
selected -= selected - size // 2
for i, row in enumerate(rows):
table.add_row(*row, style=SELECTED if i == selected else None)
return table
def format_ts(ts):
return datetime.utcfromtimestamp(ts).strftime("%Y-%m-%d")
headers = ["filename", "size (bytes)", "modified"]
items = [
(fname, str(stat.st_size), format_ts(stat.st_mtime))
for fname, stat in [(f, os.stat(f)) for f in os.listdir()]
]
console = Console()
selected = 0
with Live(
generate_table(console, headers, items, selected), auto_refresh=False
) as live:
while True:
ch = readkey()
if ch == key.UP or ch == "k":
selected = max(0, selected - 1)
if ch == key.DOWN or ch == "j":
selected = min(len(items) - 1, selected + 1)
if ch == key.ENTER:
live.stop()
print("you selected: ", items[selected])
break
live.update(generate_table(console, headers, items, selected), refresh=True) |
Beta Was this translation helpful? Give feedback.
0 replies
-
Learning about the Rich library and wanted to make a scrollable table for a task tracker type object. This was very helpful. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I wanted to allow a user to pick an option from a list using rich, and not needing support for the windows command line.
Textual/click/etc seemed pretty heavy, and I wanted to know how this would work, so I wanted to not add any dependencies.
Here's the simplest implementation I could come up with; I welcome feedback on how to make it simpler or better, but I'm putting it here mainly for anybody else to see how they might begin:
Screen.Recording.2021-12-28.at.12.48.24.PM.mov
(update: see comment below for a much improved version)
menutest.py:
getchar.py is a modification of click's input handling code:
Beta Was this translation helpful? Give feedback.
All reactions