Interacting with a live display #1011
-
Hi Will, thanks for building and sharing I'm trying to build a TUI, and I was exploring if I can do it with Then capture the user input and update the table (pressed key was I see Can I achieve my needs with If it is not possible, which package would you recommend me to use? Thanks a lot! |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
Hello. I have the same request here. It seams that it is not supported... :-( I tried several libraries.. but no success. My idea was to add a library that gets keyboard input, write to a file (or maybe send a signal?), and read it in the program. The code below was the best I could get... gotta hit ESC then ControlC to exit. But if you change focus to another window you will crash everything. To start, you need a output.txt already created .
Any contributions to this code ? Thanks |
Beta Was this translation helpful? Give feedback.
-
@ig-perez @Cristianasp To answer both your questions... Rich doesn't yet handle keyboard input, other than Input() (or Prompt.ask). Unfortunately input() is unlikely to work well with Live. @Cristianasp Your idea of using using pynput is probably a good one (although I haven't tried myself). No need to write to files though. What I would suggest you do is put your logic inside on_press. Update layout["whatever"] there. Your live loop need only do something like the following: with Live(layout, screen=True):
while True:
sleep(1) Hope that helps! |
Beta Was this translation helpful? Give feedback.
-
Thanks @willmcgugan and @Cristianasp for your ideas and suggestions. In my case I ended up creating a shell with a I'm really excited with Rich. I think that building TUIs is an excellent option to make an idea or project come true in a simple and fast way (assuming your target users are not afraid of terminals of course 🤓). It doesn't have the complexity of a Web User Interface nor faces the portability issues of desktop apps. The recently added Layouts are fantastic! |
Beta Was this translation helpful? Give feedback.
-
I don't know if the way I did it creates some kind of bottleneck, but the concept would be something like this. menu.mp4import random
import readchar
import asyncio
from threading import Timer
from rich.live import Live
from rich.table import Table
def list_systems():
names = ["Ubuntu", "Debian", "Kali", "Arch", "Fedora", "CentOS"]
states = ["Stopped", "Running"]
values = []
for name in names:
values.append(
{
"name": name,
"state": random.choice(states),
}
)
return values
def generate_table(cursor_line: int) -> Table:
"""Make a new table."""
systems = list_systems()
table = Table(title="All Systems")
table.add_column(" ", justify="center", no_wrap=True)
table.add_column("#", justify="center", no_wrap=True)
table.add_column("Name", justify="center")
table.add_column("State", justify="center")
for number, system in enumerate(systems, 1):
color = "green" if system["state"] == "Stopped" else "red"
check = "X" if cursor_line == number else ""
table.add_row(check, str(number), system["name"], system["state"], style=color)
return table
async def key_listener(callback):
while True:
key = readchar.readkey()
if key in [readchar.key.ENTER, readchar.key.ENTER_2]:
break
if key in [readchar.key.UP, readchar.key.DOWN]:
if key == readchar.key.UP:
callback("up")
else:
callback("down")
print("Listener stopped")
async def set_timeout(i, callback):
Timer(i, callback).start()
async def run():
cursor_line = 1
timer_interval = 1
with Live(generate_table(cursor_line), auto_refresh=False) as live:
while True:
print("Waiting")
def callback():
live.update(generate_table(cursor_line))
live.refresh()
def callback_timer():
callback()
nonlocal timer
timer.cancel()
timer = Timer(timer_interval, callback_timer)
timer.start()
def callback_key(arrow_direction: str):
nonlocal cursor_line
cursor_line = (
cursor_line + 1 if arrow_direction == "down" else cursor_line - 1
)
callback()
timer = Timer(timer_interval, callback_timer)
timer.start()
events = [
asyncio.create_task(key_listener(callback_key)),
]
done, pending = await asyncio.wait(
events,
)
print("Done", done, "Pending", pending)
timer.cancel()
break
asyncio.run(run()) |
Beta Was this translation helpful? Give feedback.
@ig-perez @Cristianasp To answer both your questions...
Rich doesn't yet handle keyboard input, other than Input() (or Prompt.ask). Unfortunately input() is unlikely to work well with Live.
@Cristianasp Your idea of using using pynput is probably a good one (although I haven't tried myself). No need to write to files though. What I would suggest you do is put your logic inside on_press. Update layout["whatever"] there.
Your live loop need only do something like the following:
Hope that helps!