优化屏幕刷新

问题
刷新多个窗体需要一些繁琐,在一个慢速的链接上,屏幕的绘制相当的慢
目标就是要尽量减少要在屏幕上的绘制的字符数

基本函数
int wnoutrefresh(WINDOW *window_ptr);
决定哪些字符需要发送到屏幕,但是并不实际的发送
int doupdate(void);
向终端发送实际的改变

说明
如果只是简单地调用wnoutrefresh,其后立即调用doupdate,其效果就如同调用wrefresh一样
如果希望重新绘制一个窗体栈,可以在每一个窗体(以正确的顺序)上调用wnoutrefresh函数,然而在最后一个wnoutrefresh函数之后调用doupdate函数
这使得curses按顺序在每一个窗体上执行屏幕更新计算,并且只输出更新的屏幕。这会使得curses尽量减少需要发送的字符数

WINDOW *subwin(WINDOW *parent, int lines, int cols, int y, int x);
subwin函数具有与newwin几乎相同的参数列表
子窗体的删除方式也与其他的窗体使用一个delwin调用方式相同
与新窗体类似,可以使用一系列的 mvw函数将数据写入子窗体中,但有一点重要区别
子窗体本身并不会存储一个单独的屏幕字符集,他们与子窗体创建时所指定的父窗体共享存储空间
这就意味着子窗体中的任何改动也同时会发生在底层的父窗体中,所以当一个子窗体被删除时,屏幕并不会发生变化
int delwin(WINDOW *window_to_delete);

在将sub_window_ptr指向subwin的调用结果之后,就将子窗体变得可以滚动
甚至是在子窗体被删除而基窗体(strdcr)已经刷新之后,屏幕上的文本仍然保持原样
这是因为子窗体实际更新的是stdscr的字符数据

keypad模式

功能键的处理
在大多数终端会发送一个以转义字符开始的字符串
这些程序所具有的不仅是单击Escape键和由按下一个功能键所引起的字符串之间区别的问题,而且必须使用相同逻辑按键的不同序列来处理不同的终端
curses提供了一个优雅的实用功能来管理这些功能按键
对于每一个终端,每一个功能键所发送的字符序列都会被存储,通常是存储在一个terminfo结构中
所包含的头文件curses.h具有一个以KEY_为前缀的定义部分定义了逻辑按键
当curses启动时,序列与逻辑按键之间的转换就被禁止,必须使用keypad函数来打开
int keypad(WINDOW *window_ptr, bool keypad_on);
如果函数调用成功则会返回OK,否则返回ERR

keypad模式的三个限制

转义序列的识别是时间相关的
许多网络协议将字符组装到数所包中(会导致不能正确识别转义序列)
或者是分割他们(从而会导致功能按键序列会被识别为Escape与单个的字符)
唯一解决办法
进行编程,使用信号来处理希望使用的每一个功能按键,为其发送单一、唯一的字符
为使curses可区分按下Escape与以Escape开头的键盘序列,必须等待一小段时间
有时,一旦打开keypad模式,Escape按键处理上的一个非常小的延时也会被注意到
curses不能处理不唯一的转义序列
如果终端有可以发送相同序列的两个不同的按键,curses只是简单的不处理这个序列,因为他不能确定应返回哪一个逻辑按键

彩色显示

大多数早期的curses版本不支持颜色
颜色被ncurses以及大多数现在的curses实现所支持
curses中的颜色支持有一些不同,其原因在于每一个字符的颜色并不是独立于其底色而定义的
所以必须同时定义前景色与背景色,即所谓的颜色对

bool has_colors(void);
如果支持颜色,has_colors就会返回真
int start_color(void);
进行颜色初始化,如果颜色初始化成功,则返回OK
初始化COLORS和COLOR_PAIR
COLORS:终端所支持的最多的颜色数目
COLOR_PAIR:用户可以定义的色彩对的最大数目
系统颜色
COLOR_BLACK 0 黑色COLOR_RED 1 红色
COLOR_GREEN 2 绿色
COLOR_YELLOW 3 黄色
COLOR_BLUE 4 蓝色
COLOR_MAGENTA 5 洋红色
COLOR_CYAN 6 蓝绿色, 青色
COLOR_WHITE 7 白色

初始化颜色对

