经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
<c++控制台>用gotoxy()函数实现方向键进行选择
来源:cnblogs  作者:coolight7  时间:2021/5/31 9:12:53  对本文有异议

0.效果图

 

可以用方向键进行选择,看起来高级点而且可以防止乱输入。

 

1.引入:

这是我经常写的选择:

 

相信这应该也是很多人在控制台的时候会用的吧,

的确这个简单容易写。

 

但!是!

人要有理想,控制台也是

 

所以我开始想把它写成一般游戏那种上下选择的样子:

所以就有了这篇博文,

接下来让我们进入正题。

 

2.思路

我们首先把这部分cout出来

 

 

 

然后我们需要使用到控制台里的光标移动函数gotoxy()(头文件:<windows.h>)

图中最后的白块就是光标,光标在哪,输出的东西就会从那开始。(应该都是懂的吧...)

 

注意:gotoxy()并不是c++标准库里的,windows.h里其实也没有这玩意,

所以我们需要借助<windows.h>来自己“写一个”。

1 void gotoxy(int x, int y)//光标移动函数, 且在这里把x定义为纵坐标,y为横坐标
2 {
3     COORD pos = { y,x };
4     HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);    // 获取标准输出设备句柄
5     SetConsoleCursorPosition(hOut, pos);            //两个参数分别是指定哪个窗体,具体位置
6 }

因为之前写一个小游戏的时候习惯了x为纵坐标,

如果你喜欢x为横坐标的话可以把函数里的第一行代码的{y,x}改为{x,y}即可。

 

借助gotoxy()移动到选项前的空白

 

怎么移动呢??

直接看图里,选项“自动模式”是在第3行,我们编程老传统默认0为开始,所以这应该认为是第2行。

gotoxy( 2 , 0 );//把光标移动到第2(实际第3)行第0(实际第1)个。

 

然后在这里cout << ">>>" ;

 

就会有这样的效果:

 

怎么样,看起来是不是有感觉了!

 

然后我们只需要监控键盘的方向键,控制“>>>”的上下就可以了。

 

怎么样,听起来是不是简简单单!

 

但!是!

 

仅仅依靠这一个移动光标的函数是不够的,

因为在让选择的这部分字打印之前肯定是会有一些其他的提示,

抑或是之前已经有了一些输出了,例如:

 

我们是要把它搞成一个可以经常用的函数,不可能每次需要就自己数数在哪一行,

 

所以我们需要一个函数来获取在这之前光标的位置。

 1 int lightgetxy(int i)   //获取光标位置,0为获取x,1为获取y,失败返回-1
 2 {
 3     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 4     COORD coordScreen = { 0, 0 };    //光标位置
 5     CONSOLE_SCREEN_BUFFER_INFO csbi;
 6 
 7     if (GetConsoleScreenBufferInfo(hConsole, &csbi))
 8     {
 9         if (i)    // 0为获取y,1为获取x
10             return csbi.dwCursorPosition.X;
11         else    // 获取y
12             return csbi.dwCursorPosition.Y;
13     }
14     else
15         return -1;
16 }

所以现在就是利用lightgetxy()来获取选择之前光标的位置,把行数+1那就是下一行,然后开始cout我们我们的选项就可以了。

详细的让我们来看看具体的实现代码吧。

 

这就是我们这篇博文的主体函数:

 

 1 /*
 2 选项选择函数;返回选择的contentstr[]的位置,默认1开始
 3 max:contentstr的数组大小,contentstr[]:选项内容, tipstr:选择前提示
 4 */
 5 int switchcase(const int max, const string contentstr[], const string tipstr)
 6 {
 7     if (tipstr != "") //判断是否有提示字符串
 8         cout << tipstr << endl;
 9     cout << "<< 请用上下方向键选择..." << endl;
10     int nowi = 1, nowx = lightgetxy(0) - 1;
11     //nowi 记录选择的选项编号
12     cout << ">>> " << contentstr[0] << endl;
13     for (int i = 2; i <= max; ++i)  //先打印选项内容
14         cout << "    " << contentstr[i - 1] << endl;
15 
16     while (1)
17     {
18         while (_kbhit()) //判断是否有按键按下
19         {
20             gotoxy(nowx + nowi, 0); //移动到原来的编号选项前
21             cout << "   ";  //覆盖掉它的">>>"
22             switch (_getch()) //获取按下的按键的ask2值
23             {
24             case 13:  //Enter键确定
25             {
26                 gotoxy(nowx + max + 1, 0);
27                 return nowi;  //返回当前选项编号
28             }break;
29             case 72: //
30             {
31                 if (nowi > 1)   //在第一个再按上键会到最后一个
32                     --nowi;
33                 else
34                     nowi = max;
35 
36             }break;
37             case 80: //
38             {
39                 if (nowi < max)  //在最后一个按下键会到第一个
40                     nowi++;
41                 else
42                     nowi = 1;
43             }break;
44             }
45             gotoxy(nowx + nowi, 0); //移动到目标位置
46             cout << ">>>";
47             gotoxy(nowx + max + 1, 0); //记得把光标移动回输出的最后
48         }
49         Sleep(50);
50     }
51 }

 

