⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch18.htm

📁 ncurses中文说明
💻 HTM
📖 第 1 页 / 共 4 页
字号:
</pre>
</font>
<p>
<dd>
作者建议使用这个函数来检查动态表单域的属性。
</dd>
</p>
<p>
<dd>
再次调用new_field()函数,函数将会自动创建高度为一个字符的单行表单域。创建初始的高度大于一个字符的表单域自动被定义为多行表单域。
</dd>
</p>
<p>
<dd>
一个关闭了O_STATIC选项的单行表单域(动态增长的表单域)只包含一行,但是如果用户输入的数据的大小超过初始的大小的话,表单域宽度可以自动增长。显示的宽度仍然是固定的,但是可以通过水平滚动来查看超出部分的数据。
</dd>
</p>
<p>
<dd>
如同单行表单域一样,一个关闭了O_STATIC选项的多行表单域(动态增长的表单域)包含固定的宽度,但是如果用户输入的数据大小超过初始的大小的话,行数可以自动增长。可显示的宽度仍然是固定的,但可以通过纵向滚动来查看超出部分的数据。
</dd>
</p>
<p>
<dd>
上面两段非常形象的描述了表单域的动态增长行为。
</dd>
</p>
<p>
<dd>
下面介绍表单库的其他行为:
</dd>
</p>
<p>
<dd>
1、	如果某个表单域的O_STATIC选项关闭,也没有设置表单域动态增长的最大限度,O_AUTOSKIP选项将被忽略。通常情况下,当用户在表单域的最后一个位置输入数据,O_AUTOSKIP会自动向Form Driver发送REQ_NEXT_FIELD请求。但是,在一个没有设定最大增长值的动态表单域里,就没有最末的位置。但是如果定义了最大增长值,如果表单域自动增长到最大限度,O_AUTOSKIP选项也将正常工作。
</dd>
</p>
<p>
<dd>
2、	如果O_STATIC选项关闭,表单域的对齐请求也将被忽略。通常的,set_field_just 可以通过JUSTIFY_LEFT,JUSTIFY_RIGHT,JUSTIFY_CENTER来设置单行域的对齐方式。但是从定义中我们知道:一个动态增长的单行表单域包含比初始长度更多的数据,并且可以通过水平滚动查看这些数据。因此,这些都超过了set_field_just作用的范围。所以函数field_jus不会改变返回的结果。
</dd>
</p>
<p>
<dd>
3、	如果O_STATIC选项关闭,并且没有为表单域定义最大动态增长范围,对Form Driver发送的REQ_NEW_LINE请求将会忽略,但O_NL_OVERLOAD选项正常执行。这时,如果表单选项O_NL_OVERLOAD是打开的,如果在表单域的最后一行发送REQ_NEW_LINE请求系统将会隐式地生成并发送一个REQ_NEXT_FIELD请求。如果一个表单域可以无限制地动态增长,则没有最后一行。因此发送REQ_NEW_LINE请求就不会隐式生成REQ_NEXT_FIELD请求了。如果指定了最大动态增长的范围,并且O_NL_OVERLOAD选项是打开的。如果在表单域自动增长到最大,且用户停留在最后一行的时候就可以发送REQ_NEW_LINE请求,系统会隐式的产生并发送REQ_NEXT_FIELD请求。
</dd>
</p>
<p>
<dd>
4、	调用库函数dup_field()仍然会正常工作;它将复制这个表单域,包括当前缓冲区的大小和表单域的内容。如果指定了表单域的最大动态增长值,也将会一起被复制。
</dd>
</p>
<p>
<dd>
5、	调用库函数link_field()仍然会正常工作;它将复制表单域的所有修饰属性和所连接表单域的共享缓冲区。如果O_STATIC选项被随后的某个表单域的共享缓冲区修改了,并且输入的数据超出了当前缓冲区能够容纳的数据,那么系统对此的反应将取决于当前域的属性。
</dd>
</p>
<p>
<dd>
6、	调用库函数field_info()仍然会正常工作;变量nrow将包含开始调用new_field时的值。用户应该用上面叙述的dynamic_field_info函数来查询缓冲区的当前大小。
</dd>
</p>
<p>
<dd>
上面的有些要点只有详细了解释Form Driver后才好理解。我们会在后面的几个部分深入讲解Form Driver。
</dd>
</p>
<br>
<br>
<h3 align="left">
<a name="formwindow">
18.4、表单窗口
</a>
</h3>
<br>
<p>
<dd>
表单窗口的概念与菜单窗口的很相似。每个表单与一个主窗口和一个子窗口关联。主窗口用来显示标题、边框以及其他的东西。子窗口包含所有的表单域并且根据它们的位置显示它们。这使得创建样式灵活的表单变得很容易。
</dd>
</p>
<p>
<dd>
由于这些操作与菜单窗口的创建很相似。所以使用的函数大致相同,工作原理也大致相同。所以这里只给出一个例子,并不做过多的解释。
</dd>
</p>
<p>
例28.一个表单窗口例子
</p>
<font color="maroon">
<pre>
#include &lt;form.h&gt;

