/*
* 很久没在TC下写过程序了,本以为一个下拉菜单不出三小时就可以OK谁知道从昨天上午
* 开始到今天上午才完成。当然这里学到了些东西,以前没用过函数指针,现在这个下拉
* 菜单的菜单处理函数都用到了函数指针,调用时是直接通过函数指针,这简化了程序的
* 编写但实际上是不能那样的不同的菜单项应该有不同的处理函数,不过作为学习还是可
* 以的;以前没搞过远堆的内存,这次本来想用远堆来保存屏幕状态,但老是出错,最后
* 还是搞了个全局变量。
* 程序从 main()开始首先初始化界面,然后由用户选择菜单以调用不同的函数,最后通
* 过 ESC 键或者选择 EXIT 菜单退出。整个操作只有 ESC,回车键 和 方向键 有效。本来
* 还想设置菜单的快捷键,以及设计一些 3D 效果,考虑到初学者的接收能力和程序的复杂
* 度,最后还是从简了。
* 记得开始学 C 的时候自己就很想编个下拉菜单,那时候无从下手,对下拉菜单感到很神秘
* 嘿嘿,其实没什么,就是下面这样的。写了详细的注释供初学者参考,学了差不多两年了
* 还是改不掉写代码的坏习惯,变量名没有见名知义,神秘数字从天而降 ……
* 不知道大家是怎么写代码的,我一写就停不下来,一搞就是好几个小时,肚子饿得咕
* 咕叫,下楼都没劲,整个人就像散了架。埃,难怪说程序员做不了几年,希望自己不在那样
* 希望天下程序员身体健康 .
* ----- 江南孤峰 ------
* 2007 -- 3 -- 22
*/
/***
*** 下拉式菜单程序, 编译环境 TC 点击下载源码
*** 转载请注明出处:http://lingdlz.programfan.com
***/
#include <stdio.h>
#include <conio.h>
/* 键盘键值 */
#define ESC 0x011b
#define DOWN 0x5000
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define UP 0x4800
#define ENTER 0x1c0d
/* 一般常量宏 */
#define SHOW_HIGH BLACK /* 高亮显示子菜单 */
#define SHOW_NORMOL WHITE /* 正常显示子菜单 */
#define MAIN_MENU_C CYAN /* 当前菜单显示背景色 */
#define MENU_LENGTH 20 /* 子菜单名的字符长度 */
#define MAIN_MENU_LENGTH 10 /* 主菜单名的长度限制 */
/* 菜单以及子菜单结构 */
typedef struct menuItem{ /* 子菜单结构 */
char name[MENU_LENGTH]; /* 菜单选项 */
void (*pFun)(char *name); /* 函数指针 */
}TypeMenuItem;
typedef struct menu{ /* 菜单结构 */
int count; /* 子菜单数目 */
char name[MENU_LENGTH]; /* 菜单名 */
TypeMenuItem *pItem; /* 指向子菜单 */
}TypeMenu;
char video[2048]; /* 用来保存屏幕 */
/* 初始化屏幕界面 */
void InitFace(void){
textbackground(SHOW_HIGH);
textcolor(SHOW_NORMOL);
clrscr();
gotoxy(24,3);
printf("POPUP MENU (c)2007 -- 2088 BY DENG");
window(10,4,70,21);
textbackground(RED);
clrscr();
window(12,5,68,20);
textbackground(SHOW_HIGH);
clrscr();
window(12,5,68,7);
textbackground(BLUE);
clrscr();
}
/* 以 show[高亮或者正常]方式在屏幕输出字符串 txt */
void WriteText(int x,int y,int xx,int yy,char *txt,int show){
window(x,y,xx,yy);
textbackground(show);
textcolor((show == SHOW_HIGH ? SHOW_NORMOL : SHOW_HIGH));
clrscr();
gotoxy(2,1);
cprintf("%s",txt);
}
/* 退出程序 */
void MyExit(void){
gotoxy(1,2);
printf("press any key to exit ...");
getch();
exit(0);
}
/* 菜单处理函数,实际应用应该根据不同需要设置这些函数 */
void menu1_fun1(char* txt){
cprintf("I get:[ %s ]",txt);
}
void menu1_fun2(char* txt){
cprintf("I get:[ %s ]",txt);
}
void menu1_fun3(char* txt){
cprintf("I get:[ %s ]",txt);
}
void menu1_fun4(char* txt){
cprintf("I get:[ %s ]",txt);
MyExit();
}
void menu2_fun1(char* txt){
cprintf("I get:[ %s ]",txt);
}
void menu2_fun2(char* txt){
cprintf("I get:[ %s ]",txt);
}
void menu2_fun3(char* txt){
cprintf("I get:[ %s ]",txt);
}
void ShowHelp(char* txt){
cprintf("I get:[ %s ]",txt);
gotoxy(1,2); cprintf("Use Destination key to move");
gotoxy(1,3); cprintf("Use Enter key to select ");
gotoxy(1,4); cprintf("Use ESC Key to Exit");
}
void ShowAbout(char* txt){
cprintf("I get:[ %s ]",txt);
gotoxy(1,2); cprintf("The program is write by JiangNanGuFeng");
gotoxy(1,3); cprintf("Only for study,you can update and send");
gotoxy(1,4); cprintf("But you can't delete the followed info");
gotoxy(1,5); cprintf("MY QQ: 403324669\nEmail: lingdlz@163.com");
gotoxy(1,6); cprintf("MY Email: lingdlz@163.com");
gotoxy(1,7); cprintf("MY Blog:http://lingdlz.programfan.com");
gotoxy(1,8); cprintf("Welcome to join QQ group : 28011342");
gotoxy(16,9); cprintf("-- 2007 - 3 - 22 --");
}
/* 绘制菜单条 */
void DrawMenu(TypeMenu pMenu[],int count){
int i,xleft = 13,xright = xleft+MAIN_MENU_LENGTH;
WriteText(xleft,6,xright,6,pMenu[0].name,MAIN_MENU_C);
for(i = 1; i < count; i ++){
xleft = xright + 2; /* 2 是菜单之间的分隔长度 */
xright = xright + MAIN_MENU_LENGTH + 2;
WriteText(xleft,6,xright,6,pMenu[i].name,SHOW_NORMOL);
}
}
/* 设置相应坐标 flag 为 0 取主菜单坐标,否则取下拉菜单的坐标 */
void SetCoordinate(int *x,int *y,int *xx,int *yy,int cMenu,int cItem){
int xleft = 13,xright = xleft + MAIN_MENU_LENGTH;
*x = xleft + cMenu * (MAIN_MENU_LENGTH + 2);
if(cItem){
*y = *yy = 6 + cItem; /* 2 是菜单之间的分隔长度 */
*xx = xright + cMenu * (MAIN_MENU_LENGTH + 2) +
MENU_LENGTH - MAIN_MENU_LENGTH;
}
else{
*xx = xright + cMenu * (MAIN_MENU_LENGTH + 2);
*y = *yy = 6;
}
}
/* 显示子菜单 */
void SpreadMenu(TypeMenu pMenu[],int cMenu){
int i,x,y,xx,yy;
SetCoordinate(&x,&y,&xx,&yy,cMenu,1);
WriteText(x,y,xx,y,pMenu[cMenu].pItem[0].name,SHOW_HIGH);
for(i = 1,y ++; i < pMenu[cMenu].count; y ++,i ++)
WriteText(x,y,xx,y,pMenu[cMenu].pItem[i].name,SHOW_NORMOL);
}
/* 程序运行的主要函数 */
void RunProgram(TypeMenu pMenu[],int count){
int MenuSpread,temp; /* 菜单是否下拉 */
int cMenu,cItem; /* cMenu 当前菜单 cItem 当前子菜单 */
int x,xx,y,yy,uKey; /* uKey 接收用户输入 */
MenuSpread = cMenu = cItem = 0;
while(1){
while(!kbhit()) ; /* 等待按键 */
uKey = bioskey(0);
switch(uKey){
case ENTER:
if(MenuSpread && cItem){
puttext(12,7,68,21,video);
window(14,8,66,19); /* 信息输出区 */
textcolor(WHITE);
textbackground(BLACK);
clrscr(); /* 下面调用处理函数 */
pMenu[cMenu].pItem[cItem-1].pFun(
pMenu[cMenu].pItem[cItem-1].name );
MenuSpread = cItem = 0;
}
else{ /* 菜单下拉 */
gettext(12,7,68,21,video);
SpreadMenu(pMenu,cMenu);
MenuSpread = 1; /* 标记菜单已经下拉 */
cItem = 1; /* 第一个子菜单高亮 */
}
break;
case LEFT:
case RIGHT:
SetCoordinate(&x,&y,&xx,&yy,cMenu,0);
WriteText(x,y,xx,yy,pMenu[cMenu].name,SHOW_NORMOL);
if(MenuSpread){
if(uKey == LEFT)
cMenu = (cMenu == 0 ? count-1 : cMenu-1);
else
cMenu = (cMenu == count-1 ? 0 : cMenu+1);
puttext(12,7,68,21,video);
SpreadMenu(pMenu,cMenu);
cItem = 1;
}
else{
if(uKey == LEFT)
cMenu = (cMenu == 0 ? count-1 : cMenu-1);
else
cMenu = (cMenu == count-1 ? 0 : cMenu+1);
}
SetCoordinate(&x,&y,&xx,&yy,cMenu,0);
WriteText(x,y,xx,yy,pMenu[cMenu].name,MAIN_MENU_C);
break;
case UP:
case DOWN:
if(MenuSpread){
SetCoordinate(&x,&y,&xx,&yy,cMenu,cItem);
WriteText(x,y,xx,yy,pMenu[cMenu].pItem[cItem-1].name,SHOW_NORMOL);
temp = cItem;
if(uKey == DOWN)
cItem = (pMenu[cMenu].count == cItem ? 1 : cItem+1);
else
cItem = (cItem == 1 ? pMenu[cMenu].count : cItem-1);
if(temp > cItem)
y = yy = y - temp + cItem;
else
y = yy = y + cItem - temp;
WriteText(x,y,xx,yy,pMenu[cMenu].pItem[cItem-1].name,SHOW_HIGH);
}
else if(uKey == DOWN){ /* 菜单下拉 */
gettext(12,7,68,21,video);
SpreadMenu(pMenu,cMenu);
MenuSpread = 1; /* 标记菜单已经下拉 */
cItem = 1; /* 第一个子菜单高亮 */
}
break;
case ESC:
window(14,8,66,19);
clrscr();
MyExit();
default: break;
}
}
}
void main(void){
TypeMenu pMenu[3] = {
4,"FILE",NULL,
3,"EDIT",NULL,
2,"HELP",NULL
};
TypeMenuItem menu1[] = {
"MENU1_FILE_OPEN",menu1_fun1,
"MENU1_FILE_SAVE",menu1_fun2,
"MENU1_FILE_NEW",menu1_fun3,
"EXIT",menu1_fun4
};
TypeMenuItem menu2[] = {
"MENU2_EDIT_CUT",menu2_fun1,
"MENU2_EDIT_COPY",menu2_fun2,
"MENU2_EDIT_FIND",menu2_fun3
};
TypeMenuItem menu3[] = {
"HELP_ITEM",ShowHelp,
"HELP_ABOUT",ShowAbout
};
pMenu[0].pItem = menu1;
pMenu[1].pItem = menu2;
pMenu[2].pItem = menu3;
InitFace();
DrawMenu(pMenu,3);
RunProgram(pMenu,3);
}
评论