python 中curses封裝了c語言的curses,把c中復雜部分簡單化,比如addstr(),mvaddstr(),mvwaddstr()合並成了一個addstr()方法。
一、語法入門
1、打開和關閉一個curses 應用程序
在任何代碼執行前都先要初始化curses。初始化操作就是調用initscr()函數,如下。該函數根據不同設備返回一個window對象代表整個屏幕,這個window對象通常叫做stdscr,和c語言報錯一致。
import curses stdscr = curses.initscr()
使用curses通常要關閉屏幕回顯,目的是讀取字符僅在適當的環境下輸出。這就需要調用noecho()方法
curses.noecho()
應用程序一般是立即響應的,即不需要按回車就立即回應的,這種模式叫cbreak模式,相反的常用的模式是緩沖輸入模式。開啟立即cbreak模式代碼如下。
curses.cbreak()
終端經常返回特殊鍵作為一個多字節的轉義序列,比如光標鍵,或者導航鍵比如Page UP和Home鍵 。curses可以針對這些序列做一次處理,比如curses.KEY_LEFT返回一個特殊的值。要完成這些工作,必須開啟鍵盤模式。
stdscr.keypad(1)
關閉curses非常簡單,如下:
curses.nocbreak()#關閉字符終端功能(只有回車時才發生終端) stdscr.keypad(0) curses.echo() #打開輸入回顯功能
調用endwin()恢復默認設置
curses.endwin()
調試curses時常見的問題就是curses應用程序結束后沒有重置終端到之前的狀態,把終端弄的一團糟。python中該問題經常是因為代碼有bug,發送異常引起的。比如鍵盤敲入字符后屏幕不回顯,這讓shell用起來非常困難。
為了避免這樣的問題,可以導入curses.wrapper模塊。這個函數做了一些初始化的工作,包括上面提到的和顏色的初始化。然后再執行你提供的函數,最后重置。而且被調用的函數寫在try-catch中。
2、打開新窗口和pad
通常調用initscr()獲取一個window對象代表全部屏幕。但是很多程序希望划分屏幕為幾個小的窗口,為了重繪,擦出這些工作在小窗口中獨立進行。newwin()函數就是用來新建一個新的窗口,需要給定窗口尺寸,並返回新的window對象的。
begin_x = 20; begin_y = 7 height = 5; width = 40 win = curses.newwin(height, width, begin_y, begin_x)
注意:坐標通過是先y后x。這和別的坐標系統不同,但是根深蒂固,寫的時候就這樣現在改太晚嘍。
當調用一個方法去顯示或者擦除文本時,效果不會立即顯示。 為了減少屏幕重繪的時間,curses就先累積這些操作,用一種更有效的方式去顯示。就比如說你的程序先在窗口顯示了幾個字符,然后就清除屏幕,那就沒必要發送初始字符了,因為它們不會被顯示。
因此,curses需要你使用refresh()函數明確指出重繪窗口。
pad
pad是window的特例。pad可以比顯示的屏幕大,一次只顯示pad的一部分。創建一個pad很簡單,只需要提供寬高即可。但是刷新pad需要提供屏幕上顯示的部分pad的坐標。
pad = curses.newpad(100, 100) # These loops fill the pad with letters; this is # explained in the next section for y in range(0, 100): for x in range(0, 100): try: pad.addch(y,x, ord('a') + (x*x+y*y) % 26) except curses.error: pass # Displays a section of the pad in the middle of the screen pad.refresh(0,0, 5,5, 20,75)
同時由多個window或者多個pad,有一問題:刷新某個window或pad時屏幕會閃爍。
避免閃爍的方法:在每個window調用noutrefresh()方法。 然后使用refresh()方法的最后再調用doupdate()方法。
3、顯示文本
addscr不同格式如下:如果沒有坐標,字符顯示在上一次操作完的位置。
Form | Description |
---|---|
str or ch | Display the string str or character ch at the current position |
str or ch, attr | Display the string str or character ch, using attribute attr at the current position |
y, x, str or ch | Move to position y,x within the window, and display str or ch |
y, x, str or ch, attr | Move to position y,x within the window, and display str or ch, using attribute attr |
屬性可以讓文本高亮顯示,比如黑體,下划線,倒序,彩色顯示。
4、屬性和顏色
屬性和描述:
Attribute | Description |
---|---|
A_BLINK | Blinking text |
A_BOLD | Extra bright or bold text |
A_DIM | Half bright text |
A_REVERSE | Reverse-video text |
A_STANDOUT | The best highlighting mode available |
A_UNDERLINE | Underlined text |
屏幕第一行reverse-video顯示。
stdscr.addstr(0, 0, "Current mode: Typing mode", curses.A_REVERSE) stdscr.refresh()
curses使用前景色和背景色,可通過color_pair()方法獲取一對顏色。
使用顏色對1顯示一行
stdscr.addstr("Pretty text", curses.color_pair(1)) stdscr.refresh()
start_color()初始化了8中基本顏色:0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white。
init_pair(n,f,b)修改顏色對n,讓f為前景色,b為背景色。顏色對0天生的黑白色,不允許改。
比如:修改color1為紅色文本,白色背景:
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
使用:
stdscr.addstr(0,0, "RED ALERT!", curses.color_pair(1))
5、用戶輸入
獲取輸入一遍使用getch()方法,這個方法暫停等待用戶輸入,顯示用echo()方法。
getch()返回一個整數 ,在0到255之間,表示輸入字符的ASCII值。打印255的是些特殊字符,比如Page Up,Home。
代碼經常這樣寫
while 1: c = stdscr.getch() if c == ord('p'): PrintDocument() elif c == ord('q'): break # Exit the while() elif c == curses.KEY_HOME: x = y = 0
getstr()獲取一個字符串。因為功能有限不常用。
curses.echo() # Enable echoing of characters # Get a 15-character string, with the cursor on the top line s = stdscr.getstr(0,0, 15)
二、例子
代碼如下:
#-*- coding: UTF-8 -*- import curses stdscr = curses.initscr() def display_info(str, x, y, colorpair=2): '''''使用指定的colorpair顯示文字''' global stdscr stdscr.addstr(y, x,str, curses.color_pair(colorpair)) stdscr.refresh() def get_ch_and_continue(): '''''演示press any key to continue''' global stdscr #設置nodelay,為0時會變成阻塞式等待 stdscr.nodelay(0) #輸入一個字符 ch=stdscr.getch() #重置nodelay,使得控制台可以以非阻塞的方式接受控制台輸入,超時1秒 stdscr.nodelay(1) return True def set_win(): '''''控制台設置''' global stdscr #使用顏色首先需要調用這個方法 curses.start_color() #文字和背景色設置,設置了兩個color pair,分別為1和2 curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) #關閉屏幕回顯 curses.noecho() #輸入時不需要回車確認 curses.cbreak() #設置nodelay,使得控制台可以以非阻塞的方式接受控制台輸入,超時1秒 stdscr.nodelay(1) def unset_win(): '''控制台重置''' global stdstr #恢復控制台默認設置(若不恢復,會導致即使程序結束退出了,控制台仍然是沒有回顯的) curses.nocbreak() stdscr.keypad(0) curses.echo() #結束窗口 curses.endwin()
if __name__=='__main__': try: set_win() display_info('Hola, curses!',0,5) display_info('Press any key to continue...',0,10) get_ch_and_continue() except Exception,e: raise e finally: unset_win()
執行:# python testcurses.py
三、排錯
報錯:
[root@yl-web-test srv]# python curses.py Traceback (most recent call last): File "curses.py", line 2, in <module> import curses File "/srv/curses.py", line 4, in <module> stdscr = curses.initscr() AttributeError: 'module' object has no attribute 'initscr'
原因:因為我的文件取名是curses.py,而系統也是用的curses.py,python執行時先從當前目錄查找,所以不能和系統文件重名。
換個名字,比如改名為testcurses.py 就好了。
參考:
https://docs.python.org/2/howto/curses.html
本文作者starof,因知識本身在變化,作者也在不斷學習成長,文章內容也不定時更新,為避免誤導讀者,方便追根溯源,請諸位轉載注明出處:http://www.cnblogs.com/starof/p/4703820.html有問題歡迎與我討論,共同進步。