论坛: UNIX系统 标题: 在Unix下用C编写类Windows菜单 复制本贴地址    
作者: tysx [tysx]       登录
河南省林州市信用联社科技部 李连卿

在开发程序时,程序的界面、开放性是两个非常重要的方面,目前,在Unix系统下运行的程序的界面大都比较死板,而且,在进行功能扩充时也不是很方便。那么,能不能设计一个象 Windows那样能够按照用户要求随意调整界面,功能扩充方便的程序呢?答案是肯定的。笔者通过实践,设计了一个菜单程序,使用户在对菜单的显式样式不满意时,只需通过对菜单参数文件进行操作即可完成对菜单位置、宽度、长度、是否有边框等进行调整;在用户需要进行功能扩充时,也无须改动源程序,只须对参数文件进行操作就可将新增功能挂到菜单上。 
一 参数文件说明 
本程序需要借肋两个参数文件来实现: 
(1)、对菜单中每一项参数进行说明的文件(menu.def),它格式如下所述: 
!所属菜单代号!项顺序号!菜单项名称!外挂程序名称!下级菜单代号! 
说明: 
1、如菜单代号为"0",则表示此项属于主菜单; 
2、如外挂程序名称为"0",则表示此菜单项对应的过程在菜单程序内部或对应于一个子菜单; 
3、如下级菜单代号为"0",则表示此菜单项无下级子菜单; 
4、项顺序号同时可作为菜单热键使用。 
假如文件menu.def中有下面这一行: 
!0!3!格式化磁盘!format /dev/rfd0135ds18!0! 
它表示主菜单的第三项为格式化磁盘,它对应的执行过程为 format /dev/rfd0135ds18,本项无子菜单。 
如果用户想把自己编的实现查询功能程序XXX挂到本程序主菜单第4项上,则可在menu.def中增加下面这一行: 
!0!4!查询!XXX!0! 
(2)、对各菜单参数进行说明文件(menu.conf),其格式如下所述: 
!菜单代号!上一级菜单代号!边框标志!菜单宽度!菜单行数!菜单列数!起始横坐标!起始纵坐标! 
说明: 
1、边框标志为"0"表示无框,为"1"表示有边框; 
2、上级菜单代号为"-1",表示无上级菜单; 
3、如菜单代号为"0",表示主菜单。 
当用户对菜单显示样式不满意时,可通过调整此文件设计个性化的界面。 

二 编程实现 
本程序文件为menu.c,部分代码如下: 

#include 
#define ESC 27 
#define ENT 13 
#define REFRESH 12 
#define MAX_M 10 /* 菜单最大层数 */ 

void initial(),nomlastpos(),revcurpos(),disponepage(),dispprevline(); 
void dispnextline(),domenu(),getmenuconf(),keycont(); 
void getitem(), get_m_conf(), get_m_item(),clearwin(),execprog(); 
/* 标识每一菜单项的结构 */ 
struct menu { 
short menu_code; /* 所属菜单代号 */ 
short item_order; /* 项顺序号 */ 
char item[20]; /* 菜单项名称 */ 
char prog[80]; /* 本项菜单执行程序 */ 
short submenu_code; /* 下一级菜单编号 */ 
struct menu *next; /* 指向上一项的指针 */ 
struct menu *prev; /* 指向下一项的指针 */ 
} m_item,*head,*this,*new,*last,*scrpos,*lastscrpos,*begin,*lastbegin,*lastscr[MAX_M]; 
/* 标识每一菜单内容的结构 */ 
struct menuconf { 
short menu_code; /* 菜单代号 */ 
short last_code; /* 上一级菜单代号 */ 
short bord_flag; /* 边框标志 0--无边框 1--有边框 **/ 
short m_wight; /* 菜单显示宽度 */ 
short m_lengh; /* 每一行项数 */ 
short m_col; /* 菜单列数 */ 
short m_bx; /* 菜单起始横坐标 */ 
short m_by; /* 菜单起始纵坐标 */ 
} m_conf; 
WINDOW *menuwin, *boxwin, *curw, *lastw[MAX_M], *workwin; 
long curpos, lastcurpos, lastscrcurpos, lastmenucur[MAX_M]; 
short menu_no = 0, wno = 0; 

/* 主函数 */ 
main() 

initial(); 
getmenuconf(0); /* 取第0号菜单参数 */ 

/* 创建主窗口 */ 
menuwin=newwin(m_conf.m_lengh, m_conf.m_wight, m_conf.m_bx+1, m_conf.m_by+1); 
curw=menuwin; lastw[wno]=menuwin; 

