Unix - ncurses ui

From NoskeWiki
Jump to navigation Jump to search

About

NOTE: This page is a daughter page of: Unix and Python


ncurses (new curses) is a programming library that provides an API which allows the programmer to write text-based user interfaces in a terminal-independent manner. It is a toolkit for developing "GUI-like" application software that runs under a terminal emulator.

If you've ever wanted to write a good interactive command line program which doesn't scroll continually this is a good option! Better yet, there is a python library for it. On this page I'll focus on how to use python to generate these (see curses Python API).


Ncurses Examples Using Python

Ncurses Hello World

ncurses_hello_world.py

#!/usr/bin/env python
# ncurses_hello_world.py - minimal ncurses example with default border.

import curses
screen = curses.initscr()  # Initialize curses.

# Clear screen and draw default border:
screen.clear()
screen.border(0)
screen.addstr(10, 30, 'Hello world!')  # Row 10, row 30

screen.refresh()      # Redraw screen.
opt = screen.getch()  # Wait for user to enter character.
curses.endwin()       # End screen (ready to draw new one, but instead we exit)

# If you wanted a second screen you'd start with screen.clear and repeat here.


Ncurses with Color

my_ncurses_with_color.py

#!/usr/bin/env python
# my_ncurses_with_color.py - very basic demonstration of ncurses with color
# plus a fancy border.

import curses

screen = curses.initscr()  # Initialize curses.
curses.start_color()       # Must call this before creating pairs.

# Create hardcoded color pairs (foreground/background) to use:
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_WHITE)
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)

# Clear screen and draw custom border:
screen.clear()
screen.border(curses.ACS_VLINE, curses.ACS_VLINE,
              curses.ACS_DIAMOND, curses.ACS_DIAMOND)
# NOTE: 0 will be normal style border, here the order is:
# left, right, top, bottom

# NOTE: First two arguments of addstr are row and col position.
screen.addstr(1, 4, 'Ncurses with color, featuring:')
screen.addstr(2, 4, '  > Underlined text', curses.A_UNDERLINE)
screen.addstr(3, 4, '  > Blue on white', curses.color_pair(2))
screen.addstr(4, 4, '  > Bold, blinking and red', curses.A_BOLD |
              curses.A_BLINK | curses.color_pair(3))
screen.addstr('     ... press any key to exit')

screen.refresh()      # Redraw screen.
opt = screen.getch()  # Wait for user to enter character.
curses.endwin()       # End screen (ready to draw new one, but instead we exit)

Some things to note:

  • To enable colors, you must call "curses.start_color()", which you should call immediately after "curses.initscr()"
  • By enabling color the background seems to turn solid black, regardless of what color/transparency you had configured your terminal as.
  • You must use color pairs.
  • The colors you can use are the standard 8 [colors]..... but you case use the constants:
    • COLOR_BLACK, COLOR_BLUE, COLOR_CYAN, COLOR_GREEN, COLOR_MAGENTA, COLOR_RED, COLOR_WHITE, COLOR_YELLOW
  • And for formatting you have:
    • A_ALTCHARSET, A_BLINK, A_BOLD, A_DIM, A_NORMAL, A_REVERSE, A_STANDOUT, A_UNDERLINE


Ncurses with Simple Menu

my_first_ncurses_menu_ui.py

#!/usr/bin/env python
# my_first_ncurses_menu_ui.py - simple interactive command line
# program generated using 'ncurses ui'.
# This example has four options:
#    > option 1:   prompts for more input
#    > option 2&3: execute basic bash commands.
#    > option 4:   exits back to bash prompt.
# This can be a good base to build a more sophisticated interative program.

import os
import curses


def get_param(prompt_string):
  """Brings up new screen asking user to enter a single parameter.
  
  Args:
      prompt_string: Prompt which asks/tells user what to enter (string).
  """
  screen.clear()
  screen.border(0)
  screen.addstr(2, 2, prompt_string)
  screen.refresh()
  input = screen.getstr(10, 10, 60)
  return input


def execute_cmd(cmd_string):
  """Clears the screen, executes the given system command and shows the result.
    
  Args:
      cmd_string: Unix/system command to execute.
  """
  os.system('clear')
  a = os.system(cmd_string)
  print ''
  if a == 0:
    print 'Command executed correctly: ' + cmd_string
  else:
    print 'Command terminated with error'
  raw_input('Press enter')
  print ''

# Init screen with global var:
screen = curses.initscr()

def main():
  opt = 0
  while opt != ord('4'):

    screen.clear()
    screen.border(0)
    screen.addstr(2, 2, 'Please enter a number...')
    screen.addstr(4, 4, '1 - Print happy birthday    (custom input)')
    screen.addstr(5, 4, '2 - Output date                     (date)')
    screen.addstr(6, 4, '3 - Show disk space                (df -h)')
    screen.addstr(7, 4, '4 - Exit')
    screen.refresh()

    opt = screen.getch()  # Wait for user to enter a character.

    if opt == ord('1'):
      names = get_param('Enter your name, or comma-seperated names')
      age = get_param('Enter your age')
      curses.endwin()
      print '\n\nHappy birthday ' + names + '. You are ' + age + '!\n\n'
      raw_input('Press enter (to return to main)')
    if opt == ord('2'):
      curses.endwin()
      execute_cmd('date')
    if opt == ord('3'):
      curses.endwin()
      execute_cmd('df -h')

  curses.endwin()


if __name__ == '__main__':
    main()

Note, this example was modified from Code Project: Build an Ncurses UI with Python.


See Also

  • Newt (wikipedia) - programming library for color text mode, widget-based user interfaces. Newt can be used to add stacked windows, entry widgets, checkboxes, radio buttons, labels, plain text fields, scrollbars, etc., to text user interfaces. Programmed in C, but has porting to other languages too.
  • Text-based user interfaces (wikipedia) - lists a few of the more popular Unix text-based user interface (TUI) options.


Links


Acknowledgements: Simon Arneaud at Google for suggesting I use this for a little project I had.... otherwise I'd never have found out about it!