您的位置:首页 > 运维架构 > Linux

Linux/Unix下的Curses库开发指南——第七章 表单开发及应用(1)

2009-12-30 09:22 288 查看

7.1表单简介

7.1.1表单概念

UNIX中输入数据是我们最经常需要做的事情,在UNIX下定位并且进行数据输入并不是一件很容易的事情。不过curses包中提供的表单库可以大大减少我们的开发难度,表单库是从curses库发展而来,它提供了一个基本的框架结构和一些基本的功能来处理用户数据输入。通过表单我们可以进行各种输入并且可以对输入数据进行有效的校验或者规范其输入格式,在表单库中我们将输入区域称之为输入域,简称域。一个表单实际上是一页或者多页的域的组合。这些域可能用来显示标题,标签以及作为输入区域。下面的图7.1显示了一个简单的表单,包括了五个域,三个用作标签域,两个用作输入区域。
简单表单示例
输入域1:_____________
输入域2:_____________
图7.1

7.1.2编译和链结表单程序

为了能够在程序中使用表单,你必须在程序中包含表单库的头文件:
#include <form.h>
我们通过下面的命令进行编译:
gcc [flags ] files –lform –lcurses [gcc编译器,比如Linux]
或者
cc [flags ] files –lform –lcurses [cc编译器,比如ScoUnix和Solaris]

7.1.3表单库中使用的一些术语

表格7.1中列出的是一些表单程序中经常用到的术语,在这里做一些解释,以后用到的地方我们不再作重复:
表7.1表单库常用术语
术语
解释
域、表单域
表单内部的一块m X n大小的字符块,表单函数将它视为一
个单元来进行操作。
输入域
即活动域,用户可以进行访问的域,可以对它进行数据的输入,更改,选择等相关类似操作。
标签、非活动域
在整个表单的处理过程中被忽略的域。我们不能访问它,也不能对它进行操作,但是保持可见。标签也是非活动域,它通常用来作为提示等信息。
表单
一页或者多页的域的组合,相当于域的容器,所有的域都登记到表单中。
页面
表单中的域有时候不能一次在屏幕中全部显示,那么必须分成多次来进行显示,每次显示的部分逻辑上称之为一个页面。如果表单中的域必须分两次才能显示完毕,我们称表单有两个页面。

7.1.4表单中的数据结构

对于系统中的每一个表单,系统中都维护了一个FORM数据结构,同时对于每一个表单域系统中也维护了一个FIELD数据结构,这两个数据结构都定义在<form.h>中。Sco Unix和Solaris中FORM的定义如下:
typedef struct formnode {
int status; /* 表单状态标志 */
int rows; /* 表单每行的尺寸 */
int cols; /* 表单每列的尺寸 */
int currow; /* 表单中的当前行 */
int curcol; /* 表单中的当前列 */
int toprow;
int begincol;
int maxfield; /* 表单中能够容纳的域的最多个数 */
int maxpage; /* 表单的最多页面数 */
int curpage; /* 当前页面的索引 */
OPTIONS opts; /* 表单的选项属性 */
WINDOW * win; /* 表单窗口 */
WINDOW * sub; /* 表单子窗口 */
WINDOW * w; /* window */
FIELD ** field; /* 表单的关联域指针 */
FIELD * current; /* 表单中的当前域 */
_PAGE * page; /* page [maxpage] */
char * usrptr; /* 表单的用户指针 */
PTF_void forminit; /* 表单初始化时候的关联函数 */
PTF_void formterm; /* 表单终止时候的关联函数 */
PTF_void fieldinit; /* 表单域初始化时候的关联函数 */
PTF_void fieldterm; /* 表单域终止时候的关联函数 */
} FORM;
对于表单中的关联域,它的数据结构定义如下:
typedef struct fieldnode {
int status; /* 域的状态标志 */
int rows; /* 域的每行的尺寸 */
int cols; /* 域的每列的尺寸 */
int frow;
int fcol;
int drows; /* 域的动态总行数 */
int dcols; /* 域的动态总列数 */
int maxgrow; /* maximum field growth */
int nrow; /* 域的偏移行 */
int nbuf; /* 域的关联缓冲区的数目 */
int just; /* 域的对齐方式:左对齐、右对齐、居中 */
int page;
int index; /* 域在表单域中的索引 */
int pad; /* 域的填充字符 */
chtype fore; /* 域的前景属性 */
chtype back; /* 域的背景属性 */
OPTIONS opts; /* 域的选项属性 */
struct fieldnode * snext; /* sorted order pointer */
struct fieldnode * sprev; /* sorted order pointer */
struct fieldnode * link; /* linked field chain */
struct formnode * form; /* containing form */
FIELDTYPE * type; /* 域类型 */
char * arg; /* argument for type */
char * buf; /* field buffers */
char * usrptr; /* 用户指针 */
} FIELD;
另外对于FORM中的_PAGE 数据结构,它定义了表单页面的数据结构:
typedef struct {
int pmin; /* 当前页面上的第一个表单域 */
int pmax; /* 当前页面上的最后一个表单域 */
int smin; /* 域的左上角 */
int smax; /* 右下角位置 */
}_PAGE;