void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
int main()
{
	FIELD *field[3];
	FORM  *my_form;
	WINDOW *my_form_win;
	int ch, rows, cols;
	
	/* 初始化curses */
	initscr();
	start_color();
	cbreak();
	noecho();
	keypad(stdscr, TRUE);

	/* 初始化颜色对 */
   	init_pair(1, COLOR_RED, COLOR_BLACK);

	/* 初始化域 */
	field[0] = new_field(1, 10, 6, 1, 0, 0);
	field[1] = new_field(1, 10, 8, 1, 0, 0);
	field[2] = NULL;

	/* 设置表单域选项*/
	set_field_back(field[0], A_UNDERLINE);
	field_opts_off(field[0], O_AUTOSKIP); 
	/* 如果当前表单域已满,不跳自动跳到下一个表单域 */

	set_field_back(field[1], A_UNDERLINE); 
	field_opts_off(field[1], O_AUTOSKIP);
	
	/* 创建表单并传递 */
	my_form = new_form(field);
	
	/* 计算表单所需要的面积大小 */
	scale_form(my_form, &rows, &cols);

	/* 创建与表单相关联的窗口 */
	my_form_win = newwin(rows + 4, cols + 4, 4, 4);
	keypad(my_form_win, TRUE);

	/* 设置主窗口和子窗口 */
	set_form_win(my_form, my_form_win);
	set_form_sub(my_form, derwin(my_form_win, rows, cols, 2, 2));

	/* 在窗口的四周显示边框和标题 */
	box(my_form_win, 0, 0);
	print_in_middle(my_form_win, 1, 0, cols + 4, "My Form", COLOR_PAIR(1));
	post_form(my_form);
	wrefresh(my_form_win);
	mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
	refresh();

	/* 循环以获取用户请求 */
	while((ch = wgetch(my_form_win)) != KEY_F(1))
	{	switch(ch)
		{	case KEY_DOWN:
				/* 跳到下一个域 */
				form_driver(my_form, REQ_NEXT_FIELD);
				/* 跳到当前缓冲区的末尾 */
				/* 在最后一个字符处跳出 */
				form_driver(my_form, REQ_END_LINE);
				break;
			case KEY_UP:
				/* 跳到上一个域 */
				form_driver(my_form, REQ_PREV_FIELD);
				form_driver(my_form, REQ_END_LINE);
				break;
			default:
				/* 如果是一个普通的字符,则打印出来 */	
				form_driver(my_form, ch);
				break;
		}
	}
	/* 取消表单递送并释放内存 */
	unpost_form(my_form);
	free_form(my_form);
	free_field(field[0]);
	free_field(field[1]); 
	endwin();
	return 0;
}

void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
{	int length, x, y;
	float temp;
	if(win == NULL)
		win = stdscr;
	getyx(win, y, x);
	if(startx != 0)
		x = startx;
	if(starty != 0)
		y = starty;
	if(width == 0)
		width = 80;
	length = strlen(string);
	temp = (width - length)/ 2;
	x = startx + (int)temp;
	wattron(win, color);
	mvwprintw(win, y, x, "%s", string);
	wattroff(win, color);
	refresh();
}

</pre>
</font>
<br>
<br>
<h3 align="left">
<a name="effiency">
18.5、表单域输入的有效性检查
</a>
</h3>
<br>
<p>
<dd>
默认情况下,表单域接收任何用户输入的数据。但也可以为表单域附加输入有效性检查。这样的话,如果域里面有和检查项不相符的数据,用户就跳不出这个域了。有些检查类型也支持即时检查——即在用户输入字符的同时进行检查。
</dd>
</p>
<p>
<dd>
可以用下面的函数给表单域附加输入有效性检查:
</dd>
</p>
<font color="maroon">
<pre>
int set_field_type(FIELD *field,          	/* 要附加输入检查的表单域 */
                   FIELDTYPE *ftype,  		/* 要关联的检查类型 */
                   ...);                  	/* 其他参数 */

</pre>
</font>
<p>
<dd>
一旦为表单域附加检查类型,表单域的有效性检查类型可以这样查询:
</dd>
</p>
<font color="maroon">
<pre>
FIELDTYPE *field_type(FIELD *field);      	/* 要查询的表单域 */

</pre>
</font>
<p>
<dd>
Form Driver只检查由用户从终端输入数据的有效性。在下面的情况下,不进行有效性检查:
</dd>
</p>
<pre>
	?应用程序通过调用set_field_buffer改变表单域的数据;
	?已连接的表单域间接的被修改了——被其他连接到这个域的表单域修改。