最后让我们来找给简单的例子测试一下。

 

3.测试代码 

 


   1 #define _CRT_SECURE_NO_WARNINGS

   2 #include<string>

 3 #include<iostream>
 4 #include<windows.h>
 5 #include<conio.h>
 6 using namespace std;
 7 
 8 //光标移动函数, 且在这里把x定义为纵坐标,y为横坐标
 9 void gotoxy(int x, int y)
10 {
11     COORD pos = { y,x };
12     HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);    // 获取标准输出设备句柄
13     SetConsoleCursorPosition(hOut, pos);            //两个参数分别是指定哪个窗体,具体位置
14 }
15 
16 //获取光标位置。i为0获取x,非零获取y,执行失败返回-1
17 int lightgetxy(int i)
18 {
19     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
20     COORD coordScreen = { 0, 0 }; //光标位置
21     CONSOLE_SCREEN_BUFFER_INFO csbi;
22 
23     if (GetConsoleScreenBufferInfo(hConsole, &csbi))
24     {
25         if (i) // 0获取y,非零获取x
26             return csbi.dwCursorPosition.X;
27         else // y
28             return csbi.dwCursorPosition.Y;
29     }
30     else
31         return -1;
32 }
33 
34 //选择函数,返回以contentstr的位置+1
//max是选项数量,contentstr[]是选项的内容,注意这是个数组,tipstr是在选项前的提示内容 35 int switchcase(const int max, const string contentstr[], const string tipstr) 36 { 37 if (tipstr != "") //判断是否有提示字符串 38 cout << tipstr << endl; 39 cout << "<< 请用上下方向键选择..." << endl; 40 int nowi = 1, nowx = lightgetxy(0) - 1; 41 //nowi 记录选择的选项编号 42 cout << ">>> " << contentstr[0] << endl; 43 for (int i = 2; i <= max; ++i) //先打印选项内容 44 cout << " " << contentstr[i - 1] << endl; 45 46 while (1) 47 { 48 while (_kbhit()) //判断是否有按键按下 49 { 50 gotoxy(nowx + nowi, 0); //移动到原来的编号选项前 51 cout << " "; //覆盖掉它的">>>" 52 switch (_getch()) //获取按下的按键的ask2值 53 { 54 case 13: //Enter键确定 55 { 56 gotoxy(nowx + max + 1, 0); 57 return nowi; //返回当前选项编号 58 }break; 59 case 72: // 60 { 61 if (nowi > 1) //在第一个再按上键会到最后一个 62 --nowi; 63 else 64 nowi = max; 65 66 }break; 67 case 80: // 68 { 69 if (nowi < max) //在最后一个按下键会到第一个 70 nowi++; 71 else 72 nowi = 1; 73 }break; 74 } 75 gotoxy(nowx + nowi, 0); //移动到目标位置 76 cout << ">>>"; 77 gotoxy(nowx + max + 1, 0); //记得把光标移动回输出的最后 78 } 79 Sleep(50); 80 } 81 } 82 83 int main() 84 { 85 cout << "歪比巴布占用了这一行" << endl; 86 cout << "玛卡巴卡占用了这一行" << endl; 87 cout << "反冲斗士芭芭拉也需要一行" << endl; 88 string str[] = 89 { 90 "自动模式", 91 "手动模式", 92 }; 93 cout << "\n<< 您选择了选项" << switchcase(2, str, "<< 您希望以什么模式开始游戏?") << endl; 94 return 0; 95 }

 

运行结果:

 

 

注意:在switchcase()函数的最后有gotoxy(nowx + max + 1, 0);

如果不加这个移动,那么在调用这个函数后,你的光标会停留在某一个选项前,

然后你再cout什么东西的话就会在那一行进行覆盖,导致看起来很乱。

 

 

4.其他

利用获取光标位置和移动光标的函数还能有其他一些不错的功能,

例如一些颜文字的打印动画,实现进度条等等,我们以后再聊聊。

 

coolight大字打印动画:

 

进度条:

原文链接:http://www.cnblogs.com/coolight7/p/14792049.html

 友情链接: NPS