int init_pair(short pair_number, short foreground, short background);
用于更改一个彩色对的定义
彩色对是Curses的一个概念,它用一个整型数值去标志一对前景/背景彩色
pair_number:彩色对数值,其范围从1到 COLOR_PAIRS-1
f:指定前景彩色
b:指定背景彩色
int COLOR_PAIR(int pair_number);
int pair_content(short pair_number, short *foreground, short *background);

初始化颜色过程

定义颜色对1,使其背景色为绿色而前景色为红色
init_pair(1, COLOR_RED, COLOR_GREEN);
使用COLOR_PAIR将这个颜色作为一个属性来进行访问
wattron(window_ptr, COLOR_PAIR(1));
将屏幕设置为绿色的背景色以及红色的前景色
说明
因为COLOR_PAIR是一个属性,所以可以将其与其他的属性进行组合
在PC上,经常可以通过使用位或操作符组合COLOR_PAIR属性与A_BOLD属性来获得屏幕的亮度
wattron(window_ptr, COLOR_PAIR(1) | A_BOLD);

重新定义颜色

在初始化颜色的时候改变某个颜色的RGB值
init_color(COLOR_RED, 700, 0, 0);参数1 : 颜色名称
参数2, 3, 4 : 分别为R(red),G(green),B(blue)的数值
最小值:0
最大值:1000
如果显示终端无法改变颜色设置,函数将返回ERR
can_change_color()
监测终端是否可以支持颜色改变

pad

背景
期望得到一个比实际物理屏幕更大的逻辑屏幕,并且每次只显示逻辑屏幕的部分内容
窗口缺陷
所有窗体必须不大于物理屏幕
pad功能
操作并不适合普通窗体的逻辑屏幕信息
pad结构与WINDOW结构相类似
所有可以用于向窗体输出的函数也可以用于pad
但pad具有其特殊的创建与刷新例程

WINDOW *newpad(int lines, int columns);
返回一个指向WINDOW的指针,与newwin函数相同
删除pad使用delwin函数,与窗体相同
pad并没有限定一个特定的屏幕位置,必须指定希望pad出现在屏幕上的区域
int prefresh(WINDOW *pad_ptr, int pad_row, int pad_column, int screen_row_min, int screen_col_min, int screen_row_max, int screen_col_max);
创建一个pad区域,由(pad_row, pad_column)开始
所定义的区域为(screen_row_min, screen_col_min)到(screen_row_max, screen_col_max)

可视化菜单界面设计

init_curses()函数
initscr初始化指针接着
start_color来显示彩色
curs_set(0)屏蔽掉物理指针
noecho()将终止键盘上的输入会在屏幕上显示出来
void init_cures(){initscr();start_color();init_pair(1,COLOR_WHITE,COLOR_BLUE);init_pair(2,COLOR_BLUE,COLOR_WHITE);init_pair(3,COLOR_RED,COLOR_WHITE);curs_set(0);noecho();keypad(stdscr,TRUE);
}
void draw_menubar(WINDOW *menubar){wbkgd(menubar,COLOR_PAIR(2));waddstr(menubar,"Menu1");wattron(menubar,COLOR_PAIR(3));waddstr(menubar,"(F1)");wattroff(menubar,COLOR_PAIR(3));wmove(menubar,0,20);waddstr(menubar,"Menu2");wattron(menubar,COLOR_PAIR(3));waddstr(menubar,"(F2)");wattroff(menubar,COLOR_PAIR(3));
}

draw_menubar()函数说明
定义一个显示在屏幕最顶部的菜单栏
实际上是stdscr窗体的一个子窗体,该子窗体只有 一行
程序将指向该子窗体的指针作为它的参数
首先改变它的背景色,接着定义菜单的文字
使用waddstr定义菜单 的文字
wattron调用另一不同颜色对(序号3)以取代缺省的颜色对(序号2)
2号颜色对在最开始就 由wbkgd设置成缺省的颜色对
wattroff函数可以让我们切换到缺省的颜色对状态