</pre>
<p>
<dd>
下面是已定义的检查类型。你也可以自定义检查类型,虽然可以让程序更敏感、更智能,但也很麻烦。
</dd>
</p>
<p>
TYPE_ALPHA(字符输入检查模式)
</p>
<p>
<dd>
这个检查模式只接受字母,不接受空格,数字,特殊字符。这个检查模式让表单域在输入时就对输入的字符进行检查。这个检查模式可以这样设置:
</dd>
</p>
<font color="maroon">
<pre>
int set_field_type(FIELD *field,          	/* 要附加输入检查的表单域 */
                   TYPE_ ALPHA         		/* 要附加的检查模式 */
                   int width);           	/* 表单域的最大宽度 */

</pre>
</font>
<p>
<dd>
参数width指定检查数据的最小宽度。用户必须输入至少一个字符,才可以离开这个表单域。通常你会把表单域的宽度设置为这个宽度;但是如果这个最小宽度大于表单域的宽度,那么有效性检查的结果总会是“无效”。把最小宽度设置为0可以使有效性检查在任何时候结束。
</dd>
</p>
<br>
<p>
TYPE_ALNUM(字符和数字输入检查模式)
</p>
<p>
<dd>
这个检查模式同时接受字母和数字,不接受空格,特殊字符这个检查模式让表单域在输入时就对输入的字符进行检查。这个检查模式可以这样设置:
</dd>
</p>
<font color="maroon">
<pre>
int set_field_type(FIELD *field,			/* 要附加输入检查的表单域 */
                   TYPE_ AKLUNM, 			/* 要附加的检查模式 */
                   int width);			/* 表单域的最大宽度 */

</pre>
</font>
<p>
<dd>
参数width设置所检查数据的最小宽度。同TYPE_ALPHA方式一样,通常你会把表单域的宽度设置为这个宽度;但是如果这个最小宽度大于表单域的宽度,那么有效性检查的结果总会是“无效”。把最小宽度设置为0可以使有效性检查在任何时候结束。
</dd>
</p>
<br>
<p>
TYPE_ENUM(限定匹配项检查模式)
</p>
<p>
<dd>
这种检查模式检查输入到表单域的数据是否在一个给定限定的匹配项集合内,这个集合可以是一系列的字符串(例如:美国各州的仅有两个字母的邮政代码)。这个检查方式可以这样设置: 
</dd>
</p>
<font color="maroon">
<Pre>
int set_field_type(FIELD *field,          	/* 要附加输入检查的表单域 */
                   TYPE_ENUM,          		/* 要附加的检查模式 */
                   char **valuelist;     	/* 限定值的列表 */
                   int checkcase;         	/* 是否大小写敏感 */
                   int checkunique);      	/* 是否检查匹配项唯一性 */

</Pre>
</font>
<p>
<dd>
参数valuelist必须指向一系列以NULL字符结束的有效的字符串。如果参数checkcase为真,输入到表单域的字符串将区分大小写。
</dd>
</p>
<p>
<dd>
当用户退出一个附加TYPE_ENUM检查的表单域时,程序将试着自动将缓冲区内的数据补充完整数据之有效。当然,输入完整的供选的字符串是一般的做法。但是也可以输入一个供选字符串的前几个字符,表单会将其自动补充完整为有效数据。
</dd>
</p>
<p>
<dd>
默认情况下,如果你输入字符串的前几个字符,并且这几个字符在供选集合中有很多个匹配项,这前几个字符将会被匹配为第一个匹配字符串。不过,如果参数checkunique为真的话,要让输入有效,就要求匹配项在集合内是唯一的。
</dd>
</p>
<p>
<dd>
REQ_NEXT_CHOICE和REQ_PREV_CHOICE请求对这些表单域会有特殊用处。
</dd>
</p>
<br>
<p>
TYPE_INTEGER
</p>
<p>
<dd>
这种检查方式检查表单域的值是否是一个整数。这个检查方式可以这样设置: 
</dd>
</p>
<font color="maroon">
<pre>
int set_field_type(FIELD *field,          	/* 要附加输入检查的表单域  */
                   TYPE_INTEGER,        		/* 要附加的检查模式 */
                   int padding,          	/* 填充为0 */
                   int vmin, int vmax);   	/* 有效值的范围 */

</pre>
</font>
<p>
<dd>
在这种情况下的有效字符为整数,也可以是带“-”号的负整数。当用户离开这个表单域之后才检查输入值是否在规定范围之内。如果限制范围的最大值小于或者等于最小值,整数值的限制范围将被忽略。如果输入的整数通过了范围检查,函数将会自动地在这个值前面填充尽可能多的0,让其变为填充变量。
</dd>
</p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -