curses
-------------------------------------------------------------
Curses:CUI
UI: User Interface.
GUI: 字符界面
CUI: 图形界面
使用一套封装库 libcurse.so
/ust/lib 目录下
编译程序的时候需要指定 -lcurses
老版本: libcurses.so
新版本: libncurses.so
--------------------------------------------------------------------------------
printf/scanf 是标准IO
大部分标准IO可以重定向到终端。/dev/tty 或者 /dev/pts/1
curses不是标准输出,是终端输出,无法重定向。
注意: 为了防止printf重定向到终端破坏UI,建议不要在curses中使用标志IO
1. 编程模型
初始化终端 initscr
操作终端(输入/ 输出/ 定位/刷新……)
释放终端 endwin
2.显示
2.1 图形输出
border-------------在指定窗口输出一个边界
box-----------------在指定窗体输出一个边界
hline----------------水平线
vline-----------------垂直线
属性字符: 字节= 属性字节+ 字符字节。
注意:
box 需要窗体
initscr 返回被初始化的窗体:标准屏幕
实际上curses 定义了一个全局stdscr就是标准屏幕。
curses 库函数命名规则:
×××××× 标准屏幕stdscr进行操作
w×××× 指定窗体
mv××× 指定位置
mvw××× 指定窗体的指定位置
2.2 刷屏
void refresh(); 只刷标准屏幕
void wreesh(WINDOW*); 刷指定窗体的屏幕
原则: 从里到外刷
2.3 字符输出
addchar();
属性字符:一个字符加上属性(' ' | 属性 )(比如让字符加粗,加上下划线)
如: mvaddch(2,10,'A' | A_BOLD);
常见属性的宏定义如下:
Name Description
────────────────────────────────────────────────────────────
A_NORMAL Normal display (no highlight)
A_STANDOUT Best highlighting mode of the terminal.
A_UNDERLINE Underlining
A_REVERSE Reverse video
A_BLINK Blinking
A_DIM Half bright
A_BOLD Extra bright or bold
A_PROTECT Protected mode
A_INVIS Invisible or blank mode
A_ALTCHARSET Alternate character set
A_ITALIC Italics (non-X/Open extension)
A_CHARTEXT Bit-mask to extract a character
COLOR_PAIR(n) Color-pair number n
______________________________________________________________________________
2.4 字符串的输出
int addstr(const char *);
2.5 格式字符串的输出
printw(const char*,..............);
3. 字符属性与颜色
3.1 判断终端释放支持颜色
bool has_colors(); (可以不用判定,现在大多数系统都支持颜色的)
3.2 初始化颜色
int start_color();
3.3 定义颜色对
int init_pair(short pair,short fore, shot );
3.4 使用颜色对(对颜色属性的访问)
COLOR_PAIR(shot pair);
3.5 设置属性
attron(); 开启属性
attroff(); 关闭属性
注意:这组函数一定要在调用了initscr之后使用
字符的颜色属性有8种
——————————————————————————
COLOR_BLACK
COLOR_RED
COLOR_GREEN
COLOR_YELLOW
COLOR_BLUE
COLOR_MAGENTA
COLOR_CYAN
COLOR_WHITE
——————————————————————————
文档的查看:
_______________________
$ man attron
$ man addch
$ man box
$ man attron
_____________________________
这是curses的一个最简单的例子
/// cur_init.c
#include <curses.h>
int main()
{
WINDOW *w = initscr(); // 初始化终端
mvhline(2,10,'-',20);
mvvline(2,10,'|',20);
refresh();
getch(); /// 等待一个字符的输入
endwin(); /// 释放终端
return 0;
}
——————————————————————————————
makefile
cur_init:
gcc cur_init.c -omain -lcurses(记得加上库)
———————————————————————————————
字符属性与颜色的例子
/// cur_out.c
#include <curses.h>
int main()
{
initscr();
if(has_colors() == TRUE) /// 判断是否支持颜色
{
start_color(); /// 初始化颜色的显示功能
/// 颜色只能是库里面的8种颜色的组合
init_pair(1,COLOR_RED,COLOR_WHITE);
init_pair(2,COLOR_BLUE,COLOR_GREEN);
init_pair(3,COLOR_BLACK,COLOR_WHITE);
bkgd(COLOR_PAIR(3));/// 调用第3个颜色对
}
box(stdscr,0,0);
// 对颜色的访问是通过COLOR_PAIR 函数的调用完成的
mvaddch(2,10,ACS_PI | COLOR_PAIR(1));
mvaddch(2,11,ACS_PI | COLOR_PAIR(2));
// 开启字符属性
attron(COLOR_PAIR(1));
// 字符串输出
mvaddstr(5,10,"Hello 我的女神");
/// 关闭字符属性
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(2) | A_UNDERLINE);
mvaddstr(7,10,"Hello Fellow!");
attroff(COLOR_PAIR(2) | A_UNDERLINE);
/// 格式字符串输出
mvprintw(9,10,"行:%d,列:%d",LINES,COLS);// 打印行和列
getch();
endwin();
return 0;
}
截图如下,显示的非常简单
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
对乱码问题的解决方案:(编码解决)
1. 在vi设置编码 :
$:set encoding = 编码 ( gb2312 ios-8859-1 utf-8)
2. ( man gcc)
在编译器指定输出源文件编码 ( -finput-charset=gb2312)
执行文件编码(-fexec-charset=charset)
---------------------------------------------------------
$ gcc addstr.c -omain -lcurses -finput-charset=gb2312
------------------------------------------------------------------
3. 终端指定编码:(鼠标直接设置编码)
4. 系统默认编码
/etc/sysconfig /il8n 配置编码
总结: 我的结论是我使用UTF-8 始终都是乱码,只有把 编辑器 和 终端 都设置成GB2312, 乱码问题可以解决,
首先说明一点我使用的系统是 ubuntu 32位 14.04
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
案例:
1. 时间显示屏幕
1. 初始化
2. 循环显示时间,并且睡眠
/// demo2.c
#include <curses.h>
#include <time.h>
#include <unistd.h>
void init();
void drawui();
void busines();
void destroy();
main()
{
init();
drawui();
busines();
destroy();
}
void init()
{
initscr();
if(has_colors() == TRUE)
{
start_color();
init_pair(1,COLOR_RED,COLOR_WHITE);
init_pair(2,COLOR_BLACK,COLOR_GREEN);
bkgd(COLOR_PAIR(2));
}
}
void drawui()
{
box(stdscr,0,0);
}
void busines()
{
time_t tt;
struct tm *t;
while(1)
{
//取取时间
tt = time(0);
// 把时间转换为struct tm 结构体
t = localtime(&tt);
// 显示时间
attron(COLOR_PAIR(1));
mvprintw(LINES/2,(COLS-8)/2,"%02d:%02d:%02d",
t->tm_hour,t->tm_min,t->tm_sec);
attroff(COLOR_PAIR(1));
// 刷新屏幕
refresh();
sleep(1);
}
}
void destroy()
{
endwin();
}
2. 做一个登陆界面
1. 初始化
2. 绘制界面
3.等待输入
4.结束
#include <curses.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void init();
void drawLogin();
void destroy();
main()
{
init();
drawLogin();
destroy();
}
void init()
{
initscr();
if(has_colors() == TRUE)
{
start_color();
init_pair(1,COLOR_BLUE,COLOR_WHITE);
init_pair(2,COLOR_RED,COLOR_GREEN);
bkgd(COLOR_PAIR(1));
}
}
void drawLogin()
{
char *heads = "图书馆图书管理系统";
char *user = "用户[ ]";
char *pass = "密码[ ]";
box(stdscr,0,0);
attron(A_BOLD | COLOR_PAIR(2)); // 打开字符属性
mvaddstr(3,(COLS-strlen(heads)) /2,heads);
attroff(A_BOLD| COLOR_PAIR(2));
mvaddstr(6,(COLS-strlen(user))/2,user);
mvaddstr(8,(COLS-strlen(pass))/2,pass);
refresh();
}
void destroy()
{
refresh();
getch();
endwin();
}
4.键盘输入
1. 字符输入
int getch(); // 返回字符
int getstr(char *string) ; //对其返回字符串长度没有限制,很容易出现问题的
int getnstr(char *string , int number_of_character); 对读取的字符数目加以限制
举例:
/// getch.c
#include <curses.h>
main()
{
int ch;
// 初始化
initscr();
noecho(); /// 隐藏光标
// 循环输入
while(1)
{
ch = mvgetch(5,10);
// 循环显示输入
mvprintw(8,10,"你输入的是:%c(%d)",ch,ch);
}
// 释放
endwin();
}
案例:
使用键盘控制字母在屏幕上移动。
补充:
(1)noecho(); 禁止回显(输入的信息不能显示在屏幕上)
(2)curses 清除屏幕:man 3 clear
int clear (void);
int erase(void);
(3)光标控制:
得到光标位置: getsyx
设置光标位置: setsyx();
设置光标是否可见:int curs_set(int visibility); (0 不可见 1可见)
(4)keypad 模式
curses 在启动时会关闭转义序列与逻辑键之间的转换功能,该功能需要通过调用keypad函数来启用
/// demo4.c
#include <curses.h>
main()
{
int ch;
int x = 5,y = 5;
initscr();
noecho(); // 禁止回显
keypad(stdscr,TRUE); // 功能键的开启,这个必须要
mvaddch(y,x,'A'); /// 移动的是字符A
while(1)
{
ch = getch();
mvaddch(y,x,' '); // 使用空格清屏
//clrtoeol();
//clear(); // 删除整个屏幕
//erase();
switch(ch)
{
case KEY_UP:
y--;
break;
case KEY_DOWN:
y++;
break;
case KEY_LEFT:
x--;
break;
case KEY_RIGHT:
x++;
break;
}
/// 在指定位置输出
mvaddch(y,x,'A');
refresh();
}
}
最后一个小例子
#include <curses.h>
void init();
void drawUi();
void dealInput();
void destroy();
main()
{
init();
drawUi();
dealInput();
destroy();
}
void init()
{
initscr();
}
void drawUi()
{
mvaddstr(2,2,"[ ] + [ ] = [ ]");
refresh();
}
void dealInput()
{
int a , b;
int c ;
while(1)
{
mvscanw(2,4,"%d",&a);
mvscanw(2,12,"%d",&b);
mvprintw(2,23,"%d",a+b);
refresh();
}
}
void destroy()
{
endwin();
}
5. 窗体
subwin(); // 创建子窗体(坐标采用标准屏幕坐标)
derwin(); // 创建子窗体(坐标采用父窗体坐标)
总结: curses 的编程模式比较固定,用的是一套库,都是函数的调用,使用并不是很难,