Linux - 可视化菜单界面设计
优化屏幕刷新
问题
刷新多个窗体需要一些繁琐,在一个慢速的链接上,屏幕的绘制相当的慢
目标就是要尽量减少要在屏幕上的绘制的字符数
基本函数
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 - 可视化菜单界面设计相关推荐
- [转]用Eclipse进行可视化Java界面设计
http://www.diybl.com/course/3_program/java/javashl/200726/11950.html 最近,Eclipse开源项目终于推出了期待已久的Visual ...
- linux的应用界面设计,技术|Xperience UI 设计理念:优雅的 Linux 桌面设计欣赏
Xperience UI 是一个基于 Nitrux 发行板的一个界面设计的概念作品,如果其开发能够完成,它将有可能成为当今最漂亮的桌面之一. 即使有些人很会折腾并使他们的桌面装扮得更帅些,但是大多数 ...
- Linux操作系统 系统界面设计
目录 一.系统要求 二.系统功能 三.总体设计 1.系统整体逻辑的程序流程图 2.game功能模块逻辑的程序框图 3.高级功能模块的程序流程图 四.具体实现 1. 主菜单 2.用户信息 3.文件目录管 ...
- 详解使用NetBeans IDE 8.2进行可视化图形界面设计——高仿QQ登录界面
目录 前言 QQ登录界面的设计与实现 1.新建一个Java项目 2.在任意包下新建一个JFrame窗体类 3.添加图片 4.设置账号文本框(JTextField)与密码框(JPasswordField ...
- 界面设计原则(china ui)
作者:未知 来源:ChinaUI 1.设计原则 (1)用户原则.人机界面设计首先要确立用户类型.划分类型可以从不同的角度,视实际情况而定.确定类型后要针对其特点预测他们对不同界面的反应.这就要从多方面 ...
- 一个开源经典的MCU菜单框架设计
来源:嵌入式专栏 不知道有多少人折腾过液晶显示的菜单,我觉得很多人都应该搞过,我还记得以前大学参加电子设计竞赛获奖的作品,我就用到了一个12864,里面有菜单功能. 以前可能觉得菜单高大上,其实并不是 ...
- 一个产品级MCU菜单框架设计
关注+星标公众号,不错过精彩内容 转自 | 嵌入式云IOT技术圈 微信公众号 | 嵌入式专栏 不知道有多少人折腾过液晶显示的菜单,我觉得很多人都应该搞过,我还记得以前大学参加电子设计竞赛获奖的作品,我 ...
- 好东西大家分享: 微软界面设计指导
假如你在Windows环境下开发,微软定义了一套称为"用户体验"的参考规范(当然,"用户体验"的内容已经超出了狭义的"用户界面").这个规范 ...
- python界面设计模块_Python+Pycharm+PyQT5可视化程序设计入门
AD: 购买本站源码请联系QQ677123或右侧QQ在线. 一个优秀的程序必须要有友好的可视化交互界面GUI.Python有很多GUI开发的框架,像我之前常用的是自带的Tkinter,对于一些小功能不 ...
最新文章
- MSCKF理论推导与代码解析
- dos命令关闭所有dos窗口
- EOS 智能合约源代码解读 (10)token合约“简介”
- jQuery 事件 - ready() 方法
- 从激活windows10家庭中文版到企业版再到开启Hyper-V
- tuples_通过字典赋值
- wav格式的音频文件 16位转化成8位的
- 基于Python的SVM算法深入研究
- Vue购物商城项目(一)
- c#一个项目同时兼容浩辰cad和AutoCad
- SAP Open SQL
- MSP MCU I2C入门指南
- Python--站在巨人肩膀上
- 微信小程序wx.setClipboardData复制文本
- 让XP系统支持GPT硬盘
- 《这样思考,人生就不一样》/《思考的整理学》 博客思听 2010年1月
- 中国商界的顶级秘法之一:民营企业的五层次策划
- CRAFT: Character Region Awareness for Text Detection ---- 论文阅读笔记
- 微信 WCDB 正式开源——高效易用的移动数据库框架
- mysql数据库应用经典案例_MySQL数据库“十宗罪”(十大经典错误案例)
热门文章
- 7-17 爬动的蠕虫
- 油耗笔记OilNote-记油耗App
- java.lang.NullPointerException: null无堆栈信息
- DP(动态规划)入门(一)
- 阶乘因式分解(一)/java
- 卡尔曼滤波Kalman Filtering:介绍
- 【Build】关于-fPIC, -fpic, -fpie, -fPIE的一点理解
- 智能网卡的网络加速技术
- 如何看待 12 月 26 日发布的华为云 WeLink 企业智能工作平台?能对标得过企业微信和钉钉吗?
- NaN是什么? NaN == NaN 的结果是什么?为什么?