科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件在Unix下用C编写类Windows菜单

在Unix下用C编写类Windows菜单

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在开发程序时,程序的界面、开放性是两个非常重要的方面,目前,在Unix系统下运行的程序的界面大都比较死板,而且,在进行功能扩充时也不是很方便。

来源:中国软件网 2008年3月31日

关键字: Windows unix C++ C Linux

  • 评论
  • 分享微博
  • 分享邮件

在开发程序时,程序的界面、开放性是两个非常重要的方面,目前,在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下编译通过):cc -o menu menu.c -lcurses 

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章