#include <graphics.h> #include <conio.h> #include <stdio.h> #define BUTTON_TOP 100 void main() { initgraph(800,600); float H=220; float S=1; float L=0.7f; for (int y=0;y<600;y++) { L+=0.0005f; setlinecolor(HSLtoRGB(H,S,L)); line(0,y,799,y); } H=0; S=1; L=0.6f; setlinestyle(PS_SOLID,10); for (int r=400;r>344;r--) { H+=5; setlinecolor(HSLtoRGB(H,S,L)); circle(700,600,r); } settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLUE); outtextxy(10, 550, "Esc: exit");//指定位置输出字符串 settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLUE); outtextxy(10, 50, "班级:电子信息工程一班");//指定位置输出字符串settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLUE); outtextxy(10, 80, "姓名:林佳豪");//指定位置输出字符串 settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLUE); outtextxy(10, 110, "学号:2201020116");//指定位置输出字符串 RECT rStr1={300, BUTTON_TOP, 500,BUTTON_TOP+50}; char str1[]="HDMI 1"; char inputChar; setfillcolor(YELLOW);//设置当前的填充颜色 solidroundrect(300, BUTTON_TOP, 500,BUTTON_TOP+50,20,20);//画填充圆角矩形,前2个参数左顶点坐标,中间两个参数右下点的坐标,后2个参数为椭圆的宽高 settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLACK);//设置当前背景色 settextstyle(24, 0, "宋体");//设置字体大小 参数24为高度,参数0为宽度自适应 drawtext(str1, &rStr1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在指定区域内以指定格式输出字符串,水平、垂直居中(单行有效) RECT rStr2={300, BUTTON_TOP+200, 500,BUTTON_TOP+50}; char str2[]="HDMI 2"; char inputChar2; setfillcolor(YELLOW);//设置当前的填充颜色 solidroundrect(300, BUTTON_TOP+100, 500,BUTTON_TOP+150,20,20);//画填充圆角矩形,前2个参数左顶点坐标,中间两个参数右下点的坐标,后2个参数为椭圆的宽高 settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLACK);//设置当前背景色 settextstyle(24, 0, "宋体");//设置字体大小 参数24为高度,参数0为宽度自适应 drawtext(str2, &rStr2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在指定区域内以指定格式输出字符串,水平、垂直居中(单行有效) RECT rStr3={300, BUTTON_TOP+400, 500,BUTTON_TOP+50}; char str3[]="HDMI 3"; char inputChar3; setfillcolor(YELLOW);//设置当前的填充颜色 solidroundrect(300, BUTTON_TOP+200, 500,BUTTON_TOP+250,20,20);//画填充圆角矩形,前2个参数左顶点坐标,中间两个参数右下点的坐标,后2个参数为椭圆的宽高 settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLACK);//设置当前背景色 settextstyle(24, 0, "宋体");//设置字体大小 参数24为高度,参数0为宽度自适应 drawtext(str3, &rStr3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在指定区域内以指定格式输出字符串,水平、垂直居中(单行有效) RECT rStr4={300, BUTTON_TOP+600, 500,BUTTON_TOP+50}; char str4[]="HDMI 4"; char inputChar4; setfillcolor(YELLOW);//设置当前的填充颜色 solidroundrect(300, BUTTON_TOP+300, 500,BUTTON_TOP+350,20,20);//画填充圆角矩形,前2个参数左顶点坐标,中间两个参数右下点的坐标,后2个参数为椭圆的宽高 settextcolor(WHITE);//设置当前文字颜色 setbkcolor(BLACK);//设置当前背景色 settextstyle(24, 0, "宋体");//设置字体大小 参数24为高度,参数0为宽度自适应 drawtext(str4, &rStr4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在指定区域内以指定格式输出字符串,水平、垂直居中(单行有效) while((inputChar=getch())!=27)//当输入不是Esc键时,一直执行while循环 { switch(inputChar) { case 72: printf("input up\n"); break; case 80: printf("input down\n"); break; case 75: printf("input left\n"); break; case 77: printf("input right\n"); break; case 13: printf("input Enter\n"); break; } } closegraph(); // 关闭图形界面 }怎么让上下键控制选项HDMI 1到HDMI 4 和esc退出程序
时间: 2025-03-17 18:08:46 浏览: 35
<think>好的,我现在需要帮助用户解决如何用上下键控制HDMI选项,并让Esc退出程序的问题。用户提供的代码是用C语言结合graphics.h库写的,看起来像是一个图形界面程序,可能使用的是EasyX或者类似的库。
首先,我需要理解现有代码的结构。主函数里初始化了图形窗口,画了背景,四个HDMI按钮,以及一些文字。然后进入一个循环,等待键盘输入,直到按下Esc键退出。当前的循环处理了方向键和回车键,但只是打印信息,没有实际控制选项。
用户的需求是让上下键在这四个HDMI选项之间移动,并用Esc退出。那么,我需要实现一个选项高亮或焦点切换的功能,当用户按上下键时,当前选中的按钮会有视觉反馈,比如颜色变化,同时可能需要处理回车键的确认操作。不过用户的问题主要是上下键控制选项,所以重点在移动焦点。
首先,考虑如何表示当前选中的选项。可以定义一个变量,比如int currentSelection = 0;,0代表HDMI 1,1代表HDMI 2,依此类推。当用户按下上或下键时,改变这个变量的值,并确保其在0到3之间循环。
接下来,需要在每次按键后重新绘制按钮,以反映当前选中的状态。例如,被选中的按钮颜色不同,或者边框高亮。当前的按钮都是黄色填充,可能可以改为当选中时改变填充色或边框颜色。
但是原代码中按钮是直接绘制在屏幕上的,没有动态更新的部分。因此,需要在每次按键后,清除原有按钮,重新绘制所有按钮,并根据currentSelection来决定哪个按钮高亮。或者,可以只更新当前选中的按钮和之前选中的按钮,但为了简单,可能直接重新绘制所有按钮更简单,但需要考虑效率问题。不过对于这个简单的程序来说,可能没问题。
原代码中的按钮绘制部分重复了四次,分别对应四个HDMI选项。可能需要将绘制按钮的代码封装成一个函数,根据currentSelection参数来设置不同的颜色。例如,每次循环时,先清除按钮区域,然后重新绘制四个按钮,其中当前选中的那个用不同的颜色(比如绿色)填充,其他用黄色。
或者,在现有代码中,绘制按钮的部分是在主函数初始化时完成的,之后并没有更新。因此,当用户按下上下键时,需要重新绘制按钮的状态。这可能需要将按钮的绘制移到循环内部,或者在每次按键后重新绘制相关部分。
另一个问题是如何处理键盘输入。当前循环使用getch()获取输入,方向键的键值可能已经被正确识别(例如72是上,80是下)。当按下上键时,currentSelection减1,按下下键时加1,然后限制在0-3之间。例如,currentSelection = (currentSelection + 4) % 4; 这样无论加减都能循环。
然后,在绘制按钮时,根据currentSelection的值来决定是否高亮。例如,HDMI 1对应currentSelection 0,当currentSelection等于0时,用绿色填充,其他用黄色。这样每次按键后,需要重新绘制这四个按钮,并更新显示。
不过原代码中按钮的位置可能有问题。例如,第一个按钮的RECT rStr1是{300, 100, 500, 150},而第二个按钮的RECT rStr2是{300, 300, 500, 150},这里可能有问题,因为第二个按钮的top是BUTTON_TOP+200(即300),而bottom是BUTTON_TOP+50(即150),这显然是不正确的。原代码中的RECT rStr2的top和bottom参数可能有错误,导致按钮的位置不正确。这可能是一个bug,导致第二个按钮的位置不对,甚至可能看不到。
例如,原代码中的:
RECT rStr2={300, BUTTON_TOP+200, 500,BUTTON_TOP+50};
这里的BUTTON_TOP是100,所以rStr2的top是300,bottom是100+50=150?这显然是不对的,因为top应该小于bottom。正确的应该是,第二个按钮的位置应该是BUTTON_TOP + 间隔,比如每个按钮间隔60像素。例如,第一个按钮的top是100,bottom是150;第二个按钮的top是160,bottom是210,依此类推。但原代码中,第二个按钮的RECT设置可能有错误,导致按钮的位置不正确。这可能是用户代码中的一个问题,需要先修正,否则按钮无法正确显示,进而影响上下键的选择。
因此,用户的问题可能不仅仅是控制逻辑的问题,还有按钮绘制的错误。需要先修正按钮的位置参数,才能让上下键正确切换。
例如,原代码中:
第一个按钮的RECT rStr1是{300, 100, 500, 150},这是正确的,因为top=100,bottom=100+50=150,左右是300到500,宽度200,高度50。
第二个按钮的RECT rStr2={300, BUTTON_TOP+200, 500,BUTTON_TOP+50},即top=300,bottom=150,这显然是不对的,因为top必须小于bottom。正确的应该是,第二个按钮的top是100+间隔,比如100+60=160,bottom是160+50=210。所以原代码中的RECT定义是错误的,导致按钮的位置不正确,可能无法显示或显示在错误的位置。
同样,第三个和第四个按钮的RECT也存在同样的问题。例如:
RECT rStr3={300, BUTTON_TOP+400, 500,BUTTON_TOP+50},即top=500,bottom=150,这明显错误。
因此,用户需要先修正按钮的RECT定义,确保每个按钮的top和bottom是递增的。例如,每个按钮的top比前一个按钮的top大60像素,这样四个按钮的位置才不会重叠或出现负高度。
修正后的RECT应该类似于:
RECT rStr1 = {300, BUTTON_TOP, 500, BUTTON_TOP + 50}; // HDMI 1: top=100, bottom=150
RECT rStr2 = {300, BUTTON_TOP + 60, 500, BUTTON_TOP + 60 + 50}; // HDMI 2: top=160, bottom=210
RECT rStr3 = {300, BUTTON_TOP + 120, 500, BUTTON_TOP + 120 +50}; // HDMI3: top=220, bottom=270
RECT rStr4 = {300, BUTTON_TOP + 180, 500, BUTTON_TOP + 180 +50}; // HDMI4: top=280, bottom=330
同时,对应的solidroundrect函数调用中的坐标也需要修正。原代码中:
第一个按钮:solidroundrect(300, 100, 500, 150, 20, 20);
第二个按钮的代码是:
solidroundrect(300, BUTTON_TOP+100, 500,BUTTON_TOP+150,20,20);
BUTTON_TOP是100,所以第二个按钮的top是100+100=200,bottom是100+150=250。这可能与RECT rStr2的top=300不匹配,导致文本显示在错误的位置。因此,按钮的绘制位置和RECT的位置必须一致,否则文本不会出现在按钮上。
这说明用户代码中存在多处坐标错误,导致按钮的位置和文本显示不正确。因此,在实现上下键控制之前,必须先修正这些坐标错误,确保四个按钮正确显示在屏幕上,并且各自的RECT区域与按钮的绘制位置一致。
接下来,处理上下键控制选项。首先,定义currentSelection变量,初始为0。当按下上键时,currentSelection减1,按下下键时加1,并使用模运算保证在0-3之间循环。例如:
case 72: // 上键
currentSelection = (currentSelection - 1 + 4) % 4;
break;
case 80: // 下键
currentSelection = (currentSelection + 1) % 4;
break;
然后,每次按键后,需要重新绘制所有按钮,根据currentSelection的值来决定颜色。例如,被选中的按钮用绿色填充,其他用黄色。这需要修改绘制按钮的代码,将颜色设置为条件判断。
原代码中的四个按钮是分别绘制的,可以将其改为循环或者函数,根据currentSelection的值来设置颜色。例如,对于每个按钮i(0到3),如果i等于currentSelection,则用绿色,否则用黄色。
但原代码中的按钮绘制是分散的,可能需要重构代码,将绘制按钮的部分放在一个循环中,或者封装成函数。例如:
for (int i = 0; i < 4; i++) {
int top = BUTTON_TOP + i * 60; // 每个按钮间隔60像素
int bottom = top + 50;
COLOR_TYPE fillColor = (i == currentSelection) ? GREEN : YELLOW;
setfillcolor(fillColor);
solidroundrect(300, top, 500, bottom, 20, 20);
// 绘制文本
RECT rStr = {300, top, 500, bottom};
char str[10];
sprintf(str, "HDMI %d", i+1);
drawtext(str, &rStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
这样,每次按键后,重新绘制所有按钮,并根据currentSelection改变颜色。但原代码中的文字输出使用了outtextxy和drawtext,可能需要调整。
不过原代码中的文字输出可能存在问题,因为drawtext需要正确的RECT区域。例如,原代码中的RECT rStr2的定义错误,导致文本无法正确显示在按钮上。因此,必须确保每个按钮的RECT区域与其绘制的solidroundrect的位置一致。
综上,修改步骤可能包括:
1. 修正四个按钮的位置和RECT区域,确保它们正确排列,不重叠,且RECT的top < bottom。
2. 将按钮的绘制改为循环或函数,根据currentSelection的值设置颜色。
3. 在按键处理中更新currentSelection,并重新绘制按钮。
4. 处理屏幕刷新,可能需要使用cleardevice()或局部刷新,但考虑到背景的渐变效果,可能需要重新绘制背景,但这样效率较低。或者,可以只清除按钮区域,但较为复杂。
或者,可以分层绘制:先绘制背景,然后绘制按钮。每次按键后,重新绘制所有按钮,覆盖之前的按钮。这样虽然效率较低,但对于简单程序足够。
但原代码的背景是一个渐变,每次重新绘制整个背景可能会影响性能,但可能可以接受。或者,在初始化时绘制背景,之后只更新按钮区域。这需要保存背景的一部分,或者在按钮区域绘制时恢复背景,这可能比较复杂。
另一种方法是,在每次更新按钮时,先使用原背景色覆盖按钮区域,再绘制新的按钮。但原背景是渐变的,无法简单恢复。因此,可能需要接受每次重新绘制整个背景,但这样会导致屏幕闪烁。
或者,可以将背景保存为图像,在需要重绘时快速贴图。但这需要用到EasyX的图像处理函数,例如IMAGE。例如,在初始化后,将整个屏幕保存为IMAGE对象,然后在需要重绘按钮时,将这部分区域从IMAGE中复制回来,再绘制新的按钮。这样可以避免重绘整个背景。
但考虑到用户提供的代码中没有使用这些功能,可能为了简单,选择每次重新绘制整个背景和按钮。不过原代码中的背景是通过循环逐行绘制的,这可能在每次重绘时导致明显的延迟。
因此,可能需要优化,将背景保存为图像。具体步骤:
- 在初始化绘制完背景后,使用getimage()保存整个屏幕到IMAGE对象。
- 每次需要重绘按钮时,使用putimage()将保存的背景图像贴回屏幕,然后绘制所有按钮。这样可以避免重新计算渐变,提高效率。
但用户提供的代码中没有这部分,需要添加。例如:
// 在初始化背景绘制完成后
IMAGE bg;
getimage(&bg, 0, 0, 800, 600);
然后在循环中,每次按键后:
putimage(0, 0, &bg); // 恢复背景
// 重新绘制所有按钮
for (int i = 0; i < 4; i++) {
// 绘制按钮i,根据currentSelection设置颜色
}
这样,按钮的更新就不会影响背景,且效率较高。
综上所述,修改步骤大致如下:
1. 修正按钮的位置和RECT定义,确保四个按钮正确排列。
2. 将按钮绘制部分重构为循环,根据currentSelection决定颜色。
3. 使用IMAGE保存背景,以便快速恢复。
4. 在按键处理中更新currentSelection,并触发按钮的重绘。
现在,逐步分析用户提供的代码中的问题:
原代码中的按钮定义:
第一个按钮:
RECT rStr1={300, BUTTON_TOP, 500,BUTTON_TOP+50}; // BUTTON_TOP=100 → top=100, bottom=150 → 正确。
solidroundrect(300, BUTTON_TOP, 500,BUTTON_TOP+50,20,20); → 正确。
第二个按钮:
RECT rStr2={300, BUTTON_TOP+200, 500,BUTTON_TOP+50}; → top=300,bottom=150 → 错误,因为top必须小于bottom。正确的应该是BUTTON_TOP + 间隔,例如BUTTON_TOP + 60,bottom是BUTTON_TOP +60 +50=210。
对应的solidroundrect调用是:
solidroundrect(300, BUTTON_TOP+100, 500,BUTTON_TOP+150,20,20); → top=200, bottom=250。所以RECT rStr2的top是300,而按钮的top是200,不匹配,导致文本显示在错误的位置。
因此,RECT的定义必须与solidroundrect的坐标一致。例如,第二个按钮的solidroundrect的top是BUTTON_TOP+100=200,bottom=250,对应的RECT应该是{300, 200, 500, 250}。但原代码中的RECT rStr2是{300, 300, 500, 150},这显然错误。
因此,需要将RECT的top和bottom与solidroundrect的坐标对应。例如,第二个按钮的RECT应该是:
RECT rStr2={300, 200, 500, 250};
同样,第三个按钮的solidroundrect调用是:
solidroundrect(300, BUTTON_TOP+200, 500,BUTTON_TOP+250,20,20); → top=300, bottom=350.
对应的RECT rStr3应该是{300, 300, 500, 350}。
而原代码中的RECT rStr3={300, BUTTON_TOP+400, 500,BUTTON_TOP+50}; → top=500, bottom=150 → 错误。
同理,第四个按钮的solidroundrect是:
solidroundrect(300, BUTTON_TOP+300, 500,BUTTON_TOP+350,20,20); → top=400, bottom=450.
对应的RECT rStr4应为{300, 400, 500, 450},但原代码中的RECT是{300, BUTTON_TOP+600, 500, BUTTON_TOP+50} → top=700,bottom=150 → 错误。
因此,用户代码中的RECT定义与solidroundrect的坐标不匹配,导致文本显示的位置不正确。需要将每个按钮的RECT的top和bottom设置为与solidroundrect的top和bottom一致。
修正后的RECT定义应为:
RECT rStr1={300, 100, 500, 150}; // HDMI1
RECT rStr2={300, 200, 500, 250}; // HDMI2
RECT rStr3={300, 300, 500, 350}; // HDMI3
RECT rStr4={300, 400, 500, 450}; // HDMI4
同时,原代码中的solidroundrect调用中的参数是正确的,如第一个按钮是BUTTON_TOP(100),第二个是BUTTON_TOP+100(200),第三个是BUTTON_TOP+200(300),第四个是BUTTON_TOP+300(400)。所以四个按钮的垂直位置是100、200、300、400,每个高度50,间隔50像素。这样,四个按钮的位置应该是正确的,但RECT的top和bottom必须与solidroundrect的坐标一致。
因此,用户需要修正RECT的定义,以匹配solidroundrect的坐标。例如:
对于第二个按钮:
原代码中的RECT rStr2的定义错误,应改为:
RECT rStr2={300, 200, 500, 250};
同样,第三个和第四个按钮的RECT也要相应调整。
接下来,处理上下键控制选项。需要定义一个变量currentSelection,初始为0,代表选中的第一个按钮。每次按下上或下键时,改变currentSelection的值,并确保在0到3之间循环。
然后,每次按键后,重新绘制所有按钮,根据currentSelection的值设置颜色。为了高效,应该在按键后恢复背景,然后重新绘制按钮。但原代码中的背景是渐变的,直接重新绘制整个背景可能效率低下,因此需要使用IMAGE保存背景。
修改后的步骤:
1. 在绘制完初始背景后,保存整个屏幕为IMAGE对象。
2. 在按键处理循环中,当方向键被按下时,更新currentSelection,然后使用putimage恢复背景,重新绘制所有按钮,并根据currentSelection设置颜色。
3. 绘制按钮时,使用循环处理四个按钮,根据currentSelection判断是否高亮。
例如:
// 在initgraph之后,绘制完背景后:
IMAGE bg;
getimage(&bg, 0, 0, 800, 600);
// 定义currentSelection变量
int currentSelection = 0;
// 在按键循环中:
while((inputChar=getch())!=27) {
switch(inputChar) {
case 72: // 上
currentSelection = (currentSelection - 1 + 4) % 4;
break;
case 80: // 下
currentSelection = (currentSelection + 1) % 4;
break;
// 其他case...
}
// 恢复背景
putimage(0, 0, &bg);
// 重新绘制所有按钮
for (int i = 0; i < 4; i++) {
int top = BUTTON_TOP + i * 100; // 因为原代码中的按钮间隔是100像素(100,200,300,400)
int bottom = top + 50;
// 设置按钮颜色
setfillcolor(i == currentSelection ? GREEN : YELLOW);
solidroundrect(300, top, 500, bottom, 20, 20);
// 绘制文本
RECT rStr = {300, top, 500, bottom};
char str[10];
sprintf(str, "HDMI %d", i+1);
setbkcolor(BLACK); // 可能需要调整背景色
settextcolor(WHITE);
drawtext(str, &rStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
// 其他需要绘制的元素,比如底部的文字,可能需要重新绘制,或者包含在bg图像中
}
但原代码中的其他元素,比如底部的“Esc: exit”和顶部的班级、姓名、学号信息,可能已经被保存在bg图像中,所以不需要重新绘制。但按钮的绘制会覆盖这些区域吗?需要看按钮的位置。例如,按钮从y=100开始,而顶部的文字在y=50、80、110,不会被按钮覆盖,所以putimage恢复背景后,这些文字会被保留,因为bg图像包含它们。但原代码中,这些文字是在初始化时绘制的,之后保存到bg图像中,所以在恢复背景时,这些文字会被保留,无需重新绘制。
因此,修改后的代码逻辑大致如下:
- 初始化图形窗口。
- 绘制背景渐变。
- 绘制顶部和底部的静态文本。
- 保存整个屏幕到bg图像。
- 进入循环,等待按键。
- 当方向键按下时,更新currentSelection。
- 恢复bg图像(即清除所有动态内容,如按钮)。
- 重新绘制所有按钮,根据currentSelection设置颜色。
- 循环继续,直到按下Esc。
这样,每次按键后,按钮会被重新绘制,而静态文本由于在bg图像中,不会被影响。
现在,需要将原代码中分散的按钮绘制代码改为循环,并根据currentSelection设置颜色。例如,原来的四个按钮绘制代码:
// 原代码中的按钮1:
setfillcolor(YELLOW);
solidroundrect(300, 100, 500, 150, 20, 20);
// 绘制文本...
改为循环:
for (int i = 0; i < 4; i++) {
int top = 100 + i * 100; // 100, 200, 300, 400
setfillcolor(i == currentSelection ? GREEN : YELLOW);
solidroundrect(300, top, 500, top + 50, 20, 20);
RECT rStr = {300, top, 500, top + 50};
char str[10];
sprintf(str, "HDMI %d", i+1);
drawtext(str, &rStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
同时,原代码中的RECT定义错误需要修正,但在此循环中,RECT是根据top动态生成的,不需要单独定义四个RECT变量。
因此,原代码中的四个RECT定义和对应的drawtext调用可以删除,改为在循环中处理。
此外,原代码中在绘制按钮后还设置了一些文本属性,如settextcolor、setbkcolor、settextstyle,这些需要在循环中设置,或者在循环前统一设置。
例如,在循环绘制按钮之前:
settextstyle(24, 0, "宋体");
settextcolor(WHITE);
setbkcolor(BLACK); // 文本背景色
这样,每次绘制按钮文本时都使用相同的样式。
综上,修改后的代码大致如下:
// 在main函数中:
initgraph(800,600);
// ... 绘制背景渐变和静态文本 ...
// 保存背景到IMAGE
IMAGE bg;
getimage(&bg, 0, 0, 800, 600);
int currentSelection = 0;
while((inputChar=getch())!=27) {
switch(inputChar) {
case 72: // 上
currentSelection = (currentSelection - 1 + 4) % 4;
break;
case 80: // 下
currentSelection = (currentSelection + 1) % 4;
break;
// 其他按键处理...
}
// 恢复背景
putimage(0, 0, &bg);
// 重新绘制所有按钮
settextstyle(24, 0, "宋体");
settextcolor(WHITE);
setbkcolor(BLACK);
for (int i = 0; i < 4; i++) {
int top = BUTTON_TOP + i * 100; // BUTTON_TOP=100,每个按钮间隔100像素
setfillcolor(i == currentSelection ? GREEN : YELLOW);
solidroundrect(300, top, 500, top + 50, 20, 20);
RECT rStr = {300, top, 500, top + 50};
char str[10];
sprintf(str, "HDMI %d", i + 1);
drawtext(str, &rStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
// 可能需要重新绘制其他动态内容,如果有的话
}
closegraph();
但需要注意,原代码中的BUTTON_TOP定义为100,所以第一个按钮的top是100,第二个是200,第三个300,第四个400,间隔100像素。这样四个按钮的位置是100,200,300,400,每个高度50,间隔50像素(因为下一个按钮的top是前一个的top+100,而高度是50,所以间隔是50像素)。这可能比较稀疏,用户可能需要调整间隔,比如间隔60像素,使按钮更紧凑。但根据原代码,间隔是100像素,所以暂时保持原样。
此外,原代码中的RECT定义和solidroundrect的坐标需要对应,但在此循环中已经统一处理,确保RECT的top和按钮的top一致。
现在,测试这个逻辑:
当用户按下上键,currentSelection减1,例如从0→3,1→0,等等;下键则加1。按钮颜色根据currentSelection变化。
这样,用户就可以用上下键在四个选项之间切换,Esc退出。
总结修改步骤:
1. 修正按钮的RECT定义,确保与solidroundrect的坐标一致。
2. 使用IMAGE保存初始背景,包括静态文本。
3. 在循环中,根据按键更新currentSelection,恢复背景,重新绘制按钮。
4. 使用循环绘制四个按钮,根据currentSelection设置颜色。
可能还需要处理其他细节,例如按钮的边框颜色或文本颜色,但主要逻辑如此。</think>以下是修改后的代码,实现了上下键控制HDMI选项高亮切换及Esc退出功能:
```c
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define BUTTON_TOP 100
void main()
{
initgraph(800,600);
// 绘制渐变背景
float H=220, S=1, L=0.7f;
for (int y=0; y<600; y++)
{
L += 0.0005f;
setlinecolor(HSLtoRGB(H,S,L));
line(0,y,799,y);
}
// 绘制彩虹圆圈
H=0; S=1; L=0.6f;
setlinestyle(PS_SOLID,10);
for(int r=400; r>344; r--)
{
H += 5;
setlinecolor(HSLtoRGB(H,S,L));
circle(700,600,r);
}
// 绘制固定文本
settextcolor(WHITE);
setbkcolor(BLUE);
outtextxy(10, 550, "Esc: exit");
outtextxy(10, 50, "班级:电子信息工程一班");
outtextxy(10, 80, "姓名:林佳豪");
outtextxy(10, 110, "学号:2201020116");
// 保存背景图像
IMAGE bg;
getimage(&bg, 0, 0, 800, 600);
int currentSelection = 0; // 当前选中项索引
char inputChar;
while((inputChar = getch()) != 27)
{
// 处理方向键
switch(inputChar)
{
case 72: // 上键
currentSelection = (currentSelection - 1 + 4) % 4;
break;
case 80: // 下键
currentSelection = (currentSelection + 1) % 4;
break;
}
// 还原背景
putimage(0, 0, &bg);
// 重绘所有按钮
settextstyle(24, 0, "宋体");
settextcolor(WHITE);
setbkcolor(BLACK);
for(int i=0; i<4; i++)
{
int top = BUTTON_TOP + i*100; // 按钮垂直位置
// 设置按钮颜色
setfillcolor(i == currentSelection ? GREEN : YELLOW);
solidroundrect(300, top, 500, top+50, 20, 20);
// 绘制按钮文字
RECT rStr = {300, top, 500, top+50};
char str[10];
sprintf(str, "HDMI %d", i+1);
drawtext(str, &rStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
}
closegraph();
}
```
主要修改说明:
1. **按钮定位优化**
使用循环结构统一管理4个按钮,每个按钮间隔100像素,坐标计算方式:
$$top = BUTTON\_TOP + i \times 100$$
2. **状态跟踪**
新增`currentSelection`变量跟踪当前选中项(0-3对应HDMI1-4)
3. **背景缓存**
使用`getimage()`保存包含静态元素的背景,按键后通过`putimage()`快速还原
4. **交互逻辑**
- 上键(72):`currentSelection`减1(支持循环)
- 下键(80):`currentSelection`加1(支持循环)
- 每次按键后重绘所有按钮,当前选中项显示为绿色
5. **视觉效果**
选中按钮通过颜色变化(黄→绿)提供视觉反馈,保持文字样式统一
效果:使用上下键时可以看到绿色高亮块在四个选项间循环移动,按Esc键正常退出程序。
阅读全文