7.1.5表单程序开发步骤

表单的使用与菜单非常的类似,而且它们的很多概念也基本相同。为了创建表单,通
常你首先必须创建表单域,一旦创建之后你可以对表单域进行属性设置,然后将表单域与表单进行关联。这一切结束之后我们就可以将表单登记到屏幕中,从而开始接受用户的输入。在菜单中我们使用menu_driver()进行交互,在表单中我们通过form_driver()进行交互。通过给form_driver()发送各种请求,我们可以对表单以及表单域进行各种操作,包括移动光标,输入文字。用户在域中输入数据的时候或者离开输入域的时候,我们可以对输入的数据进行校验,判断其是否符合我们事先规定的数据格式。表单的整个开发步骤可以分为下面几个部分:
■ 创建表单所需要的域
在创建表单之前我们通常需要创建一些域,没有任何域的表单没有什么实际意义。表单库中提供了new_field()函数来创建,创建过程中我们可以指定域的宽度,高度以及它在表单中的位置。
■ 创建表单
使用创建的域创建表单,将域与表单进行关联。
■ 登记表单
与菜单类似,在显示表单之前必须首先使用post_form()将它登记到屏幕上,然后进行刷新显示。
■ 通过from_driver()处理终端用户的输入
■ 取消登记表单
■ 释放表单所占用空间
■ 释放域所占用空间
■ 结束curses程序

7.1.6简单表单示例程序

现在我们来创建如图7.1所示的表单程序,它演示了表单的创建和销毁过程。在这个例子中,表单中的所有的文本都是与域关联在一起的。域可能是处于活动状态,也可能处于非活动状态:活动域受表单处理过程影响,我们可以在其中输入数据,而非活动域却不受任何影响,我们不能对它进行输入,通常称之为标签。在这个例子中,有下划线的域是可以进行输入的,而标签,例如“简单表单示例”,“输入域1:”,“输入域2:”都是不允许输入的。
程序7-1 简单表单示例程序
程序名称 formsimp.c
编译命令 cc –o formsimp formsimp.c –lform –lcurses
程序使用的表单库函数:
new_field(),new_form(),post_form(),unpost_form(),free_field(),
free_form(),set_field_buffer(),set_field_opts(),set_field_back()
#include <form.h>
#include <string.h>
/*通过关闭域的O_ACTIVE属性创建标签*/
FIELD* make_label(frow,fcol,label)
int frow;
int fcol;
char* label;
{
FIELD* f=new_field(1,strlen(label),frow,fcol,0,0);
if(f)
{
set_field_buffer(f,0,label);
set_field_opts(f,field_opts(f)&~O_ACTIVE);
}
return f;
}
/*通过打开域的O_UNDERLINE属性创建输入域*/
FIELD* make_field(frow,fcol,cols)
int frow;
int fcol;
int cols;
{
FIELD * f=new_field(1,cols,frow,fcol,0,0);
if(f)
set_field_back(f,A_UNDERLINE);
return f;
}
main()
{
FORM* form;
FIELD* f[6];
int i=0;
initscr();
nonl();
raw();
noecho();
wclear(stdscr);
f[0]=make_label(0,7,"简单表单示例");
f[1]=make_label(2,0,"输入域1:");
f[2]=make_field(2,9,16);
f[3]=make_label(3,0,"输入域2:");
f[4]=make_field(3,9,16);
f[5]=(FIELD*)0;

form=new_form(f);
post_form(form);
wrefresh(stdscr);
sleep(5);

unpost_form(form);
wrefresh(stdscr);
free_form(form);
while(f[i])
free_field(f[i++]);
endwin();
exit(0);
}

7.1.7示例程序解析

