coolblog(個人博客):http://blog.coolight.cool/
0.效果圖
可以用方向鍵進行選擇,看起來高級點而且可以防止亂輸入。
1.引入:
這是我以前經常寫的選擇:
相信這應該也是很多人在控制台的時候會用的吧,
的確這個簡單容易寫。
但!是!
人要有理想,控制台也是
所以我開始想把它寫成一般游戲那種上下選擇的樣子:
所以就有了這篇博文
//------接下來讓我們進入正題-----
2.思路
注意:內容代碼中使用了我自定義的命名空間coolfun
如果必要請自行修改
我們首先把這部分cout出來
然后我們需要使用到控制台里的光標移動函數gotoxy()(頭文件:<windows.h>)
圖中最后的白塊就是光標,光標在哪,cout輸出的東西就會從那開始。(應該都是懂的吧...)
注意:gotoxy()並不是c++標准庫里的,windows.h里其實也沒有這玩意,
所以我們需要借助<windows.h>來自己“寫一個”。
void light_gotoxy(int x, int y) { COORD pos = { (short)x,(short)y }; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hOut, pos); }
這里的X是橫坐標,Y 是縱坐標。
借助gotoxy()移動到選項前的空白
怎么移動呢??
直接看圖里,選項“自動模式”是在第3行,我們編程老傳統默認0為開始,所以這應該認為是第2行。
gotoxy(0,2);//把光標移動到第2(實際第3)行第0(實際第1)個。
然后在這里cout << ">>>" ;
就會有這樣的效果:
看起來已經有點感覺了!
然后我們只需要監控鍵盤的方向鍵,控制“>>>”的上下就可以了。
怎么樣,聽起來是不是簡簡單單!
但!是!
僅僅依靠這一個移動光標的函數是不夠的,
因為在讓選擇的這部分字打印之前經常是會有一些其他的提示,
抑或是之前已經有了一些輸出了,例如:
我們是要把它搞成一個可以經常用的函數
不可能每次需要就自己數數在哪一行開始輸出選項並移動
所以我們需要一個函數來獲取在這之前光標的位置。
light_getxy() : 獲取當前光標所在位置
void light_getxy(int& x, int& y) { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(hConsole, &csbi); x = csbi.dwCursorPosition.X; y = csbi.dwCursorPosition.Y; }
把行數+1那就是下一行,然后開始cout我們我們的選項就可以了。
到這解決了輸出位置的問題了
具體的讓我們來看看實現代碼吧。
這就是我們這篇博文的主體函數:
template<typename T> int switch_case(int case_num, const T* content_str) { int nowi = 1, nowx, nowy;//nowi 記錄選擇的選項編號 coolfun::light_getxy(nowx, nowy); cout << "<--請用上下鍵選擇 | Enter鍵確定-->"; coolfun::light_gotoxy(nowx, nowy + 1); const T* p = content_str; cout << ">>> " << *(p++); for (int i = 2; i <= case_num; ++i) //先打印選項內容 { coolfun::light_gotoxy(nowx, nowy + i); cout << " " << *(p++); } coolfun::light_gotoxy(nowx, nowy + case_num + 1); coolfun::kbhit_remove();//清除殘留按鍵 for (int getnum;;) //等待按鍵按下,getnum記錄按鍵asc { getnum = coolfun::kbhit_wait_getasc(); coolfun::light_gotoxy(nowx, nowy + nowi); //移動到原來的編號選項前 cout << " "; //覆蓋掉它的">>>" switch (getnum) //獲取按下的按鍵的ask2值 { case 72: //上 { if (nowi > 1) //在第一個再按上鍵會到最后一個 --nowi; else nowi = case_num; }break; case 80: //下 { if (nowi < case_num) //在最后一個按下鍵會到第一個 ++nowi; else nowi = 1; }break; case 13: //Enter鍵確定 { coolfun::light_gotoxy(nowx, nowy + nowi); cout << "-->"; coolfun::light_gotoxy(nowx, nowy + case_num + 1); return nowi; //返回當前選項編號 }break; } coolfun::light_gotoxy(nowx, nowy + nowi);//移動到修改后的位置 cout << ">>>"; coolfun::light_gotoxy(nowx, nowy + case_num + 1); //把光標移動回輸出的最后 } return 0; }
其中還用到兩個按鍵相關的函數
頭文件:<conio.h>
//清空按鍵緩沖區,防止之前的殘留按鍵行為的影響 void coolfun::kbhit_remove() { while (_kbhit()) _getch(); } //等待按鍵並讀取按下按鍵的 ASC碼 int coolfun::kbhit_wait_getasc() { int num; do { num = _getch(); } while (_kbhit()); return num; }
最后讓我們來找給簡單的例子測試一下。
3.測試代碼
使用時只需要把coolfun整個復制過去並加上頭文件<windows.h>和<conio.h>
就可以調用switch_case()實現了
#include<conio.h> #include<windows.h> #include<iostream> using namespace std; namespace coolfun { //清空按鍵緩沖區,防止之前的殘留按鍵行為的影響 void kbhit_remove() { while (_kbhit()) _getch(); } //等待按鍵並讀取按下按鍵的 ASC碼 int kbhit_wait_getasc() { int num; do { num = _getch(); } while (_kbhit()); return num; } /*光標移動函數 * x為橫坐標,y為縱坐標 */ inline void light_gotoxy(int x, int y) { COORD pos = { (short)x,(short)y }; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hOut, pos); } /*獲取光標位置 * 同時獲取xy,需要傳入接受的xy變量引用 * x為橫坐標,y為縱坐標 */ inline void light_getxy(int& x, int& y) { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(hConsole, &csbi); x = csbi.dwCursorPosition.X; y = csbi.dwCursorPosition.Y; } /*選擇函數 * 返回選擇的content_str[]的位置,默認1開始 * case_num:contentstr的數組大小;contentstr[]:選項內容 * >支持偏移< */ template<typename T> int switch_case(int case_num, const T* content_str) { int nowi = 1, nowx, nowy;//nowi 記錄選擇的選項編號 coolfun::light_getxy(nowx, nowy); cout << "<--請用上下鍵選擇 | Enter鍵確定-->"; coolfun::light_gotoxy(nowx, nowy + 1); const T* p = content_str; cout << ">>> " << *(p++); for (int i = 2; i <= case_num; ++i) //先打印選項內容 { coolfun::light_gotoxy(nowx, nowy + i); cout << " " << *(p++); } coolfun::light_gotoxy(nowx, nowy + case_num + 1); coolfun::kbhit_remove();//清除殘留按鍵 for (int getnum;;) //等待按鍵按下,getnum記錄按鍵asc { getnum = coolfun::kbhit_wait_getasc(); coolfun::light_gotoxy(nowx, nowy + nowi); //移動到原來的編號選項前 cout << " "; //覆蓋掉它的">>>" switch (getnum) //獲取按下的按鍵的ask2值 { case 72: //上 { if (nowi > 1) //在第一個再按上鍵會到最后一個 --nowi; else nowi = case_num; }break; case 80: //下 { if (nowi < case_num) //在最后一個按下鍵會到第一個 ++nowi; else nowi = 1; }break; case 13: //Enter鍵確定 { coolfun::light_gotoxy(nowx, nowy + nowi); cout << "-->"; coolfun::light_gotoxy(nowx, nowy + case_num + 1); return nowi; //返回當前選項編號 }break; } coolfun::light_gotoxy(nowx, nowy + nowi);//移動到修改后的位置 cout << ">>>"; coolfun::light_gotoxy(nowx, nowy + case_num + 1); //把光標移動回輸出的最后 } return 0; } } int main() { cout << "歪比巴布占用了這一行" << endl; cout << "瑪卡巴卡占用了這一行" << endl; cout << "反沖斗士芭芭拉也需要一行" << endl; string str[] = { "1.自動模式", "2.手動模式", }; cout << "<< 您希望以什么模式開始游戲?" << endl; cout << "\n<< 您選擇了選項" << coolfun::switch_case(2, str) << endl; return 0; }
運行結果:
4.coolfun
coolfun:http://blog.coolight.cool/?p=313
利用獲取光標位置和移動光標的函數還能有其他一些不錯的功能,
例如一些顏文字的打印動畫,實現進度條等等,我們以后再聊聊。
coolight大字打印動畫:
進度條: