使用c ++从另一个内部菜单返回主菜单
Returning to main menu from another inner menu using c++
我想制作一种销售点 (POS) 程序。因此,当您打开程序时,将打开一个菜单(主菜单),这是一个滚动菜单(您可以使用箭头键向上和向下移动到 select 菜单中的一个项目)和项目里面有 "Start business day"、"Stats"、"Inventory" blah blah。
现在,当您按 "Start Business day"(使用回车键)时,您会看到另一个菜单,其中会询问诸如 "Take order " ......"Return to the main menu" 之类的内容。这就是我发现问题的地方。当我按 "Return to the main menu" 时,我无法返回主菜单。
我的尝试
#include<iostream>
#include<conio.h>
#include<string>
#include<windows.h>
using namespace std;
int chk=0;
int sbd(void) //the order menu (start business day -> ' press ENTER')
{
int pointer=0;
string order[4]={"TAKE ORDER","CHECK MENU","MEMO","RETURN TO MAIN MENU"};
while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),14);
cout<<"\t\t ZAIKA KATHI ROLLS\n";
cout<<"\t\t\tORDER MENU\n\n";
for(int i=0;i<=3;i++)
{
if( i==pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11);
cout<<"-> "<<order[i]<<endl<<endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
cout<<" "<<order[i]<<endl<<endl;
}
}
while(true)
{
if(GetAsyncKeyState(VK_UP)!=0)
{
pointer-=1;
if(pointer==-1)
{
pointer=3;
}
break;
}
else if(GetAsyncKeyState(VK_DOWN)!=0)
{
pointer+=1;
if(pointer==4)
{
pointer=0;
}
break;
}
else if(GetAsyncKeyState(VK_RETURN)!=0)
{
switch(pointer)
{
case 3 : return 1;
}
}
}
Sleep(150);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
int pointer=0;
int flag=1;
string menu[6]={"START BUSINESS DAY","CONTINUE BUSINESS DAY","END BUSINESS DAY","INVENTORY MANAGEMENT","STATISTICS","SETTINGS"};
Mainmenu : while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),14);
int i=0;
cout<<"\t\t ZAIKA KATHI ROLLS\n";
cout<<"\t\t\tMAIN MENU\n\n";
for(i=0;i<=5;i++)
{
if(i==pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11);
cout<<"-> "<<menu[i]<<endl<<endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
cout<<" "<<menu[i]<<endl<<endl;
}
}
while(true)
{
if(GetAsyncKeyState(VK_UP)!=0)
{
pointer-=1;
if(pointer==-1)
{
pointer=5;
}
break;
}
else if(GetAsyncKeyState(VK_DOWN)!=0)
{
pointer+=1;
/* if(flag==0 && pointer==1)
pointer=3;
if(flag==1 && pointer==0)
pointer=1;*/
if(pointer==6)
{
pointer=0;
}
break;
}
else if(GetAsyncKeyState(VK_RETURN)!=0)
{
switch(pointer)
{
case 0 :chk=sbd();
if(chk==1)
goto Mainmenu;
}
}
}
Sleep(150);
}
return 0;
}
我想到的最好的想法是将 "start business day" 作为一个函数,在该函数中当我们按下 "Return to main menu" 时,该函数将 return 一个值主要功能将检测,然后通过使用 goto 功能程序控制将转移到主要功能 menu.Apparently 那是不工作的,所以任何人都可以帮助我解决这个问题吗?
实际情况是,当您在 "Return to main menu" 上按回车键时,实际上是返回到主菜单。如果您调试并单步执行它,您会看到这一点。问题是,一旦它走出 sub-menu 循环,它就会进入主菜单循环,检查 "enter" 是否被按下,通过条件并进入 sub-menu 循环再次.
问题是您没有在代码中正确使用 GetAsyncKeyState 函数:
if (GetAsyncKeyState(VK_RETURN) != 0)
它检查值是否为零。但是根据文档,这个函数 return 是一个 SHORT。
按键按下时最高位为1,未按下时为0。
如果自上次调用 GetAsyncKeyState 后按键被按下,则最低有效位为 1。我想这就是你想要的。因此,首先更改代码中的两个位置:
if (GetAsyncKeyState(VK_RETURN) != 0)
至:
if (GetAsyncKeyState(VK_RETURN) & 0x01 != 0)
我们只想检查最低有效位以查看自上次调用该函数以来是否按下了该键。如果你这样做它应该工作。
你也可以用Windows宏这样写:
if (LOBYTE(GetAsyncKeyState(VK_RETURN)) != 0)
我还应该提一下,您可能应该以同样的方式进行按键上键和下键操作。
不过我真的很喜欢,干得漂亮。
编辑:GetAsyncKeyState() returns 一个短整数。它很可能是两个字节。当函数 return 具有此值时,它会设置某些位或标志来告诉您信息。就像我说的,最高有效位(最高位)告诉你键是否按下,最低有效位告诉你自上次调用该函数以来是否按下了键。
所以二进制的 returned 数字看起来像这样 (MSB) 是最重要的,(LSB) 是最不重要的:
10000000 00000001
^ MSB ^ LSB
如果这是一个无符号整数,它的值将是 32769。您对当前是否按下该键不感兴趣,但更感兴趣的是自上次调用该函数以来该键是否被按下。你只对右边的位感兴趣。按位运算符 & AND 将比较两个位模式,当且仅当两个位都为 1 时,它会将结果位设置为 1。这与掩码一起使用,因此您可以提取某些值,可以这么说。
10000000 00000001 // Original value
00000000 00000001 // The mask
00000000 00000001 // Result
结果是1。然后你可以检查这个值是否是1,如果是,那么这个键在上次调用之后被按下了。这是一种非常低级的做事方式,但这有点像 Windows 的工作方式,并且 Windows 实际上通过提供执行相同操作的宏 LOBYTE() 来提供帮助。另一种方法是函数可以 returned class/struct 每个事物的布尔值。
第二次编辑(进一步解释):
如果自上次调用 GetAsyncKeyState 后按下键,则最低有效位仅为 1。因此,如果您按下 enter 键并保持按下 3 秒,则 LSB 将仅在第一次调用 GetAsyncKeyState 时设置。然而,MSB 将继续 return 并设置 MSB,因为这表明键是否按下。我认为以下快速程序应该很好地说明了这一点。
在我们的例子中,一个 short 有 2(字节)16 位,因此我们将使用正确的移位运算符 >> 来获取它。我要将 return 类型从 SHORT 转换为 USHORT。这是因为对于负数的有符号整数,位移是未定义的,因为右移可以传播最左边的位。例如:
// Right shifting 7 bits
UNSIGNED INT
1000 0000 >> 7 = 0000 0001
SIGNED INT
1000 0000 >> 7 = 1111 1111 // We may get this instead which is not what we want
开始一个新项目并粘贴这个和运行,尝试按回车键:
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
while (true)
{
int count = 0;
USHORT funcResult = 0;
while ((funcResult = GetAsyncKeyState(VK_RETURN)) != 0)
// If MSB or LSB is set then condition is true
{
count++;
cout << "Return pressed " << count << " times in one loop\n";
cout << "MSB = " << (funcResult >> 15) << '\n';
cout << "LSB = " << (funcResult & 1) << '\n';
}
// You will see that the MSB is always 1, because it tells us
// if the key is down.
// However the LSB is 1 only on the first run of the while loop
}
}
所以这就是为什么添加 Sleep() 也可以解决问题,因为如果您按下 enter 键 400 毫秒然后松开,让线程休眠 500 毫秒,下次它会检查该键'不下来,MSB不会被设置
我想制作一种销售点 (POS) 程序。因此,当您打开程序时,将打开一个菜单(主菜单),这是一个滚动菜单(您可以使用箭头键向上和向下移动到 select 菜单中的一个项目)和项目里面有 "Start business day"、"Stats"、"Inventory" blah blah。
现在,当您按 "Start Business day"(使用回车键)时,您会看到另一个菜单,其中会询问诸如 "Take order " ......"Return to the main menu" 之类的内容。这就是我发现问题的地方。当我按 "Return to the main menu" 时,我无法返回主菜单。
我的尝试
#include<iostream>
#include<conio.h>
#include<string>
#include<windows.h>
using namespace std;
int chk=0;
int sbd(void) //the order menu (start business day -> ' press ENTER')
{
int pointer=0;
string order[4]={"TAKE ORDER","CHECK MENU","MEMO","RETURN TO MAIN MENU"};
while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),14);
cout<<"\t\t ZAIKA KATHI ROLLS\n";
cout<<"\t\t\tORDER MENU\n\n";
for(int i=0;i<=3;i++)
{
if( i==pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11);
cout<<"-> "<<order[i]<<endl<<endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
cout<<" "<<order[i]<<endl<<endl;
}
}
while(true)
{
if(GetAsyncKeyState(VK_UP)!=0)
{
pointer-=1;
if(pointer==-1)
{
pointer=3;
}
break;
}
else if(GetAsyncKeyState(VK_DOWN)!=0)
{
pointer+=1;
if(pointer==4)
{
pointer=0;
}
break;
}
else if(GetAsyncKeyState(VK_RETURN)!=0)
{
switch(pointer)
{
case 3 : return 1;
}
}
}
Sleep(150);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
int pointer=0;
int flag=1;
string menu[6]={"START BUSINESS DAY","CONTINUE BUSINESS DAY","END BUSINESS DAY","INVENTORY MANAGEMENT","STATISTICS","SETTINGS"};
Mainmenu : while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),14);
int i=0;
cout<<"\t\t ZAIKA KATHI ROLLS\n";
cout<<"\t\t\tMAIN MENU\n\n";
for(i=0;i<=5;i++)
{
if(i==pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11);
cout<<"-> "<<menu[i]<<endl<<endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
cout<<" "<<menu[i]<<endl<<endl;
}
}
while(true)
{
if(GetAsyncKeyState(VK_UP)!=0)
{
pointer-=1;
if(pointer==-1)
{
pointer=5;
}
break;
}
else if(GetAsyncKeyState(VK_DOWN)!=0)
{
pointer+=1;
/* if(flag==0 && pointer==1)
pointer=3;
if(flag==1 && pointer==0)
pointer=1;*/
if(pointer==6)
{
pointer=0;
}
break;
}
else if(GetAsyncKeyState(VK_RETURN)!=0)
{
switch(pointer)
{
case 0 :chk=sbd();
if(chk==1)
goto Mainmenu;
}
}
}
Sleep(150);
}
return 0;
}
我想到的最好的想法是将 "start business day" 作为一个函数,在该函数中当我们按下 "Return to main menu" 时,该函数将 return 一个值主要功能将检测,然后通过使用 goto 功能程序控制将转移到主要功能 menu.Apparently 那是不工作的,所以任何人都可以帮助我解决这个问题吗?
实际情况是,当您在 "Return to main menu" 上按回车键时,实际上是返回到主菜单。如果您调试并单步执行它,您会看到这一点。问题是,一旦它走出 sub-menu 循环,它就会进入主菜单循环,检查 "enter" 是否被按下,通过条件并进入 sub-menu 循环再次.
问题是您没有在代码中正确使用 GetAsyncKeyState 函数:
if (GetAsyncKeyState(VK_RETURN) != 0)
它检查值是否为零。但是根据文档,这个函数 return 是一个 SHORT。
按键按下时最高位为1,未按下时为0。
如果自上次调用 GetAsyncKeyState 后按键被按下,则最低有效位为 1。我想这就是你想要的。因此,首先更改代码中的两个位置:
if (GetAsyncKeyState(VK_RETURN) != 0)
至:
if (GetAsyncKeyState(VK_RETURN) & 0x01 != 0)
我们只想检查最低有效位以查看自上次调用该函数以来是否按下了该键。如果你这样做它应该工作。
你也可以用Windows宏这样写:
if (LOBYTE(GetAsyncKeyState(VK_RETURN)) != 0)
我还应该提一下,您可能应该以同样的方式进行按键上键和下键操作。
不过我真的很喜欢,干得漂亮。
编辑:GetAsyncKeyState() returns 一个短整数。它很可能是两个字节。当函数 return 具有此值时,它会设置某些位或标志来告诉您信息。就像我说的,最高有效位(最高位)告诉你键是否按下,最低有效位告诉你自上次调用该函数以来是否按下了键。
所以二进制的 returned 数字看起来像这样 (MSB) 是最重要的,(LSB) 是最不重要的:
10000000 00000001
^ MSB ^ LSB
如果这是一个无符号整数,它的值将是 32769。您对当前是否按下该键不感兴趣,但更感兴趣的是自上次调用该函数以来该键是否被按下。你只对右边的位感兴趣。按位运算符 & AND 将比较两个位模式,当且仅当两个位都为 1 时,它会将结果位设置为 1。这与掩码一起使用,因此您可以提取某些值,可以这么说。
10000000 00000001 // Original value
00000000 00000001 // The mask
00000000 00000001 // Result
结果是1。然后你可以检查这个值是否是1,如果是,那么这个键在上次调用之后被按下了。这是一种非常低级的做事方式,但这有点像 Windows 的工作方式,并且 Windows 实际上通过提供执行相同操作的宏 LOBYTE() 来提供帮助。另一种方法是函数可以 returned class/struct 每个事物的布尔值。
第二次编辑(进一步解释):
如果自上次调用 GetAsyncKeyState 后按下键,则最低有效位仅为 1。因此,如果您按下 enter 键并保持按下 3 秒,则 LSB 将仅在第一次调用 GetAsyncKeyState 时设置。然而,MSB 将继续 return 并设置 MSB,因为这表明键是否按下。我认为以下快速程序应该很好地说明了这一点。
在我们的例子中,一个 short 有 2(字节)16 位,因此我们将使用正确的移位运算符 >> 来获取它。我要将 return 类型从 SHORT 转换为 USHORT。这是因为对于负数的有符号整数,位移是未定义的,因为右移可以传播最左边的位。例如:
// Right shifting 7 bits
UNSIGNED INT
1000 0000 >> 7 = 0000 0001
SIGNED INT
1000 0000 >> 7 = 1111 1111 // We may get this instead which is not what we want
开始一个新项目并粘贴这个和运行,尝试按回车键:
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
while (true)
{
int count = 0;
USHORT funcResult = 0;
while ((funcResult = GetAsyncKeyState(VK_RETURN)) != 0)
// If MSB or LSB is set then condition is true
{
count++;
cout << "Return pressed " << count << " times in one loop\n";
cout << "MSB = " << (funcResult >> 15) << '\n';
cout << "LSB = " << (funcResult & 1) << '\n';
}
// You will see that the MSB is always 1, because it tells us
// if the key is down.
// However the LSB is 1 only on the first run of the while loop
}
}
所以这就是为什么添加 Sleep() 也可以解决问题,因为如果您按下 enter 键 400 毫秒然后松开,让线程休眠 500 毫秒,下次它会检查该键'不下来,MSB不会被设置