程序7.1 演示了表单程序的简单使用过程,包括表单创建,表单销毁以及表单域属性设置等等。由于程序中我们没有调用form_driver(),因此目前还不能接受用户的输入,程序在运行5秒钟后自动退出。
程序的开始处是两个#include 文件。每一个表单程序都必须包括头文件form.h,这个头文件中包含了表单的一些很重要的数据结构定义及一些宏。由于函数中用到了strlen()函数,因此我们也必须包括文件string.h。

下一步,是两个程序自定义函数make_label()和make_field(),它们分别生成标签和输入域。下面就是函数的主函数main()。在主函数中我们声明了三个对象:
form 这是一个指向表单的指针
f[6] 这是与表单关联的域指针
i 这是变量的索引,程序中初始化为0
变量声明之后的五个函数用来对curses进行初始化。函数initscr()用来初始化屏幕,nonl()确保通过wgetch()获取的换行符并不会自动的产生一个新行。noecho()使得你的程序输出并不立即显示在屏幕上。wclear()清除标准屏幕。

主函数中我们用来创建表单输入域和标签的时候调用了程序自定义函数make_label()和make_field()。在这两个自定义函数中我们可以看出,不管输入域还是标签域我们都是通过调用函数new_field()来实现的。它们只是对域的属性进行了一些特别的设置,对于make_label()将创建域的O_ACTIVE属性关闭,从而变为非活动域,这样不能接受用户输入形成标签,对于make_field()则是将域的背景设置为A_UNDERLINE,从而形成输入域。

现在我们看看new_field()函数。它的第一个参数是创建的域所占的总行数。这个例子中我们将它设为1,通常情况下它们只占一行。第二个参数表示域所占的列数。这个值的最大值由该域需要容纳的最大字符个数决定。对于标签,它的长度应该为组成标签的字符串的长度决定。而对于输入域来说,它的长度应该由该域能够容纳的最大字符数目决定。第三个以及第四个参数决定了域在表单子窗口中的起始的行和列数。默认情况下,表单子窗口为stdscr。第五个参数通常用在滚动域中,表示域中第一行的偏移量,通常为0,意味着输入域是不可滚动的。最后一个参数是域关联的额外缓冲区的数目。每个域至少关联一个缓冲区,即0号缓冲区,此外你还可以关联其余的缓冲区,如果该参数为0,表示除了0号缓冲区不再需要额外的缓冲区。

表单域的0号缓冲区由系统使用,在其中将保存域的内容。因此一旦我们通过函数make_label()创建了标签,我们必须使用函数set_field_buffer()将标签内容关联到0号缓冲区中。如果你有额外的缓冲区,你也可以通过set_field_buffer()将设定的值关联到其余给定的缓冲区中。make_label()中最后调用set_field_opts()将这个域的O_ACTIVE选项关闭。这意味着这个域是非活动的,不会接受任何的输入。这正是标签的特点。

另一方面,make_field()函数一旦创建了一个域之后,它将域的背景属性设置为A_UNDERLINE。这样的效果就是这个域加上了下划线,通过这个下划线,我们可以明显的区分标签和输入域,而且能够清楚输入域的位置。

一旦你为表单创建了所需要的域之后,你可以使用new_form()创建表单了。函数接受一个域数组指针作为参数,同时将它与表单关联起来。new_form()返回的指针保存在变量form中,这个变量在后面的相关表单函数中被应用。为了显示该表单,函数post_form()将它登记到默认的子窗口stdscr中。函数wrefresh()真正的刷新显示窗口。这种显示仅持续5秒钟。

在这个时候应该是大多数的表单程序接受和处理终端用户输入的时候。这个程序并不接受终端的输入。接受输入的程序在后面的章节进行讨论。
5秒显示之后为了清除表单,你首先必须使用unpost_form()将它从登记中取消。函数将表单从子窗口中清除。只有调用wrefresh()函数之后,清除才发生效果。函数free_form()将它与域数组指针断开关联。在while循环中,我们将从域数组的第一个开始,将数组中的域释放。结果就是释放每一个域的所占的空间。

在上面的这个例子中我们仅仅用到了一部分的表单函数。下面的部分我们将介绍所有的表单函数。每一个函数介绍的时候我们都象前面介绍菜单的时候给出一些程序片断或者完整演示程序。

7.2表单域应用

7.2.1创建和释放表单域

