Last active
November 30, 2024 16:08
-
-
Save claymcleod/b670285f334acd56ad1c to your computer and use it in GitHub Desktop.
Python curses example
This file contains 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
import sys,os | |
import curses | |
def draw_menu(stdscr): | |
k = 0 | |
cursor_x = 0 | |
cursor_y = 0 | |
# Clear and refresh the screen for a blank canvas | |
stdscr.clear() | |
stdscr.refresh() | |
# Start colors in curses | |
curses.start_color() | |
curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK) | |
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) | |
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE) | |
# Loop where k is the last character pressed | |
while (k != ord('q')): | |
# Initialization | |
stdscr.clear() | |
height, width = stdscr.getmaxyx() | |
if k == curses.KEY_DOWN: | |
cursor_y = cursor_y + 1 | |
elif k == curses.KEY_UP: | |
cursor_y = cursor_y - 1 | |
elif k == curses.KEY_RIGHT: | |
cursor_x = cursor_x + 1 | |
elif k == curses.KEY_LEFT: | |
cursor_x = cursor_x - 1 | |
cursor_x = max(0, cursor_x) | |
cursor_x = min(width-1, cursor_x) | |
cursor_y = max(0, cursor_y) | |
cursor_y = min(height-1, cursor_y) | |
# Declaration of strings | |
title = "Curses example"[:width-1] | |
subtitle = "Written by Clay McLeod"[:width-1] | |
keystr = "Last key pressed: {}".format(k)[:width-1] | |
statusbarstr = "Press 'q' to exit | STATUS BAR | Pos: {}, {}".format(cursor_x, cursor_y) | |
if k == 0: | |
keystr = "No key press detected..."[:width-1] | |
# Centering calculations | |
start_x_title = int((width // 2) - (len(title) // 2) - len(title) % 2) | |
start_x_subtitle = int((width // 2) - (len(subtitle) // 2) - len(subtitle) % 2) | |
start_x_keystr = int((width // 2) - (len(keystr) // 2) - len(keystr) % 2) | |
start_y = int((height // 2) - 2) | |
# Rendering some text | |
whstr = "Width: {}, Height: {}".format(width, height) | |
stdscr.addstr(0, 0, whstr, curses.color_pair(1)) | |
# Render status bar | |
stdscr.attron(curses.color_pair(3)) | |
stdscr.addstr(height-1, 0, statusbarstr) | |
stdscr.addstr(height-1, len(statusbarstr), " " * (width - len(statusbarstr) - 1)) | |
stdscr.attroff(curses.color_pair(3)) | |
# Turning on attributes for title | |
stdscr.attron(curses.color_pair(2)) | |
stdscr.attron(curses.A_BOLD) | |
# Rendering title | |
stdscr.addstr(start_y, start_x_title, title) | |
# Turning off attributes for title | |
stdscr.attroff(curses.color_pair(2)) | |
stdscr.attroff(curses.A_BOLD) | |
# Print rest of text | |
stdscr.addstr(start_y + 1, start_x_subtitle, subtitle) | |
stdscr.addstr(start_y + 3, (width // 2) - 2, '-' * 4) | |
stdscr.addstr(start_y + 5, start_x_keystr, keystr) | |
stdscr.move(cursor_y, cursor_x) | |
# Refresh the screen | |
stdscr.refresh() | |
# Wait for next input | |
k = stdscr.getch() | |
def main(): | |
curses.wrapper(draw_menu) | |
if __name__ == "__main__": | |
main() |
To get less flickering, use stdscr.erase() instead of stdscr.clear(), see this S.O answer.
Thank you!
Thank you for the code. When ran in the terminal, it does good to represent some of the major functionalities of the curses library 👍
Thanks!
Thank you!
Thank you for great example.
thanks
thank you.
why do you have the import for sys, and os if you don't use them in your code?
I added stdscr.keypad(True)
to make the cursor move.
great little snippet, I just tested it with the latest termux build from github on android and it works great.
very nice!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I also thank Clay for his very nice code example. I took it on myself to improve it a little by adding code to more cleanly clear out the keycode line(s) and to get all three curses "key read" functions to show the results for getch(), get_wch() and getkey() all for the same single keystroke entered.
Copy pasted below if anyone is interested.
Edit: After seeing unexpected failures of the getkey() code on Linux systems using the ncursesw library (though it never failed on Windows systems using the PDCurses library underneath) , I asked for some help on the bug-ncurses mailing list, and discovered that the unget_wch() function does not know what to do with a non-character (i.e., arrow keys, Home, End, F1, etc.). Instead, if get_wch() returns an integer representing one of those "non-printing" keys, you must use ungetch() to put that key back in order for a subsequent getkey() or get_wch() to be able to retrieve it again.
I have updated the code below to reflect that technique.
Peter