getitem(); /* 取当前菜单各项内容 */ 
domenu(head, 0); 
endwin(); 


/* 取菜单各项参数函数 */ 
void getitem() 

FILE *fp; 
char buff[0x100]; 

/* 建边框窗口 */ 
boxwin=newwin(m_conf.m_lengh+2,m_conf.m_wight+2,m_conf.m_bx,m_conf.m_by); 
keypad(curw, TRUE); 
if (m_conf.bord_flag==1) { 
box(boxwin, 0,0 ); 
wrefresh(boxwin); 


head=NULL; 
if ((fp = fopen("./menu.def","r")) == NULL) { 
fprintf(stderr, "\n不能打开菜单定义文件\n"); 
return; 

while( fgets(buff, 0x100, fp)!=NULL) { 
get_m_item(buff); 

if (m_item.menu_code != menu_no) 
continue; 

new=(struct menu*)malloc(sizeof(struct menu)); 
if (head == NULL) { 
last = head; head = new; 

else { 
this->next = new; last = this; 

this = new; 
this->menu_code=m_item.menu_code; 
this->item_order=m_item.item_order; 
strcpy(this->item,m_item.item); 
strcpy(this->prog,m_item.prog); 
this->submenu_code=m_item.submenu_code; 
this->next=NULL; 
this->prev = last; 

fclose(fp); 

/* 菜单处理函数 */ 
void domenu(curscrp, curp) 
struct menu *curscrp; 
int curp; 

int i, x, y; 
struct menu *mpos; 

this = head; 
disponepage(this); 
curpos = curp; scrpos = curscrp; 
lastcurpos = lastscrcurpos = 0; 
revcurpos(); 
for(;;) { 
switch (wgetch(curw)) { 
case ENT: 
/* 有下一级菜单 */ 
if ((!strcmp(scrpos->prog, "0")) && (scrpos->submenu_code != 0)) { 
lastbegin = begin->next; 
getmenuconf(scrpos->submenu_code); 
menu_no = scrpos->submenu_code; 

wno++; 
lastmenucur[wno]=curpos; 
lastscr[wno] = scrpos; 
lastw[wno]=curw; 

workwin=newwin(m_conf.m_lengh,m_conf.m_wight,m_conf.m_bx+1,m_conf.m_by+1); 
curw=workwin; 
getitem(); 
domenu(head, 0); 

/* 是内部函数 */ 
/* 是外部可执行程序 */ 
else { 
endwin(); 
execprog(); 

break; 
case ESC: 
case 'q': 
case 'Q': 
case '0': 
/* 无上级菜单 */ 
if (m_conf.last_code == -1) { 
clearwin(); endwin(); exit(0); 

/* 有上级菜单 */ 
else { 
menu_no = m_conf.last_code; 
clearwin(); 
getmenuconf(menu_no); 
getitem(); 
touchwin(lastw[wno]); 
curw=lastw[wno]; 
curpos = lastmenucur[wno]; 
scrpos = lastscr[wno]; 
wno--; 
wrefresh(curw); 

break; 
case 'r': 
case 'R': 
case REFRESH: /* 重显屏幕 */ 
wrefresh(curscr); 
break; 
case KEY_RIGHT: /* 右光标键 */ 
if ( scrpos->next != NULL ) { 
lastcurpos = curpos; lastscrpos = scrpos; 
scrpos=scrpos->next; 
getyx(curw, x, y); 
if((x==m_conf.m_lengh-1)&&(curpos%m_conf.m_col==m_conf.m_col-1)){ 
curpos-=(m_conf.m_col-1); lastcurpos = curpos - 1; 
/* 实现向上卷屏 */ 
wmove(curw, 0, 0); wdeleteln(curw); dispnextline("R"); 

else 
curpos++; 
if ((curpos%m_conf.m_col == 0) && (m_conf.m_lengh == 1)) { 
revcurpos(); break; 

else { 
nomlastpos(); revcurpos(); 


break; 
case KEY_LEFT: /* 左光标键 */ 
if ( scrpos->prev != NULL ) { 
lastcurpos = curpos; lastscrpos = scrpos; 
scrpos=scrpos->prev; 
getyx(curw, x, y); 
if ((x==0) && (curpos%m_conf.m_col ==0)) { 
curpos+=m_conf.m_col-1; lastcurpos = curpos + 1; 
/* 实现向下卷屏 */ 
winsertln(curw); dispprevline("L"); 

else 
curpos--; 
if ((curpos%m_conf.m_col==m_conf.m_col-1)&&(m_conf.m_lengh==1)) { 
revcurpos(); break; 

else { 
nomlastpos(); revcurpos(); 


break; 
case KEY_UP: /* 上光标键 */ 
lastcurpos = curpos; lastscrpos = scrpos; 
mpos = scrpos; 
for(i=0; i/td> 
if ( mpos->prev != NULL ) mpos=mpos->prev; 
else break; 

if ( i==m_conf.m_col ) { 
getyx(curw, x, y); 
if (x==0) { 
lastcurpos += m_conf.m_col; 
/* 实现向下卷屏 */ 
winsertln(curw); dispprevline("U"); 

else { 
curpos-=m_conf.m_col; 

scrpos = mpos; 
if ( m_conf.m_lengh!=1) 
nomlastpos(); 
revcurpos(); 

break; 
case KEY_DOWN: /* 下光标键 */ 
lastcurpos = curpos; lastscrpos = scrpos; 
mpos = scrpos; 
for(i=0; i/td> 
if ( mpos->next != NULL ) 
mpos=mpos->next; 
else 
break; 

if ( i==m_conf.m_col ) { 
getyx(curw, x, y); 
if (x==m_conf.m_lengh-1) { 
lastcurpos -= m_conf.m_col; 
/* 实现向上卷屏 */ 
wmove(curw, 0, 0); wdeleteln(curw); dispnextline("D"); 

else 
curpos+=m_conf.m_col; 
scrpos = mpos; 
if ( m_conf.m_lengh!=1) 
nomlastpos(); 
revcurpos(); 

break; 
default: 
beep(); 
break; 



/* 反显当前项函数 */ 
void revcurpos() 

wattrset(curw, A_STANDOUT); 
wmove(curw, curpos/m_conf.m_col, 
(curpos%m_conf.m_col)*m_conf.m_wight/m_conf.m_col+m_conf.m_col); 
wprintw(curw, "%s", scrpos->item); 
wattrset(curw, A_NORMAL); 
wrefresh(boxwin); 

/* 正常显示上一项函数 */ 
void nomlastpos() { 
wmove(curw, lastcurpos/m_conf.m_col, (lastcurpos%m_conf.m_col) 
*m_conf.m_wight/m_conf.m_col+m_conf.m_col); 
wprintw(curw, "%s", lastscrpos->item); 

/* 显示一页函数 */ 
void disponepage(first) 
struct menu *first; 

short col, row; 

begin=first; /* begin 为本页首指针 */ 
for(row=0; row/td> 
for(col=0; col/td> 
/* m_conf.m_wight/m_col为每一菜单项应占列数*/ 
wmove(curw,row,col*m_conf.m_wight/m_conf.m_col+m_conf.m_col); 
wprintw(curw, "%s", first->item); 
wrefresh(curw); 
last = first; 
first = first->next; 
if (first == NULL) { 
break; 




/* 显示上一行函数 */ 
void dispprevline(flag) 
char flag[2]; /* L-左光标引起 U-上光标引起 */ 

struct menu *tmppos; 
int tmpcurpos; 

tmpcurpos = curpos; 
tmppos = scrpos; 
if ( flag[0] == 'U') { 
while ( tmpcurpos % m_conf.m_col != 0) { 
tmppos = tmppos->prev; 
tmpcurpos--; 

tmppos = tmppos->prev; 

for (tmpcurpos = m_conf.m_col-1; tmpcurpos >= 0; tmpcurpos--) { 
wmove(curw, 0, (tmpcurpos%m_conf.m_col) 
*m_conf.m_wight/m_conf.m_col+m_conf.m_col); 
wprintw(curw, "%s", tmppos->item); 
begin = tmppos; /*begin 为本页首指针*/ 
last = tmppos; 
tmppos = tmppos->prev; 
if (tmppos == NULL) 
break; 

wrefresh(curw); 

/* 显示下一行函数 */ 
void dispnextline(flag) 
char flag[2];/* R-右光标引起 D-下光标引起 */ 

struct menu *tmppos; 
int tmpcurpos; 

tmpcurpos = curpos; 
tmppos = scrpos; 
if ( flag[0] == 'D') { 
while ( tmpcurpos % m_conf.m_col != m_conf.m_col-1) { 
tmppos = tmppos->next; tmpcurpos++; 

tmppos = tmppos->next; 


for (tmpcurpos = 0; tmpcurpos < m_conf.m_col; tmpcurpos++) { 
wmove(curw, m_conf.m_lengh-1, (tmpcurpos%m_conf.m_col) 
*m_conf.m_wight/m_conf.m_col+m_conf.m_col); 
wprintw(curw, "%s", tmppos->item); 
last=tmppos;/* last 为本页最后一个结点指针 */ 
begin=tmppos; tmppos = tmppos->next; 
if (tmppos == NULL) 
break; 


/* 取指定菜单参数函数 */ 
void getmenuconf(menu_code) 
short menu_code; 

FILE *fp; 
char menu_buff[0x100]; 

if ((fp = fopen("menu.conf", "r"))==NULL) { 
fprintf(stderr, "can not open menu config file"); 
return; 

while( fgets(menu_buff, 0x100, fp)!=NULL ) { 
get_m_conf(menu_buff); 
if (m_conf.menu_code == menu_code) 
break; 

return ; 

/* 取指定菜单参数处理函数 */ 
void get_m_conf(menu_conf) 
char *menu_conf; 

register i, j, k; 
char buff[20]; 

j = k = 0; 
for (i = 0; i < strlen(menu_conf); i++) { 
if ( menu_conf[i] == '!' ) { 
j++; 
if ( j == 1) { 
k = i+1; 
continue; 

switch(j) { 
case 2: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.menu_code = atoi(buff); 
k=i+1; 
break; 
case 3: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.last_code = atoi(buff); 
k=i+1; 
break; 
case 4: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.bord_flag = atoi(buff); 
k=i+1; 
break; 
case 5: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.m_wight = atoi(buff); 
k=i+1; 
break; 
case 6: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.m_lengh = atoi(buff); 
k=i+1; 
break; 
case 7: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.m_col = atoi(buff); 
k=i+1; 
break; 
case 8: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.m_bx = atoi(buff); 
k=i+1; 
break; 
case 9: 
memcpy(buff, &menu_conf[k], i-k); 
buff[i-k]=0; 
m_conf.m_by = atoi(buff); 
k=i+1; 
break; 
default: 
break; 




/* 取指定项参数处理函数 */ 
void get_m_item(menu_item) 
char *menu_item; 

register i, j, k; 
char buff[80]; 

j = k = 0; 
for (i = 0; i < strlen(menu_item); i++) { 
if ( menu_item[i] == '!' ) { 
j++; 
if ( j == 1) { 
k = i+1; 
continue; 

switch(j) { 
case 2: 
memcpy(buff, &menu_item[k], i-k); 
buff[i-k] = 0; 
m_item.menu_code = atoi(buff); 
k=i+1; 
break; 
case 3: 
memcpy(buff, &menu_item[k], i-k); 
buff[i-k] = 0; 
m_item.item_order = atoi(buff); 
k=i+1; 
break; 
case 4: 
memcpy(buff, &menu_item[k], i-k); 
buff[i-k] = 0; 
strcpy(m_item.item,buff); 
k=i+1; 
break; 
case 5: 
memcpy(buff, &menu_item[k], i-k); 
buff[i-k] = 0; 
strcpy(m_item.prog,buff); 
k=i+1; 
break; 
case 6: 
memcpy(buff, &menu_item[k], i-k); 
buff[i-k] = 0; 
m_item.submenu_code = atoi(buff); 
k=i+1; 
break; 
default: 
break; 




void initial() /* 自定开启 curses 函式 */ 

initscr(); 
cbreak(); nonl(); noecho(); 
intrflush(stdscr,FALSE); 
keypad(stdscr,TRUE); 
refresh(); 

/* 按键等待函数 */ 
void keycont() 

fprintf(stderr, "按键继续..."); getchar(); 

/* 运行可执行程序函数 */ 
void execprog() 

system("clear"); 
fprintf(stderr, "%s: \n", scrpos->item); 
system(scrpos->prog); 
keycont(); initial(); 
touchwin(boxwin); touchwin(curw); keypad(curw, TRUE); 
wrefresh(boxwin); wrefresh(curw); 

/* 清除窗口函数 */ 
void clearwin() 

wmove(boxwin, 0, 0); 
wclrtobot(boxwin); wrefresh(boxwin); delwin(curw); delwin(boxwin); 

三 编译说明 
该程序可用如下命令编译(在SCO OpenServer 5.05下编译通过)

地主 发表时间: 04/06 20:34

回复: none [onizuka]   论坛用户   登录
一时难懂,我可以拷贝吗

B1层 发表时间: 04/09 00:44

回复: xiaojun [xiaojun]   剑客   登录
发表在本论坛的东东,均可以自由考贝,但不可将著作权视为己有。

B2层 发表时间: 04/09 18:31

回复: cimsxiyang [cimsxiyang]   版主   登录
好东西啊!!
不错!

B3层 发表时间: 07/03 01:53

论坛: UNIX系统

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号