为了能够创建表单,你首先必须使用new_field()创建表单所需要的域。new_field()函数语法如表7.2所示:
表7.2 表单域创建函数概述
头文件
curses.h form.h
概述
FIELD *new_field(rows,cols,firstrow,firstcol,nrow,nbuf)
int rows,cols,firstrow,firstcol,nrow,nbuf;
域与菜单项不同,一个菜单项总是占一行的空间,而表单中的域却可能占一行或者更多行的空间。函数new_field()函数创建并且初始化一个rows X cols大小的域。域与表单子窗口的左上角的相对位置为(firstrow,firstcol)。变量rows和cols的值必须大于0,而firstrow、firstcol、nrow、nbuf的值必须大于或者等于0。


变量nrow是域的行偏移量。屏幕上域的显示的行数总是为rows。事实上域的实际行数应该为(rows+nrow),它们关系见图7.2。如果nrow为0,则显示行数与实际行数相同,域中所有内容都可以显示出来。如果nrow不为0,则某个时刻屏幕上只能显示域的部分内容,因此对于域的不可见部分,我们必须通过滚动来操作。
图7.2
变量nbuf是分配给域的额外的缓冲区数目,所有的域都有一个默认的缓冲区,即就是0号缓冲区。0号缓冲区中保存了域的值。终端用户对域进行的任何改动都会映射到0号缓冲区中。如果算上0号缓冲区,则域关联的缓冲区数目应该为(nbuf+1)。每一个域缓冲区的大小为((rows+nrow)*cols+1)。除了0号缓冲区之外,其余的缓冲区你都可以自由使用。比如,你可以使用这些缓冲区支持Undo操作,一旦域中的内容发生变化你就将它的值保存到额外的缓冲区中,以备用来Undo。

为了创建一个一行高,三十二列宽的域,在表单子窗口中的起点为(2,5),行偏移量为2,附加缓冲区的个数为3,代码如下:
FIELD *occupation;
occupation = new_field(1,32,2,15,2,3);
除了使用new_field()创建一个新的域之外,我们还可以使用dup_field()和link_field()从已经存在的域进行复制或者链接,从而产生新的域,它们的函数语法见表7.3。
表7.3 表单域复制函数概述
头文件
curses.h form.h
概述
FIELD *dup_field(field,firstrow,firstcol)
FIELD *field;
int firstrow,firstcol;

FIELD *link_field(field,firstrow,firstcol)
FIELD *field;
int firstrow,firstcol;
dup_field()将一个存在的域复制到另外的一个新的位置(firstrow,firstcol)。在初始化期间,dup_field()几乎拷贝域的所有的属性包括它的大小、缓冲区信息以及其余的相关属性。不过有些属性,比如“该域可能是某页的第一个域”之类的信息是不可能拷贝到新的域中的。一旦函数执行成功,将会产生两个独立的域,它们分别拥有自己的空间,并且相互之间没有任何影响。
与dup_field()相同的是,函数link_field() 也是在同一表单或者不同表单的指定位置复制存在的域。与dup_field()不同的是,这种复制并不包括域缓冲区,即两个域同时共享所有的域缓冲区,包括0号缓冲区。因此如果一个域发生了任何的变化,它将修改该域的缓冲区,同时修改的也是另外一个域的缓冲区,这样一个域的变化将同时影响两个域的内容。这种特点可以用来生成动态标签。
需要注意的是link_field()创建的两个域之间仅仅共享缓冲区。任何一个域的其余的属性更改都不会影响另外一个域。

考虑前面的创建的域occupation ,如果需要将它复制到位置(3,15),然后链接到(4,15),函数代码如下:
FIELD *dup_occ, *link_occ;
dup_occ = dup_field(occupation 3,15);
link_occ = link_field(occupation , 4 ,15);
如果函数new_field(),dup_field()和link_field()函数的指针为NULL,则函数执行失败。如果分配给域的内存不够或者当前域与表单关联,则可能导致失败。
下面我们给出一个完整的程序7-2,其中演示了new_field(),dup_field(),link_field()的用法。程序如下:
程序7-2 dup_field()、link_field()函数使用示例
程序名称 link_field.c
编译命令 cc –o link_field link_field.c –lform –lcurses
程序使用的表单库函数:
new_field(),new_form(),post_form(),unpost_form(),free_field(),
free_form(),set_field_buffer(),set_field_opts(),set_field_back(),
link_field(),dup_field()
#include <curses.h>
#include <form.h>
int main()
{
FIELD *field[4];
FORM *my_form;
int ch;

initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);

field[0] = new_field(1, 10, 4, 18, 0, 0);
field[1] = dup_field(field[0], 6, 18);
field[2] = link_field(field[0], 8, 18);
field[3] = NULL;