WINDOW **draw_menu(int start_col){int i;WINDOW **items;items=(WINDOW **)malloc(9*sizeof(WINDOW *));items[0]=newwin(10,19,1,start_col);wbkgd(items[0],COLOR_PAIR(2));box(items[0],ACS_VLINE,ACS_HLINE);items[1]=subwin(items[0],1,17,2,start_col+1);items[2]=subwin(items[0],1,17,3,start_col+1);items[3]=subwin(items[0],1,17,4,start_col+1);items[4]=subwin(items[0],1,17,5,start_col+1);items[5]=subwin(items[0],1,17,6,start_col+1);items[6]=subwin(items[0],1,17,7,start_col+1);items[7]=subwin(items[0],1,17,8,start_col+1);items[8]=subwin(items[0],1,17,9,start_col+1);

draw_menu()函数说明
显示当按下F1或者F2键显示的菜单
定义一个在蓝色背景上 菜单栏颜色一样的白色背景窗体
新窗口不应被显示在背景色上的字覆盖掉,它应该停留在那里直到 关闭菜单
因此菜单窗体不能定义为stdscr的子窗体
窗体items[0]是用newwin函数定义的,其他8个窗体则都是定义成items[0]窗体的子窗体
items[0]被用来绘制一个围绕在菜单旁边的边框,其他窗体则用来显示菜单中选中的单元
同样的,他们不会覆盖掉菜单上的边框
函数中倒数第三句使得菜单中的第一个单元背景色和其他的不一样,这是因为菜单弹出来后,第一个单元是选中状态(区别选中和没选中的状态)

void delete_menu(WINDOW **items,int count)
{int i;for (i=0;i<count;i++)delwin(items[i]);free(items);
}
int scroll_menu(WINDOW **items,int count,int menu_start_col){int key;int selected=0;while (1) {key=getch();if (key==KEY_DOWN || key==KEY_UP) {wbkgd(items[selected+1],COLOR_PAIR(2));wnoutrefresh(items[selected+1]);if (key==KEY_DOWN) {selected=(selected+1) % count;} else {selected=(selected+count-1) % count;}
  wbkgd(items[selected+1],COLOR_PAIR(1));wnoutrefresh(items[selected+1]);doupdate();} else if (key==KEY_LEFT || key==KEY_RIGHT) {delete_menu(items,count+1);touchwin(stdscr);refresh();items=draw_menu(20-menu_start_col);return scroll_menu(items,8,20-menu_start_col);} else if (key==ESCAPE) {return -1;} else if (key==ENTER) {return selected;}}
}

scroll_menu()函数说明
允许在菜单选择项上上下移动
通过getch读取键盘上的键值
如果按下上移或下移方向键,菜单选择项的上一个项或者下一个项被选中
如果是向左或向右 方向键,当前菜单将会关闭,另一个菜单打开
如果按下回车键,则返回选中的单元值
如果按下ESC键,菜单将会被关闭,并且没有任何选择项
getch能从键盘上读取键值
这是因为程序开始使用keypad(stdscr,TRUE)
将返回值赋给一个int型变量而不是char型变量,这是因为int型变量能表示比char型更大的值

int main(){int key;WINDOW *menubar,*messagebar;init_curses();bkgd(COLOR_PAIR(1));menubar=subwin(stdscr,1,80,0,0);messagebar=subwin(stdscr,1,79,23,1);draw_menubar(menubar);move(2,1);printw("Press F1 or F2 to open the menus. ");printw("ESC quits.");refresh();
 do {int selected_item;WINDOW **menu_items;key=getch();werase(messagebar);wrefresh(messagebar);if (key==KEY_F(1)) {menu_items=draw_menu(0);selected_item=scroll_menu(menu_items,8,0);delete_menu(menu_items,9);if (selected_item<0)wprintw(messagebar,"You haven't selected any item.");elsewprintw(messagebar,"You have selected menu item %d.",selected_item+1);
touchwin(stdscr);refresh();} else if (key==KEY_F(2)) {menu_items=draw_menu(20);selected_item=scroll_menu(menu_items,8,20);delete_menu(menu_items,9);if (selected_item<0)wprintw(messagebar,"You haven't selected any item.");elsewprintw(messagebar,"You have selected menu item %d.",selected_item+1);touchwin(stdscr);refresh();}} while (key!=ESCAPE);

Linux - 可视化菜单界面设计相关推荐

  1. [转]用Eclipse进行可视化Java界面设计

    http://www.diybl.com/course/3_program/java/javashl/200726/11950.html 最近,Eclipse开源项目终于推出了期待已久的Visual ...

  2. linux的应用界面设计,技术|Xperience UI 设计理念:优雅的 Linux 桌面设计欣赏

    Xperience UI 是一个基于 Nitrux 发行板的一个界面设计的概念作品,如果其开发能够完成,它将有可能成为当今最漂亮的桌面之一. 即使有些人很会折腾并使他们的桌面装扮得更帅些,但是大多数 ...

  3. Linux操作系统 系统界面设计

    目录 一.系统要求 二.系统功能 三.总体设计 1.系统整体逻辑的程序流程图 2.game功能模块逻辑的程序框图 3.高级功能模块的程序流程图 四.具体实现 1. 主菜单 2.用户信息 3.文件目录管 ...

  4. 详解使用NetBeans IDE 8.2进行可视化图形界面设计——高仿QQ登录界面

    目录 前言 QQ登录界面的设计与实现 1.新建一个Java项目 2.在任意包下新建一个JFrame窗体类 3.添加图片 4.设置账号文本框(JTextField)与密码框(JPasswordField ...

  5. 界面设计原则(china ui)

    作者:未知 来源:ChinaUI 1.设计原则 (1)用户原则.人机界面设计首先要确立用户类型.划分类型可以从不同的角度,视实际情况而定.确定类型后要针对其特点预测他们对不同界面的反应.这就要从多方面 ...

  6. 一个开源经典的MCU菜单框架设计

    来源:嵌入式专栏 不知道有多少人折腾过液晶显示的菜单,我觉得很多人都应该搞过,我还记得以前大学参加电子设计竞赛获奖的作品,我就用到了一个12864,里面有菜单功能. 以前可能觉得菜单高大上,其实并不是 ...

  7. 一个产品级MCU菜单框架设计

    关注+星标公众号,不错过精彩内容 转自 | 嵌入式云IOT技术圈 微信公众号 | 嵌入式专栏 不知道有多少人折腾过液晶显示的菜单,我觉得很多人都应该搞过,我还记得以前大学参加电子设计竞赛获奖的作品,我 ...

  8. 好东西大家分享: 微软界面设计指导

    假如你在Windows环境下开发,微软定义了一套称为"用户体验"的参考规范(当然,"用户体验"的内容已经超出了狭义的"用户界面").这个规范 ...

  9. python界面设计模块_Python+Pycharm+PyQT5可视化程序设计入门

    AD: 购买本站源码请联系QQ677123或右侧QQ在线. 一个优秀的程序必须要有友好的可视化交互界面GUI.Python有很多GUI开发的框架,像我之前常用的是自带的Tkinter,对于一些小功能不 ...

最新文章

  1. MSCKF理论推导与代码解析
  2. dos命令关闭所有dos窗口
  3. EOS 智能合约源代码解读 (10)token合约“简介”
  4. jQuery 事件 - ready() 方法
  5. 从激活windows10家庭中文版到企业版再到开启Hyper-V
  6. tuples_通过字典赋值
  7. wav格式的音频文件 16位转化成8位的
  8. 基于Python的SVM算法深入研究
  9. Vue购物商城项目(一)
  10. c#一个项目同时兼容浩辰cad和AutoCad
  11. SAP Open SQL
  12. MSP MCU I2C入门指南
  13. Python--站在巨人肩膀上
  14. 微信小程序wx.setClipboardData复制文本
  15. 让XP系统支持GPT硬盘
  16. 《这样思考,人生就不一样》/《思考的整理学》 博客思听 2010年1月
  17. 中国商界的顶级秘法之一:民营企业的五层次策划
  18. CRAFT: Character Region Awareness for Text Detection ---- 论文阅读笔记
  19. 微信 WCDB 正式开源——高效易用的移动数据库框架
  20. mysql数据库应用经典案例_MySQL数据库“十宗罪”(十大经典错误案例)

热门文章

  1. 7-17 爬动的蠕虫
  2. 油耗笔记OilNote-记油耗App
  3. java.lang.NullPointerException: null无堆栈信息
  4. DP(动态规划)入门(一)
  5. 阶乘因式分解(一)/java
  6. 卡尔曼滤波Kalman Filtering:介绍
  7. 【Build】关于-fPIC, -fpic, -fpie, -fPIE的一点理解
  8. 智能网卡的网络加速技术
  9. 如何看待 12 月 26 日发布的华为云 WeLink 企业智能工作平台?能对标得过企业微信和钉钉吗?
  10. NaN是什么? NaN == NaN 的结果是什么?为什么?