`
helpbs
  • 浏览: 1161497 次
文章分类
社区版块
存档分类
最新评论

使用curses管理基于文本的屏幕--(五)

 
阅读更多

子窗体

现在我们已经探讨了多窗体,现在我们可以来看一下一类特殊的多窗体,名为子窗体。我们可以用下面的函数调用来创建和销毁子窗体:

#include <curses.h>
WINDOW *subwin(WINDOW *parent, int num_of_lines, int num_of_cols,
int start_y, int start_x);
int delwin(WINDOW *window_to_delete);

subwin函数具有与newwin几乎相同的参数列表,而子窗体的删除方式也与其他的窗体使用一个delwin调用方式相同。与新窗体类似,我们可以使用一系列的mvw函数将数据写入子窗体中。确实如此,绝大多数时候,子窗体的行为与新窗体非常类似,但是却有一点重要的区别:子窗体本身并不会存储一个单独的屏幕字符集,他们与子窗体创建时所指定的父窗体共享存储空间。这就意味着子窗体中的任何改动也同时会发生在底层的父窗体中,所以当一个子窗体被删除时,屏幕并不会发生变化。

第一眼感觉,子窗体似乎意义不大。为什么不直接将会变化发送给父窗体呢?子窗体的主要用途就是要提供一个更为简洁的方法来在另一个窗体中滚动部分内容。当编写一个curses程序时,滚动屏幕一部分的需要是十分常见的。通过使用子窗体以及滚动子窗体,我们可以达到这个目的。

使用子窗体的一个严格限制就是程序在刷新屏幕之前应调用touchwin函数。

试验--子窗体

1 首先,subscl.c的初始化代码部分使用一些文本初始化基窗体。

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main()
{
WINDOW *sub_window_ptr;
int x_loop;
int y_loop;
int counter;
char a_letter = ‘1’;
initscr();
for (x_loop = 0; x_loop < COLS - 1; x_loop++) {
for(y_loop=0;y_loop<LINES-1;y_loop++) {
mvwaddch(stdscr,y_loop,x_loop,a_letter);
a_letter++;
if(a_letter > '9') a_letter = '1';
}
} if (a_letter > 'Z') a_letter = 'A';

2 我们现在创建滚动子窗体,正如我们所建议的那样,我们必须在刷新屏幕之前"touch"父窗体。

sub_window_ptr = subwin(stdscr, 10, 20, 10, 10);
scrollok(sub_window_ptr, 1);
touchwin(stdscr);
refresh();
sleep(1);

3 然后我们创建子窗体的内容,向其中输入文本。滚动文本是通过一个循环来完成的。

werase(sub_window_ptr);
mvwprintw(sub_window_ptr, 2, 0, “%s”, “This window will now scroll”);
wrefresh(sub_window_ptr);
sleep(1);
for (counter = 1; counter < 10; counter++) {
wprintw(sub_window_ptr, “%s”, “This text is both wrapping and /
scrolling.”);
wrefresh(sub_window_ptr);
sleep(1);
}

4 在完成这个循环之后,我们删除子窗体。然后刷新基屏幕。

delwin(sub_window_ptr);
touchwin(stdscr);
refresh();
sleep(1);
  endwin();
exit(EXIT_SUCCESS);
}

工作原理

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

键区

在前面的讨论中我们已经看到了curses所提供的一些实用功能来处理键盘。许多键盘至少具有光标键与功能键。许多键盘还有键区和其他的键,例如Insert和Home。

在大多数的终端上解码这些按键是一个非常困难的事情,因为通常他们会发送一个以转义字符开始的字符串。这些程序所具有的不仅是单击Escape键和由按下一个功能键所引起的字符串之间区别的问题,而且他必须使用相同逻辑按键的不同序列来处理不同的终端。

幸运的是,curses提供了一个优雅的实用功能来管理这些功能按键。对于每一个终端,每一个功能键所发送的字符序列都会被存储,通常是存储在一个terminfo结构中,而所包含的头文件curses.h具有一个以KEY_为前缀的定义部分定义了逻辑按键。

当curses启动时,序列与逻辑按键之间的转换就被禁止了,而且必须使用keypad函数来打开。如果函数调用成功则会返回OK,否则返回ERR。

#include <curses.h>
int keypad(WINDOW *window_ptr, bool keypad_on);

一旦keypad模式通过将keypad_on参数设置为真打开后,curses就会接管按键的处理,从而读取键盘不仅会返回所按下的键,而且会返回逻辑按键的KEY_定义。

使用keypad模式时需要注意下面的三个限制:

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

试验--使用Keypad

下面所显示的是一个简短的程序,keypad.c,演示了如何使用keypad模式。当我们运行这个程序时,试着按下Escape并且要注意到当程序等待以确定Escape是一个序列的开始还是单一的一个按键时的小段延时。

1 初始化程序与curses库,我们将keypad模式设置TRUE。

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#define LOCAL_ESCAPE_KEY 27
int main()
{
int key;
initscr();
crmode();
keypad(stdscr, TRUE);

2 接下来我们必须关闭echo以及防止当光标键按下时光标进行移动。清除屏幕并显示一些文本。程序会等待每一次击键,除非他是Q,或是产生了一个错误,此时按键会被打印出来。如果击键匹配一个终端的keypad序列,那么就会打印这个序列。

noecho();
clear();
mvprintw(5, 5, “Key pad demonstration. Press ‘q’ to quit”);
move(7, 5);
refresh();
key = getch();
while(key != ERR && key != ‘q’) {
move(7, 5);
clrtoeol();
if ((key >= ‘A’ && key <= ‘Z’) ||
(key >= ‘a’ && key <= ‘z’)) {
printw(“Key was %c”, (char)key);
}
else {
switch(key) {
case LOCAL_ESCAPE_KEY: printw(“%s”, “Escape key”); break;
case KEY_END: printw(“%s”, “END key”); break;
case KEY_BEG: printw(“%s”, “BEGINNING key”); break;
case KEY_RIGHT: printw(“%s”, “RIGHT key”); break;
case KEY_LEFT: printw(“%s”, “LEFT key”); break;
case KEY_UP: printw(“%s”, “UP key”); break;
case KEY_DOWN: printw(“%s”, “DOWN key”); break;
default: printw(“Unmatched - %d”, key); break;
} /* switch */
} /* else */
refresh();
key = getch();
} /* while */
endwin();
exit(EXIT_SUCCESS);
}

分享到:
评论

相关推荐

    使用curses管理基于文本的屏幕

    Linux或者Windows+Cygwin开发环境下,使用ncerses进行文本方式的图形界面编程的指导手册!

    Linux程序设计 第6章 使用curses函数库管理基于文本的屏幕

    即使是编写基于字符的全屏幕程序,使用curses函数库的方案也更简明,而程序本身也更独立于具体的终端。在编写这类程序时,使用curses函数库更比直接使用escape转义序列容易得多。curses函数库还可以对键盘进行管理,...

    cd管理系统程序 linux

    界面部分:本程序基于Linux下运行,所以暂时用curses函数库来编写其文本屏幕。分为两个文本窗口和pad窗口实现其选项。 逻辑部分:通过unixC系统函数实现对其的输入输出管理,数据更新,用户操作管理,软件运行失败时...

    ncurses-devel-5.5-24.20060715.x86_64.rpm

    Ncurses是一个能提供功能键定义(快捷键),屏幕绘制以及基于文本终端的图形互动功能的动态库。 Ncurses是一个能提供基于文本终端窗口功能的动态库. Ncurses可以: 只要您喜欢,您可以使用整个屏幕 创建和管理一个...

    i9n:快速的cljs + nodejs终端(curses)声明式UI

    对于复杂curses应用程序(例如文件管理器,音乐播放器,基于ascii的游戏,甚至是文本编辑器)的中坚力量,除了对core.async的使用以外,对其余代码几乎没有足够的见解,因此它们始终是一个库,而不是一个框架core....

    ncurses安装包

    ncurses(new curses)是一个提供应用程序编程接口(API)的编程库,允许程序员以独立于终端的方式编写基于文本的用户界面。它是用于开发在终端仿真器下运行的“类似GUI的” 应用程序软件的工具包。它还优化了屏幕...

    Linux程序设计中文第4版.part3

    第6章 使用curses函数库管理基于文本的屏幕 第7章 数据管理 第8章 MySQL 第9章 开发工具 第10章 调试 第11章 进程和信号 第12章 POSIX线程 第13章 进程间通信:管道 第14章 信号量、共享内存和消息...

    Linux程序设计中文第4版.part1

    第6章 使用curses函数库管理基于文本的屏幕 第7章 数据管理 第8章 MySQL 第9章 开发工具 第10章 调试 第11章 进程和信号 第12章 POSIX线程 第13章 进程间通信:管道 第14章 信号量、共享内存和消息队列 第...

    Linux程序设计中文第4版.part2

    第6章 使用curses函数库管理基于文本的屏幕 第7章 数据管理 第8章 MySQL 第9章 开发工具 第10章 调试 第11章 进程和信号 第12章 POSIX线程 第13章 进程间通信:管道 第14章 信号量、共享内存和消息...

    C指针原理教程之Ncurses介绍

    Ncurses是一个能提供功能键定义(快捷键),屏幕绘制以及基于文本终端的图形互动功能的动态库。 Ncurses是一个能提供基于文本终端窗口功能的动态库. Ncurses可以: · 只要您喜欢,您可以使用整个屏幕 · 创建和管理一个...

    UNIX操作系统教程 张红光

    第1章绪论.1 1.1操作系统概述1 1.1.1建立操作系统的目标1 1.1.2操作系统是用户与计算机的接口1 1.1.3操作系统是资源管理器2 1.2UNIX系统的主要特性3 1.3UNIX系统的发展史4 1.4开源软件与UNIX的推广发展6 1.4.1开源...

    Linux程序设计 第4版.haozip01

    第6章 使用curses函数库管理基于文本的屏幕 175 6.1 用curses函数库进行编译 175 6.2 curses术语和概念 176 6.3 屏幕 178 6.3.1 输出到屏幕 179 6.3.2 从屏幕读取 180 6.3.3 清除屏幕 180 6.3.4 移动光标 180...

    Linux程序设计 第4版.haozip02

    第6章 使用curses函数库管理基于文本的屏幕 175 6.1 用curses函数库进行编译 175 6.2 curses术语和概念 176 6.3 屏幕 178 6.3.1 输出到屏幕 179 6.3.2 从屏幕读取 180 6.3.3 清除屏幕 180 6.3.4 移动光标 180...

Global site tag (gtag.js) - Google Analytics