set_field_back(field[0],A_UNDERLINE);
set_field_back(field[1],A_UNDERLINE);
field_opts_off(field[2], O_ACTIVE);

my_form = new_form(field);
post_form(my_form);
refresh();

mvprintw(4, 9, "表单域 1:");
mvprintw(6, 9, "表单域 2:");
mvprintw(8, 9, "表单域 3:");
mvprintw(LINES - 30, 10, "使用方向键进行移动!");
refresh();

set_current_field(my_form, field[0]);
while((ch = getch()) != KEY_F(1))
{ switch(ch)
{
/*如果是↓键或者或者回车键,将移到下一个表单域*/
case KEY_DOWN:
case 10://回车键
form_driver(my_form, REQ_NEXT_FIELD);
break;
/*如果是↑,则移动到上一个表单域*/
case KEY_UP:
form_driver(my_form, REQ_PREV_FIELD);
break;
/*如果是其余的字符,则打印*/
default:
form_driver(my_form, ch);
break;
}
}
unpost_form(my_form);
free_form(my_form);
free_field(field[0]);
free_field(field[1]);
free_field(field[2]);

endwin();
return 0;
}
程序执行结果如图7.3所示:



图7.3
在运行程序的过程中,应该留意表单域1对域3的影响。一旦光标离开域,域3的内容将更新为与域1相同的内容,这一点证明了使用link_field()链结生成的两个域的确是共享域缓冲区的。

在程序结束后我们应该将分配给域的空间收回,这可以通过free_field()实现。它的参数是先前通过new_field(),dup_field(),link_field()创建的域指针。在释放之前必须确保释放的域与表单不关联。如果关联的话首先必须断开。free_field()的语法如表7.4所示。
表7.4 表单域释放函数概述
头文件
curses.h form.h
概述
int free_field(field)
FIELD *field;
为了释放一个表单以及与它关联的所有的域,代码通常可以如下:
FORM *form;
FIELD **f = form_fields(form);
free_form(form);
while(*f)
free_field(*f++);
如果释放成功,函数返回E_OK,否则它返回如表7.5所示的错误码:
表7.5 free_field()出错信息
返回errno 错误码 错误信息
-1 E_SYSTEM_ERROR 内存分配错误
-2 E_BAD_ARGUMENT 不存在的域或者参数域为NULL
-3 E_CONNECTED 域与表单关联,不能释放
一旦表单中的某个域被释放,它就不能再使用。因为释放的域指针并不指向真正的域。如果这样做的话可能会导致一些莫名其妙的问题发生。

7.2.2表单域缓冲区

在使用new_fields()创建表单域的时候,我们会同时创建nbuf个缓冲区与它关联。缓冲区的个数通常视程序的需要而设定,但至少有一个缓冲区,即0号缓冲区。0号缓冲区由系统保留使用,通常用来保存关联域的值。通过函数set_field_buffer()我们可以将数据写入缓冲区,通过field_buffer()可以获取给定缓冲区的数据。
表7.6 表单域创建函数概述
头文件
curses.h form.h
概述
int set_field_buffer(field,buffer_num,value)
FIELD *field;
int buffer_num;
char *value;

char *field_buffer(field,buffer_num)
FIELD *field;
int buffer_num;
set_field_buffer()用来将value写入与域关联的第buffer_num个缓冲区中。参数buffer_num的值必须在0到 nbuf之间。nbuf是使用new_field()创建域的时候附加的缓冲区的数目。如果设置的value的长度超出了域的长度,则value的值将被截断。
在下面的代码中,假设你的应用程序将域的默认值保存在域的1号缓冲区中。下面的代码可以将当前域的值恢复为默认值。
#define VAL_BUF 0
#define DFL_BUF 1
void reset_current(form)
FORM *form;
{
FIELD *f=current_field(form);
set_field_buffer(f,VAL_BUF,field_buffer(f,DFL_BUF));
}
如果set_field_buffer()函数执行成功,返回E_OK,否则返回表7.7所示的错误码:
表7.7 set_field_buffer()函数出错信息
返回值 错误码 错误信息
-1 E_SYSTEM_ERROR 内存分配错误
-2 E_BAD_ARGUMENT 给定的域不存在
对于field_buffer(),如果参数为NULL或者buffer_num的值超出了nbuf范围,它将返回NULL。如果域不是当前域,函数field_buffer()总是能够返回正确的值。然而,如果域是当前域,则这个函数的返回值不一定准确。 因为在用户输入数据后,输入的值并不会立即写入到0号缓冲区中,所以函数返回的可能是写入以前的值。为了确保field_buffer()总是返回正确的值,在调用函数之前必须保证域中的值能够写入0号缓冲区中,因此函数调用必须保证在下面的几种情况下:
■ 在表单域校验函数中进行调用
■ 在表单域或者表单初始化以及中断函数中调用
■ 在REQ_VALIDATION请求调用之后进行调用

