C語(yǔ)言實(shí)現(xiàn)一個(gè)Window控制臺(tái)帶彩色,且可以用方向鍵選擇并確認(rèn)的菜單式列表(一)
在Linux的編程里,管理列表的形式,我們可以使用VT100控制碼來(lái)進(jìn)行實(shí)現(xiàn)。因?yàn)閂T100控制碼在printf函數(shù)中就可以設(shè)置顯示的行和列,這樣實(shí)現(xiàn)一個(gè)列表選擇的GUI界面就非常容易。比如Linux內(nèi)核中的Make menuconfig。
我們可以看到像下面這樣的GUI菜單式界面,這樣的界面用Linux VT100控制碼結(jié)合C語(yǔ)言是很容易就可以實(shí)現(xiàn)出來(lái)的。
那么,在Window上想要在控制臺(tái)實(shí)現(xiàn)類似的功能,是否也可以做到呢?當(dāng)然是可以的,Window控制臺(tái)同樣提供了實(shí)現(xiàn)這樣的函數(shù)給開(kāi)發(fā)者來(lái)進(jìn)行使用。說(shuō)到選擇,那么選擇就有上下左右四個(gè)方向,可以用鍵盤(pán)上的上下左右來(lái)進(jìn)行控制選擇。
如何讀取對(duì)應(yīng)的鍵值碼呢?我們可以使用C語(yǔ)言的getch()函數(shù)獲取。通過(guò)參考百度百科:https://baike.baidu.com/item/getch()/10996394
我們知道getch()的用法如下:
getch():
所在頭文件:conio.h
函數(shù)用途:從控制臺(tái)讀取一個(gè)字符,但不顯示在屏幕上
函數(shù)原型:int getch(void)
返回值:讀取的字符
例如:
char ch;或int ch;
getch();或ch=getch();
用getch();會(huì)等待你按下任意鍵,再繼續(xù)執(zhí)行下面的語(yǔ)句;
用ch=getch();會(huì)等待你按下任意鍵之后,把該鍵字符所對(duì)應(yīng)的ASCII碼賦給ch,再執(zhí)行下面的語(yǔ)句。
明白了使用方法,現(xiàn)在我們可以用一個(gè)demo程序來(lái)測(cè)試鍵盤(pán)上按鍵的鍵值,方便我們后面實(shí)現(xiàn)列表程序:
程序:find_keyboard_code.c
[cpp] view plain copy
#include <stdio.h>
#include <conio.h>
int main(void){
int num;
printf("please input keyboard num\n") ;
while(1)
{
if((num=getch())<127)
printf("num:%d\n",num);
}
return 0;
}
現(xiàn)在我們分別來(lái)輸入鍵盤(pán)上的上下左右四個(gè)按鍵,如圖:
運(yùn)行結(jié)果:
演示過(guò)程:
我們分別得出鍵盤(pán)的上下左右的鍵值為上:72 下:80 左:75 右:77 , 其它按鍵給讀者自己去測(cè)試,這里就不再多說(shuō)了。
我們以學(xué)生信息管理系統(tǒng)為例,分別在這個(gè)黑乎乎的終端上顯示一個(gè)菜單,并且?guī)в胁噬铱梢园聪律?,下按鍵進(jìn)行選擇。菜單顯示的內(nèi)容如下,且要求內(nèi)容居中顯示:
"*學(xué)生信息添加*",
"*學(xué)生信息查找*",
"*學(xué)生信息打印*",
"*學(xué)生信息修改*",
"*學(xué)生信息刪除*",
"* 退出 *",
關(guān)于怎么在Window上顯示顏色可以參考這個(gè)博主的博客,以及一些網(wǎng)文,鏈接如下:
http://blog.csdn.net/odaynot/article/details/7722240
http://www.xuebuyuan.com/1674430.html
也可以參考我以前寫(xiě)的文章總結(jié):
http://blog.csdn.net/morixinguan/article/details/52804302
我們來(lái)實(shí)現(xiàn)這個(gè)程序,來(lái)看看效果是怎么樣的:
student_project_for_window.c
[cpp] view plain copy
#include <stdio.h>
#include <Windows.h>
#include <conio.h>
#include <stdlib.h>
#define NR(x) (sizeof(x)/sizeof(x[0]+0))
#define TITLE "學(xué)生信息管理系統(tǒng)"
#define AUTHOR "作者:楊源鑫"
#define DATE "日期:2017年8月22日"
//定義枚舉Keyboard的鍵值數(shù)據(jù)
enum
{
UP = 72,
DOWN = 80 ,
LEFT = 75 ,
RIGHT = 77 ,
ENTER = 13 ,
ESC = 27 ,
};
//定義要顯示的菜單
char *menu[] =
{
"*學(xué)生信息添加*",
"*學(xué)生信息查找*",
"*學(xué)生信息打?。?,
"*學(xué)生信息修改*",
"*學(xué)生信息刪除*",
"* 退出 *",
};
//定義結(jié)構(gòu)體
CONSOLE_CURSOR_INFO cci;
//定義默認(rèn)的坐標(biāo)位置
COORD pos = {0,0};
//顯示菜單
void showmenu(HANDLE hOut ,char **menu , int size , int index) ;
//獲取用戶輸入
int get_userinput(int *index , int size) ;
int main()
{
int i;
int ret ;
int index = 0 ;
HANDLE hOut;
SetConsoleTitleA(TITLE);
//獲取當(dāng)前的句柄---設(shè)置為標(biāo)準(zhǔn)輸出句柄
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
//獲取光標(biāo)信息
GetConsoleCursorInfo(hOut, &cci);
//設(shè)置光標(biāo)大小
cci.dwSize = 1;
//設(shè)置光標(biāo)不可見(jiàn) FALSE
cci.bVisible = 0;
//設(shè)置(應(yīng)用)光標(biāo)信息
SetConsoleCursorInfo(hOut, &cci);
while(1)
{
showmenu(hOut , menu , NR(menu) , index);
ret = get_userinput(&index , NR(menu));
if(ret == ESC)
break ;
if(ret == ENTER)
{
switch(index)
{
case 0: break ; //學(xué)生信息添加
case 1: break ; //學(xué)生信息查找
case 2: break ; //學(xué)生信息打印
case 3: break ; //學(xué)生信息修改
case 4: break ; //學(xué)生信息刪除
case 5: return 0 ;//退出
}
}
}
return 0;
}
void showmenu(HANDLE hOut ,char **menu , int size , int index)
{
int i ;
system("cls");
//設(shè)置顯示的文本的顏色
SetConsoleTextAttribute(hOut, FOREGROUND_GREEN | 0x8);
//初始化控制臺(tái)顯示的X,Y軸的坐標(biāo)
pos.X = 30;
pos.Y = 0 ;
//設(shè)置顯示到控制臺(tái)終端的具體位置
SetConsoleCursorPosition(hOut,pos);
//調(diào)用printf在控制臺(tái)對(duì)應(yīng)的位置上輸出
printf("%s",TITLE);
pos.X = 32;
pos.Y = 1 ;
SetConsoleCursorPosition(hOut,pos);
printf("%s",AUTHOR);
pos.X = 30;
pos.Y = 2 ;
SetConsoleCursorPosition(hOut,pos);
printf("%s",DATE);
for(i = 0 ; i < size ; i++)
{
//如果i==index表示在當(dāng)前選項(xiàng)的位置,默認(rèn)初始化顯示是第一項(xiàng),顯示為紅色,
//當(dāng)按下上下按鍵選擇的時(shí)候,光標(biāo)會(huì)移動(dòng),也就看到了列表選擇的現(xiàn)象
if(i == index)
{
//紅色
SetConsoleTextAttribute(hOut, FOREGROUND_RED | 0x8);
pos.X = 30;
pos.Y = 5+i;
//設(shè)置光標(biāo)坐標(biāo)
SetConsoleCursorPosition(hOut,pos);
printf("%s",menu[i]);
}
//否則顯示為白色
else
{
//白色
SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
pos.X = 30;
pos.Y = 5+i;
//設(shè)置光標(biāo)坐標(biāo)
SetConsoleCursorPosition(hOut,pos); //設(shè)置光標(biāo)坐標(biāo)
printf("%s",menu[i]);
}
}
//刷新標(biāo)準(zhǔn)輸出緩沖區(qū)
fflush(stdout);
}
//獲取用戶輸入的接口
int get_userinput(int *index , int size)
{
int ch ;
ch = getch();
switch(ch)
{
//上
//如果選擇上,那么光標(biāo)向上移動(dòng)
case UP : if(*index > 0) *index -= 1 ; break;
//下
//如果選擇下,那么光標(biāo)向下移動(dòng)
case DOWN :if(*index < size -1) *index += 1 ; break;
//左
case LEFT:
case 97:return 0 ;
//右
case RIGHT:return 0 ;
//回車(chē)
case ENTER: return ENTER ;
//ESC
case ESC: return ESC ;
}
return 0 ;
}
運(yùn)行結(jié)果:
演示結(jié)果:
當(dāng)然,程序只是實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的列表控制,后面我們?cè)賮?lái)將這個(gè)程序進(jìn)一步的完善,使它的功能更加的豐富。這樣,學(xué)生信息管理系統(tǒng)也是可以做得比較有趣的,就沒(méi)有那么單調(diào)了吧,哈哈!
如有興趣,請(qǐng)持續(xù)關(guān)注本博客,本博客將為你帶來(lái)源源不斷的干貨!
http://blog.csdn.net/morixinguan
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!