The Curses Library (ncurses) provides a terminal-independent approach to controlling character screens. Curses is a standard part of most UNIX-like systems, including Linux, and it has been ported to Windows and other systems. The curses program will run on a plain text system, xterm, and other windowing console sessions, making these applications portable.
Introduction Curses
Python's standard curses provides the basic interface for the common features of "glass Telex" (Glass teletype) (in the 1970s, when the original curses library was first created, it was called a CRT). There are many ways to make interactive text-mode programs written in Python more ingenious. These methods fall into two categories.
On the one hand, some Python modules support a ncurses (curses superset) or a complete set of functions for slang (similar but independent console libraries). Most notably, there is an enhanced library (encapsulated by the appropriate Python module) that allows you to add colors to the interface.
On the other hand, many of the advanced widget libraries built on curses (or Ncurses/slang) add features such as buttons, menus, scroll bars, and various common interface devices. If you've seen applications developed with libraries such as Borland ' s Turbowindows (DOS edition), you know how appealing these features are in the text-mode console. The widgets in the widget library can be achieved by using only curses, but can also take advantage of the results of other programmers at the advanced interface. See Resources for a link to the referenced module.
This article only deals with the characteristics of curses itself. Since the curses module is part of a standard release, you can find and use it (at least in Linux or UNIX systems) without downloading the support library or other Python modules. Understanding the basic support provided by curses is useful, even if only as a basis for understanding advanced modules. Even without the use of other modules, it is easy to build beautiful and useful Python text-mode applications using curses alone. A pre-release note mentions that Python 2.0 will include an enhanced version of curses, but in any case it should be compatible with the version described here.
Application
I will discuss the wrappers written for txt2html (the text to the HTML converter described in "cute Python: My first web-based Filter agent") as a test application for this article. There are several ways to run txt2html. But in keeping with the purpose of this article, we'll look at the txt2html that runs from the command line. One way to manipulate txt2html is to provide it with a set of command-line variables that describe all aspects of the transformation to be performed, and then run the application as a batch. For occasionally used users, a friendlier user interface provides an interactive selection screen that enables the user to traverse the conversion option (providing visual feedback for the selected option) before performing the actual conversion.
The Curses_txt2html interface is based on the common top bar menu, which comes with a drop-down and nested submenu. All menu-related features are designed "from the beginning" on the curses. Although these menus lack some of the features of the more complex curses wrappers, their basic functionality is implemented by just a few lines of code using only curses. The interface also comes with a simple scrolling help box and several user input fields. The following is a screenshot of the application that shows the general layout and style.
The application on the X terminal
Applications on Linux Terminals
Encapsulating curses applications
The basic element of curses programming is the Window object. A window is an area of the actual physical screen with an addressable cursor, and the coordinates of the cursor are related to the window. You can move Windows everywhere, and you can create and delete windows without affecting other windows. In a Window object, an input or output operation occurs on the cursor, which is typically set explicitly by the input or output method, but can also be modified separately.
After you initialize curses, you can modify or completely disable the flow-oriented console input and output in various ways. This is basically the whole point of using curses. However, once the streaming console interaction is changed, if the program fails, the Python retrospective event will not be displayed in the normal way. Andrew Kuchling solves this problem using a good curses program top-level framework (see Resources for his tutorial).
The following template (essentially the same as kuchling) retains the error reporting feature on the normal command line Python:
Top-level Setup code for the Python [curses] Program
Import
curses, Traceback
if
__name__==
' __main__ ':
try
:
# Initialize Curses
STDSCR=CURSES.INITSCR ()
# Turn off echoing of keys, and enter Cbreak mode,
# where no buffering are performed on K Eyboard input
Curses.noecho ()
curses.cbreak ()
# in keypad mode, escape sequences for special keys
# (like the cursor keys) would be interpreted and
# A special value like curses. Key_left'll be returned
Stdscr.keypad (1)
main (STDSCR)
# Enter The main loop
# Set everything back T o normal
stdscr.keypad (0) Curses.echo () Curses.nocbreak () Curses.endwin ()
# Terminate Curses
except
:
# in the event of error, restore terminal to sane state.
Stdscr.keypad (0) Curses.echo () Curses.nocbreak () Curses.endwin ()
traceback.print_exc ()
# Print The exception
The try code block performs some initialization, calls the main () function to perform the actual work, and then performs the final cleanup. If an error occurs, the except code block restores the console to its default state, and then reports the exception that is encountered.
Main () event loop
Now, let's look at the main () function and see what curses_txt2html does:
curses_txt2html.py main () function and event loop
Defmain
(STDSCR):
# Frame The interface area in fixed VT100 size
global
Screen
= Stdscr.subwin (0, 0)
Screen.box ()
screen.hline (2, 1, curses. Acs_hline,
Screen.refresh ()
# Define The Topbar menus file_menu
= (
"file",
"File_func ()"
Proxy_menu = (
"proxy Mode",
"Proxy_func ()")
Doit_menu = ("Do
it!",
"Doit_func ()")
Help_menu = (
"Help",
"Help_func ()")
Exit_menu = (
"Exit",
"Exit")
# ADD the Topbar menus to Screen object
Topbar_menu (File_menu, Proxy_menu, Doit_menu,
Help_menu, Exit_menu))
Enter the Topbar menu loop
while
Topbar_key_handler ():
draw_dict ()
The main () function is easy to understand based on three parts separated by a blank line.
The first section performs general settings for the appearance of the application. To establish an expected interval between application elements, the interactive area is limited to the VT100/PC screen size (even if the actual terminal window is larger). The program draws a box around the child window and uses a horizontal line to draw the visual offset of the top bar menu.
The second section establishes the menu used by the application. function Topbar_menu () uses some techniques to bind a hotkey to an application operation and display the menu with the desired visual properties. Please obtain a source file (see Resources) to see all the code. Topbar_menu () should be very common. (Welcome to incorporate it into your own application.) It is very important that once the hotkey is bound, they are the strings contained in the second element of the menu-related byte group. For example, activating the "File" menu in the above setting invokes eval (File_func ()). This requires the application to define a function called File_func (), which requires it to return a Boolean (Boolean) value to indicate whether the application termination state is reached.
There are only two lines in the third section, but that's exactly what the entire application actually runs. The function Topbar_key_handler () is implied by its name: it waits for keystrokes and then processes them. A keystroke handler can return a Boolean false value. (If this is the case, the application terminates.) In the application, the key handler is primarily to check the key that is bound in the second paragraph. But even if your curses application binds the key in a different way than the application, you still need to use a similar event loop. The key part of the handler is likely to use the following line of code:
c = Screen.getch () # Read a keypress
The call to Draw_dict () is only the only code in the event loop. This function draws the values in several places in the screen window. But in your application, you might want to include the following line of code:
Screen.refresh () # Redraw the screen w/any new output
Added to the Draw/refresh function (or only to the event loop itself).
Get user input
The curses application obtains all user input in the form of keystroke events. We've seen it. Getch () method, now let's take a look at the example of combining. Getch () with other input methods. GETSTR (). The following is the abbreviated version of the File_func () function we mentioned earlier (it is activated by the "File" menu).
curses_txt2html.py File_func () function
Deffile_func
():
s = Curses.newwin (5,10,2,1)
s.box ()
s.addstr (1,2,
"I", hotkey_attr)
S.addstr (1,3, "
nput", menu_attr)
s.addstr (2,2,
"O", hotkey_attr)
s.addstr (2,3,
"Utput", menu_attr)
s.addstr (3,2, "
T", hotkey_attr)
s.addstr (3,3,
"ype", menu_attr)
s.addstr (1,2 ,
"", hotkey_attr)
S.refresh ()
C = S.getch ()
if
C
in
(Ord (
' I '), Ord (
' i '), curses. Key_enter):
Curses.echo () s.erase (
) screen.addstr (
5,33,
"" *43, curses. A_underline)
cfg_dict[
' source ' = Screen.getstr (5,33)
Curses.noecho ()
else
:
Curses.beep ()
s.erase ()
return
CONTINUE
This function combines several curses attributes. The first thing it does is create another window object. Because this new Window object is the actual Drop-down menu for the "File" selection, the program uses the. box () method to draw a frame around it. In window s, the program draws several drop-down menu options. The hotkey for each option is highlighted in a slightly laborious way, which contrasts with the rest of the option description. (Check out the Topbar_menu () in the full source code (see Resources) to learn a way to handle highlighting slightly automatically. The final. ADDSTR () call moves the cursor to the default menu option. Like the main screen, S.refresh () actually shows the elements that are drawn to the Window object.
After drawing a drop-down menu, the program uses a simple S.getch () call to get the user's selection. In the demo application, the menu responds to the hotkey only, but does not respond to the arrow keys or move the highlight bar. You can build these more complex menu functions by capturing additional key actions and setting up event loops in the Drop-down menu. But this example is enough to illustrate the concept.
The program then compares the keystrokes that have just been read with the various hot key values. In this case, the case of a hotkey activates the Drop-down menu option, and you can use the ENTER key to activate the default option. (The curses special key constant does not look completely reliable, and I find it necessary to add the actual ASCII value "10" to capture the ENTER key.) Note that if you want to perform character value comparisons, encapsulate the string into the Ord () built-in Python function.
When the input option is selected, the program uses the. GETSTR () method, which provides field input with the original editing capability (you can use the backspace). The input is terminated by the ENTER key, and the method returns the value entered. This value is usually assigned to a variable, as in the previous example.
To visually differentiate the input fields, I used a little trick to underline the areas where data entry would occur. In any case, this is necessary, but it adds a visual effect. Underline the following line of code:
Screen.addstr (5,33, "" *43, curses. A_underline)
Of course, the program must also remove the underscore, which is performed by the following line of code in the Draw_dict () Refresh function:
Screen.addstr (5,33, "" *43, curses. A_normal)
Conclusion
The techniques outlined here and those used in the full application source code (see Resources) should give you a rudimentary understanding of curses programming. Please use it to write your application. It is not difficult to use. To tell you the good news, there are many languages that can access the curses library in addition to Python, so the knowledge you learn about using the Python curses module also works in other languages.
If tested, the basic curses module does not meet your requirements, the Resources section provides links to a number of modules that add curses functionality and provide a very good development direction.