7.2.3获取域的尺寸和位置信息

在创建域的时候我们传递给函数new_field()一些参数,有的时候我们需要获取这些参数,一方面可以直接操作FIELD数据结构,获取相关结构成员,但这不是一个很好的方法。另一方面我们可以通过函数field_info()获取,它允许你获取域定义尺寸大小、位置、行偏移量以及关联的缓冲区数目等属性。Field_info()函数语法如表7.8所示。
表7.8表单域信息获取函数概述
头文件
curses.h form.h
概述
int field_info(field,rows,cols,firstrow,firstcol,nrow,nbuf)
FIELD *field;
int *rows, *cols, *firstrow, *firstcol , *nrow, *nbuf;
在下面的代码中我们使用field_info()获取指定域的缓冲区大小。我们通过获取屏幕上域的行数以及行偏移量累计获得域的总行数,然后与域的列数相乘计算得到域的总的缓冲区大小,计算方法为(屏幕行数+偏移行数)*总列数+1:
int bufsize(f)
FIELD *f;
{
int rows,cols,firstrow,firstcol,offrow,nbuf;
field_info(f,&rows,&cols,&firstrow,&firstcol,&offrow,&nbuf);
return (rows+offrow)*cols +1;
}
如果函数field_info()执行成功,返回E_OK,否则返回如表7.9所示的错误码:
表7.9 field_info()出错信息
返回值 错误码 错误信息
-1 E_SYSTEM_ERROR 系统错误
-2 E_BAD_ARGUMENT 不存在的表单域,即没有通过new_field()创建或
者已经通过free_field()进行释放

7.2.4设置域对齐方式

我们在表单域中进行输入的时候,可以设置数据的对齐方式,或是左对齐,或是右对齐,或是居中对齐或是不采取任何对齐方式。但是对齐方式的设置仅仅适用于单行域,对于多行域则不适用。如果对多行域进行对齐调整,则某行的调整可能影响到下一行的内容。因此即使你对多行域设置对齐方式,对齐设置也不会产生作用。我们通过set_field_just()对域进行对齐调整,语法如表7.10所示。
表7.10表单域对齐调整函数概述
头文件
curses.h form.h
概述
int set_field_just(field,justification)
FIELD *field;
int justification;

int field_just(field)
FIELD *field;
如果函数执行成功,set_field_just()返回E_OK,否则,返回如表7.11所示的错误码:
表7.11 set_field_just()出错信息
返回值 错误码 错误信息
-1 E_SYSTEM_ERROR 系统错误
-2 E_BAD_ARGUMENT 不存在的表单域
-12 E_REQUEST_DEFINE 调整请求被忽略
关于域中数据的对齐方式curses中提供了如表7.12所示的四种方式:
表7.12表单域数据对齐方式
对齐方式
描述
NO_JUSTIFICATION
没有任何对齐方式
JUSTIFY_LEFT
左对齐
JUSTIFY_RIGHT
右对齐
JUSTIFY_CENTER
居中对齐
不管你将域设置成什么对齐方式,在你输入数据和编辑数据的时候,它们并不会按照设定的对齐方式排列,系统会自动的将它们调整为左对齐。只有用户离开域进行校验的时候域的对齐方式才会真正的进行调整到设置方式。默认情况下,域是没有任何对齐方式的。

例如,将域field1 设置为左对齐,同时将field2域设置为右对齐,则代码如下:
FIELD *field1 , *field2;
set_field_just(field1,JUSTIFY_LEFT);
set_field_just(field2,JUSTIFY_RIGHT);

field_just()函数返回指定域的对齐方式,如果函数执行成功,则返回NO_JUSTIFIC
ATION、JUSTIFY_LEFT、JUSTIFY_RIGHT、JUSTIFY_CENTER,分别对应表7.12的描述的四种方式。
与大多数的curses函数相同,如果函数的域指针设置为NULL,它将设置和获取当前域对齐方式的默认值。例如,下面的代码将居中对齐方式设置为域的默认对齐方式。
set_field_just((FIELD *)0,JUSTIFY_CENTER);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: