C语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)

article/2025/9/16 20:58:13

目录

  • 0.引言
  • 1.素材准备
  • 2.编程
    • 2.1.创建你的界面
    • 2.2.创建按钮
    • 2.3.鼠标操作
      • 2.3.1.单击特效
      • 2.3.2.光标感应
      • 2.3.3.进度条
  • 3.完整代码及效果

0.引言

\qquad 看了CSDN上很多关于C程序图形化界面的介绍,有的代码繁琐难解,不方便调试修改;有的不够详细。本文提供的代码简单、易于移植、容易理解,望急需使用C语言制作图形化界面的朋友采纳。
\qquad 对easyx尚不熟悉的朋友不需要担心,我敢打包票它只需10分钟就可以上手,而它为你节省的时间可能是3个小时甚至更多。关于easyx的简单应用请参考一篇我以前写的关于C程序可视化的博文。
→【C语言实现动画控制】←
\qquad 本文的讲解是循序渐进的,读者应该重点关注每个步骤的理解,两步之间代码的变化,即可完全理解本文。

1.素材准备

  1. easyx的下载链接如下:(本文使用的版本是2014冬至版)
    https://www.easyx.cn/downloads/
    注:使用easyx需要注意它兼容的编译器(下载的帮助文件会写),不同的easyx兼容的编译器不同,但总是和visual C++6兼容(和字符编码有关),本文以visual C++6编译器为例书写代码。
  2. easyx的最新英文帮助文档链接(下载2014冬至版会自带中文帮助文档):
    https://docs.easyx.cn/en-us/intro
  3. 如果你成功下载了easyx2014冬至版,那么解压后把头文件(easyx.h和graphic.h)和lib文件(amd64)分别放在VC文件夹默认的include文件夹和lib文件夹中。右键你的VC程序,选择打开文件所在位置,然后找到MFC文件夹,友情提供两个文件夹的位置截图。
    include
    lib
  4. 建议编译的C文件以cpp后缀保存。

2.编程

2.1.创建你的界面

\qquad 创建一个480×360的窗口,我们需要使用initgraph()函数,闲言少叙,让我们直接看一段代码:

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>				//用到了定时函数sleep()
#include <math.h>int main()
{int i;short win_width,win_height;//定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width,win_height);//初始化窗口(黑屏)for(i=0;i<256;i+=5){setbkcolor(RGB(i,i,i));//设置背景色,原来默认黑色cleardevice();//清屏(取决于背景色)Sleep(15);//延时15ms}closegraph();//关闭绘图界面
}

\qquad 这段代码很容易理解,运行这段程序,就会出现逐渐明亮的屏幕。因为不断刷新背景色为 R G B ( i , i , i ) RGB(i,i,i) RGB(i,i,i)。C语言中的颜色使用十六进制表示的,RGB函数可以将0~255范围内的三个整数三原色转换成这个十六进制。
\qquad cleardevice()函数用于清屏,是界面内所有元素都被清空,一般只会在初始化出现。
\qquad Sleep()是毫秒级延迟,当然界面变亮时间不一定是准确的15ms×255/5=0.765s,因为其他语句还需要执行时间。
\qquad closegraph():关闭绘图界面。注意,如果初始化了绘图界面但没有在主函数结束前关闭它,可能会引发一些莫名其妙的错误!所以这个函数一定要有!

2.2.创建按钮

\qquad 我们尝试在界面创建几个按钮,按钮需要的操作是绘制矩形和打印文字。虽然看着简单,但是里面还是有点学问,为了方便大家理解,还是先放上代码和注释。

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>				//用到了定时函数sleep()
#include <math.h>
int r1[]={30,20,130,60};//输入按钮的矩形参数
int r2[]={170,20,220,60};//运行按钮的矩形参数
int r3[]={260,20,310,60};//退出按钮的矩形参数
int main()
{int i;short win_width,win_height;//定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width,win_height);//初始化窗口(黑屏)for(i=0;i<256;i+=5){setbkcolor(RGB(i,i,i));//设置背景色,原来默认黑色cleardevice();//清屏(取决于背景色)Sleep(15);//延时15ms}RECT R1={r1[0],r1[1],r1[2],r1[3]};//矩形指针R1RECT R2={r2[0],r2[1],r2[2],r2[3]};//矩形指针R2RECT R3={r3[0],r3[1],r3[2],r3[3]};//矩形指针R3LOGFONT f;//字体样式指针gettextstyle(&f);					//获取字体样式_tcscpy(f.lfFaceName,_T("宋体"));	//设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿  settextstyle(&f);                     // 设置字体样式settextcolor(BLACK);				//BLACK在graphic.h头文件里面被定义为黑色的颜色常量drawtext("输入参数",&R1,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R1内输入文字,水平居中,垂直居中,单行显示drawtext("运行",&R2,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R2内输入文字,水平居中,垂直居中,单行显示drawtext("退出",&R3,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R3内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r1[0],r1[1],r1[2],r1[3]);rectangle(r2[0],r2[1],r2[2],r2[3]);rectangle(r3[0],r3[1],r3[2],r3[3]);system("pause");//暂停,为了显示closegraph();return 0;
}

在这里插入图片描述
\qquad 这里需要特别介绍的是矩形指针 p R e c t pRect pRect,它使用句柄RECT定义,并且不可以中途再次赋值。之所以要设置矩形指针了为了打印字体的时候以矩形为边界自动填充。它的格式是RECT r={X1,Y1,X2,Y2},X1和X2是矩形的左边和右边的横坐标,Y1和Y2是矩形的上边和下边的纵坐标,这一点和rectangle()绘制空心矩形函数参数排列一致。后面的DT_CENTER | DT_VCENTER | DT_SINGLELINE就是描述填充格式的常量。使用drawtext书写文字不需要再计算文字的坐标和设置大小,会方便很多。
\qquad LOGFONT是字体样式指针,通过gettextstyle()函数来获取当前的字体类型,再通过settextstyle()函数加以设置。这里只修改了字体的名称和显示质量,还可以修改斜体、下划线等属性,更详细的部分请参考帮助文档。

2.3.鼠标操作

2.3.1.单击特效

\qquad 作为一个图形化界面的C程序,鼠标操作总不能少吧。在讲解程序前先别着急,简单为大家科普一下鼠标事件:
\qquad 鼠标是输入设备,只要发生以下的事件,就会暂存在鼠标消息列表中,我们的操作系统就会依次响应列表中的鼠标消息事件,常用的鼠标事件如下:

  • WM_MOUSEMOVE——鼠标移动
  • WM_MOUSEWHEEL——鼠标滚轮滚动
  • WM_LBUTTONDOWN——鼠标左键按下
  • WM_LBUTTONUP——鼠标左键弹起
  • WM_LBUTTONDBLCLK——鼠标左键双击
  • WM_RBUTTONDOWN——鼠标右键按下
  • WM_RBUTTONUP——鼠标右键弹起
  • WM_RBUTTONDBLCLK——鼠标左键双击
  • WM_MBUTTONDOWN——鼠标中键按下
  • WM_MBUTTONUP——鼠标中键弹起
  • WM_MBUTTONDBLCLK——鼠标中键双击
    \qquad 我们只需要根据不断获取鼠标消息队列的消息并根据消息依次进行响应即可。

\qquad 相信大家已经迫不及待了,那么请看下面一个简单的程序。

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>				//用到了定时函数sleep()
#include <math.h>
int r1[]={30,20,130,60};//输入按钮的矩形参数
int r2[]={170,20,220,60};//运行按钮的矩形参数
int r3[]={260,20,310,60};//退出按钮的矩形参数
int main()
{int i;short win_width,win_height;//定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width,win_height);//初始化窗口(黑屏)for(i=0;i<256;i+=5){setbkcolor(RGB(i,i,i));//设置背景色,原来默认黑色cleardevice();//清屏(取决于背景色)Sleep(15);//延时15ms}RECT R1={r1[0],r1[1],r1[2],r1[3]};//按钮1的矩形区域RECT R2={r2[0],r2[1],r2[2],r2[3]};//按钮2的矩形区域RECT R3={r3[0],r3[1],r3[2],r3[3]};//按钮2的矩形区域LOGFONT f;gettextstyle(&f);					//获取字体样式_tcscpy(f.lfFaceName,_T("宋体"));	//设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿  settextstyle(&f);                     // 设置字体样式settextcolor(BLACK);				//BLACK在graphic.h头文件里面被定义为黑色的颜色常量drawtext("输入参数",&R1,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R1内输入文字,水平居中,垂直居中,单行显示drawtext("运行",&R2,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R2内输入文字,水平居中,垂直居中,单行显示drawtext("退出",&R3,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R3内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r1[0],r1[1],r1[2],r1[3]);rectangle(r2[0],r2[1],r2[2],r2[3]);rectangle(r3[0],r3[1],r3[2],r3[3]);MOUSEMSG m;//鼠标指针setrop2(R2_NOTXORPEN);//二元光栅——NOT(屏幕颜色 XOR 当前颜色)while(true){m = GetMouseMsg();//获取一条鼠标消息if(m.uMsg==WM_LBUTTONDOWN){for(i=0;i<=10;i++){setlinecolor(RGB(25*i,25*i,25*i));//设置圆颜色circle(m.x,m.y,2*i);Sleep(25);//停顿2mscircle(m.x,m.y,2*i);//抹去刚刚画的圆}FlushMouseMsgBuff();//清空鼠标消息缓存区}}system("pause");//暂停,为了显示closegraph();return 0;
}

在这里插入图片描述
\qquad 每点击鼠标以下,应该可以看到鼠标点击处有一个逐渐扩大并淡出的圆(截图无法清晰,在画面的中右侧),当循环体内Sleep的视觉大于20ms后视觉效果很强。
\qquad 每响应一次鼠标左键单击事件,都会调用一次清空鼠标消息缓存区的函数FlushMouseMsgBuff(),如果没有这个函数会怎么样呢?如果我们快速连续地单击鼠标左键N次,那么特效就会播放N次,如果特效播放速度比单击的速度慢,那么即使你停下来了,程序仍然会接着播放单击特效,因为你的左键单击仍然在鼠标的消息队列m.uMsg中的鼠标消息没有响应完。
\qquad 这里需要解释的是一个二元光栅设置函数setrop2(),二元光栅是混合背景色和当前颜色的模式。我们这里采用的方式是同或(NOT XOR)的方式,若底色为白色(1),则当前颜色不变;若底色是黑色(0),则当前颜色反色。为什么需要采用这种方式呢?因为我们在第二次抹去原来的圆的时候不能采用白色,否则如果背景色原来就为黑(比如按钮和文字),就也会被抹成白色。而背景色与任意一个颜色同或两次都为其本身,即可起到还原背景色的效果。这里的背景色与cleardevice()前面那个背景色不同,这里的是指执行这一条绘画指令之前屏幕上的颜色。

2.3.2.光标感应

\qquad 我们希望鼠标移到按钮上时按钮会有所变化,移开按钮时又会回到原样。这里我们采用一种简单的填充颜色的方法,就是按钮变色。我们需要解决一个问题就是按钮变色了但是按钮的文字不能被覆盖,那么我们还是需要使用到二元光栅。只是我们这次的模式改成了同或。
\qquad 为了方便起见,存放三个按钮的数组我们合并为了一个二维数组,在鼠标事件中更容易使用和分配任务。

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>				//用到了定时函数sleep()
#include <math.h>
int r[3][4]={{30,20,130,60},{170,20,220,60},{260,20,310,60}};//三个按钮的二维数组int button_judge(int x,int y)
{if(x>r[0][0] && x<r[0][2] && y>r[0][1] && y<r[0][3])return 1;if(x>r[1][0] && x<r[1][2] && y>r[1][1] && y<r[1][3])return 2;if(x>r[2][0] && x<r[2][2] && y>r[2][1] && y<r[2][3])return 3;return 0;
}
int main()
{int i,event=0;short win_width,win_height;//定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width,win_height);//初始化窗口(黑屏)for(i=0;i<256;i+=5){setbkcolor(RGB(i,i,i));//设置背景色,原来默认黑色cleardevice();//清屏(取决于背景色)Sleep(15);//延时15ms}RECT R1={r[0][0],r[0][1],r[0][2],r[0][3]};RECT R2={r[1][0],r[1][1],r[1][2],r[1][3]};RECT R3={r[2][0],r[2][1],r[2][2],r[2][3]};LOGFONT f;gettextstyle(&f);					//获取字体样式_tcscpy(f.lfFaceName,_T("宋体"));	//设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿  settextstyle(&f);                     // 设置字体样式settextcolor(BLACK);				//BLACK在graphic.h头文件里面被定义为黑色的颜色常量drawtext("输入参数",&R1,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R1内输入文字,水平居中,垂直居中,单行显示drawtext("运行",&R2,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R2内输入文字,水平居中,垂直居中,单行显示drawtext("退出",&R3,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R3内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r[0][0],r[0][1],r[0][2],r[0][3]);rectangle(r[1][0],r[1][1],r[1][2],r[1][3]);rectangle(r[2][0],r[2][1],r[2][2],r[2][3]);MOUSEMSG m;//鼠标指针while(true){m = GetMouseMsg();//获取一条鼠标消息switch(m.uMsg){case WM_MOUSEMOVE:setrop2(R2_XORPEN);setlinecolor(LIGHTCYAN);//线条颜色为亮青色setlinestyle(PS_SOLID, 3);//设置画线样式为实现,10磅setfillcolor(WHITE);//填充颜色为白色if(button_judge(m.x,m.y)!=0){if(event != button_judge(m.x,m.y)){event = button_judge(m.x,m.y);//记录这一次触发的按钮fillrectangle(r[event-1][0],r[event-1][1],r[event-1][2],r[event-1][3]);//有框填充矩形(X1,Y1,X2,Y2)}}else{if(event != 0)//上次触发的按钮未被修正为原来的颜色{fillrectangle(r[event-1][0],r[event-1][1],r[event-1][2],r[event-1][3]);//两次同或为原来颜色event = 0;}}break;case WM_LBUTTONDOWN:setrop2(R2_NOTXORPEN);//二元光栅——NOT(屏幕颜色 XOR 当前颜色)for(i=0;i<=10;i++){setlinecolor(RGB(25*i,25*i,25*i));//设置圆颜色circle(m.x,m.y,2*i);Sleep(30);//停顿30mscircle(m.x,m.y,2*i);//抹去刚刚画的圆}break;FlushMouseMsgBuff();//清空鼠标消息缓存区}}system("pause");//暂停,为了显示return 0;
}

在这里插入图片描述
\qquad 这里我们运用了两次设置二元光栅的函数setrop2,在鼠标的移动条件内(case MOUSEMOVE),我们使用的是屏幕颜色和当前颜色异或,这是为什么呢?因为fillrectangle()函数是画一个有框填充矩形,我们让这个有框填充矩形和原按钮的一样大。由于线条的颜色为亮青色,填充颜色为白色(1),白色的填充颜色和屏幕颜色异或,取的是屏幕颜色的反色。按钮的边框是黑色(0),它与亮青色异或,则会保留原来的亮青色。
\qquad 与同或一样,异或两次等于没有执行操作,所以可以还原到原屏幕画布的颜色。

2.3.3.进度条

\qquad 既然涉及到进度条了,那么就应该涉及到正式程序了,这里我不想涉及太多的专业知识影响大家理解,但又不能让程序运行得太快以至于看不出进度条的变化,所以我设计了一个简单的弹性球轨迹作图程序。
\qquad 假设球半径为R,初始高度为 h 0 h_0 h0,初速度为0(自由落体),非弹性碰撞时能量损失率为 α \alpha α。计算部分子函数如下:

int simulation()
{float dt = 0.01;//仿真间隔10mslong int N = (long int)(sim_t/dt);//迭代次数float *h=(float*)calloc(N,sizeof(float));//高度float *v=(float*)calloc(N,sizeof(float));//速度(竖直方向)long int i;//迭代变量for(i=1;i<N;i++){if(h[i-1]>R)//未发生碰撞{v[i]=v[i-1]-9.8*dt;//速度计算}else//发生碰撞,动能损失alpha,速度损失alpha的开方{v[i]=-sqrt(alpha)*v[i-1];	}}free(h);free(v);//释放内存return 0;
}

\qquad 当然,我们还需要绘图网格,定义绘图网格的函数如下:

void init_figure()
{int i;setrop2(R2_COPYPEN);//当前颜色setlinecolor(BLACK);setlinestyle(PS_SOLID);//实线rectangle(30,100,420,330);//外框线setlinestyle(PS_DOT);//点线for(i=30+39;i<420;i+=39){line(i,100,i,330);//竖直辅助线}for(i=100+23;i<330;i+=23){line(30,i,420,i);//水平辅助线}
}

\qquad 注意,我们使用了rectangle()空心矩形函数绘制网格外框架,使用了line函数依次画出了辅助线。

\qquad 我们现在的目标就是将h的坐标转换到网格上去,绘制出球心的轨迹,这样似乎并不复杂,只需要对simulation()函数稍加修改即可。

int simulation()
{float dt = 0.01;//仿真间隔10msfloat dy = 230/h0;//单位纵坐标long int N = (long int)(sim_t/dt);//迭代次数float *h=(float*)calloc(N,sizeof(float));//高度float *v=(float*)calloc(N,sizeof(float));//速度(竖直方向)long int i;//迭代变量float process_duty;//进度init_figure();//初始化图像网格setrop2(R2_COPYPEN);//当前颜色//计算步骤h[0]=h0;v[0]=0;for(i=1;i<N;i++){if(h[i-1]>R)//未发生碰撞{v[i]=v[i-1]-9.8*dt;//速度计算}else//发生碰撞,动能损失alpha,速度损失alpha的开方{v[i]=-sqrt(alpha)*v[i-1];	}h[i]=h[i-1]+v[i]*dt;//高度计算process_duty = (i+1)/(float)(N);putpixel(30+(int)(process_duty*390),330-(int)(h[i]*dy),RED);//画点putpixel(X,Y,color*)Sleep(dt*1000);//延时}free(h);free(v);return 0;
}

\qquad 这里的新函数putpixel(X,Y,color*)是画像素点的函数,适合刻画不连续或不规则的移动轨迹。
\qquad 现在我们只剩下了刻画进度条的函数了,进度条的刷新很明显是应该放在for循环里面的,那么我们采用什么进度条的格式呢?进度条可以有圆形、扇形、长条连续型、长条不连续型等多种,我们这里采用的是环形进度条,将进度数字显示在环中心。请看以下的对simulation()函数改进的代码:

//仿真运行
int simulation()
{char t[3];//百分值的字符char *out_text;//带百分号的百分字符float dt = 0.01;//仿真间隔10msfloat dy = 230/h0;//单位纵坐标long int N = (long int)(sim_t/dt);//迭代次数float *h=(float*)calloc(N,sizeof(float));//高度float *v=(float*)calloc(N,sizeof(float));//速度(竖直方向)long int i;//迭代变量float process_duty;//进度RECT r={370,35,400,65};//百分值显示区域的矩形指针init_figure();//初始化图像网格setrop2(R2_COPYPEN);//当前颜色setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354,19,411,81);//覆盖原进度条区域setlinestyle(PS_NULL);//无线条setbkmode(TRANSPARENT);//设置文字填充背景为透明//计算步骤h[0]=h0;v[0]=0;BeginBatchDraw();//开始缓存区for(i=1;i<N;i++){if(h[i-1]>R)//未发生碰撞{v[i]=v[i-1]-9.8*dt;//速度计算}else//发生碰撞,动能损失alpha,速度损失alpha的开方{v[i]=-sqrt(alpha)*v[i-1];	}setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354,19,416,81);//覆盖原进度条区域h[i]=h[i-1]+v[i]*dt;//高度计算process_duty = (i+1)/(float)(N);setlinestyle(PS_SOLID);putpixel(30+(int)(process_duty*390),330-(int)(h[i]*dy),RED);setfillcolor(BLUE);setlinestyle(PS_NULL);fillpie(355,20,415,80,0,process_duty*2*PI);setfillcolor(WHITE);fillcircle(385,50,20);sprintf(t,"%d",(int)(process_duty*100.0));//整型转换为字符串out_text = strcat(t,"%");//添加一个百分号drawtext(out_text,&r,DT_CENTER | DT_VCENTER | DT_SINGLELINE);Sleep(dt*1000);FlushBatchDraw();//刷新缓存区}EndBatchDraw();//结束缓存区free(h);free(v);return 0;
}

\qquad 这里我们需要多加载一个头文件<string.h>。
\qquad 首先需要计算进度条的坐标,把环形进度条区域用白色矩形刷新掉,环形进度条需要一个扇形和圆形的组合,扇形的角度是0~360°。这里我们用到了fillpie(X1,Y1,X2,Y2,start_angle,end_angle),前四个参数为椭圆扇形的外接矩形坐标,后两个参数分别为起始角和终止角(弧度制)。每过一次迭代都重新计算终止角(起始角始终为0),即可起到扇形角度逐渐增长的效果,再用一个白色填充圆覆盖中心部分即可变成环形进度条。
\qquad FlushBatchDraw()函数是刷新缓存区的函数,与BeginBatchDraw()EndBatchDraw()一起使用,如果我们绘图之后不想立即显示,而想批量绘图最后一起刷新画板,用缓存区的方法再合适不过了。

3.完整代码及效果

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>				//用到了定时函数sleep()
#include <math.h>
#include <string.h>
#define PI 3.1416
int r[3][4]={{30,20,130,60},{170,20,220,60},{260,20,310,60}};//三个按钮的二维数组
float alpha,R,h0,sim_t;//碰撞时的能量损失率,球的半径、初始高度、仿真时间
//按钮判断函数
int button_judge(int x,int y)
{if(x>r[0][0] && x<r[0][2] && y>r[0][1] && y<r[0][3])return 1;if(x>r[1][0] && x<r[1][2] && y>r[1][1] && y<r[1][3])return 2;if(x>r[2][0] && x<r[2][2] && y>r[2][1] && y<r[2][3])return 3;return 0;
}
//初始化图像
void init_figure()
{int i;setrop2(R2_COPYPEN);//当前颜色setlinecolor(BLACK);setlinestyle(PS_SOLID);//实线rectangle(30,100,420,330);//外框线setlinestyle(PS_DOT);//点线for(i=30+39;i<420;i+=39){line(i,100,i,330);//竖直辅助线}for(i=100+23;i<330;i+=23){line(30,i,420,i);//水平辅助线}
}
//仿真运行
int simulation()
{char t[3];//百分值的字符char *out_text;float dt = 0.01;//仿真间隔10msfloat dy = 230/h0;//单位纵坐标long int N = (long int)(sim_t/dt);//迭代次数float *h=(float*)calloc(N,sizeof(float));//高度float *v=(float*)calloc(N,sizeof(float));//速度(竖直方向)long int i;//迭代变量float process_duty;//进度RECT r={370,35,400,65};//百分值显示区域的矩形指针init_figure();//初始化图像网格setrop2(R2_COPYPEN);//当前颜色setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354,19,411,81);//覆盖原进度条区域setlinestyle(PS_NULL);//无线条setbkmode(TRANSPARENT);//设置文字填充背景为透明//计算步骤h[0]=h0;v[0]=0;BeginBatchDraw();//开始缓存区for(i=1;i<N;i++){if(h[i-1]>R)//未发生碰撞{v[i]=v[i-1]-9.8*dt;//速度计算}else//发生碰撞,动能损失alpha,速度损失alpha的开方{v[i]=-sqrt(alpha)*v[i-1];	}setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354,19,416,81);//覆盖原进度条区域h[i]=h[i-1]+v[i]*dt;//高度计算process_duty = (i+1)/(float)(N);setlinestyle(PS_SOLID);putpixel(30+(int)(process_duty*390),330-(int)(h[i]*dy),RED);setfillcolor(BLUE);setlinestyle(PS_NULL);fillpie(355,20,415,80,0,process_duty*2*PI);setfillcolor(WHITE);fillcircle(385,50,20);sprintf(t,"%d",(int)(process_duty*100.0));//整型转换为字符串out_text = strcat(t,"%");//添加一个百分号drawtext(out_text,&r,DT_CENTER | DT_VCENTER | DT_SINGLELINE);Sleep(dt*1000);FlushBatchDraw();//刷新缓存区}EndBatchDraw();//结束缓存区free(h);free(v);return 0;
}int main()
{int i,event=0;char s[30];//输入字符串变量short win_width,win_height;//定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width,win_height);//初始化窗口(黑屏)for(i=0;i<256;i+=5){setbkcolor(RGB(i,i,i));//设置背景色,原来默认黑色cleardevice();//清屏(取决于背景色)Sleep(30);//延时30ms}RECT R1={r[0][0],r[0][1],r[0][2],r[0][3]};RECT R2={r[1][0],r[1][1],r[1][2],r[1][3]};RECT R3={r[2][0],r[2][1],r[2][2],r[2][3]};LOGFONT f;//字体样式指针gettextstyle(&f);					//获取字体样式_tcscpy(f.lfFaceName,_T("宋体"));	//设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿  settextstyle(&f);                     // 设置字体样式settextcolor(BLACK);				//BLACK在graphic.h头文件里面被定义为黑色的颜色常量drawtext("输入参数",&R1,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R1内输入文字,水平居中,垂直居中,单行显示drawtext("运行",&R2,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R2内输入文字,水平居中,垂直居中,单行显示drawtext("退出",&R3,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R3内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r[0][0],r[0][1],r[0][2],r[0][3]);rectangle(r[1][0],r[1][1],r[1][2],r[1][3]);rectangle(r[2][0],r[2][1],r[2][2],r[2][3]);MOUSEMSG m;//鼠标指针while(true){m = GetMouseMsg();//获取一条鼠标消息switch(m.uMsg){case WM_MOUSEMOVE:setrop2(R2_XORPEN);setlinecolor(LIGHTCYAN);//线条颜色为亮青色setlinestyle(PS_SOLID, 3);//设置画线样式为实现,10磅setfillcolor(WHITE);//填充颜色为白色if(button_judge(m.x,m.y)!=0){if(event != button_judge(m.x,m.y)){event = button_judge(m.x,m.y);//记录这一次触发的按钮fillrectangle(r[event-1][0],r[event-1][1],r[event-1][2],r[event-1][3]);//有框填充矩形(X1,Y1,X2,Y2)}}else{if(event!=0)//上次触发的按钮未被修正为原来的颜色{fillrectangle(r[event-1][0],r[event-1][1],r[event-1][2],r[event-1][3]);//两次同或为原来颜色event = 0;}}break;case WM_LBUTTONDOWN:setrop2(R2_NOTXORPEN);//二元光栅——NOT(屏幕颜色 XOR 当前颜色)for(i=0;i<=10;i++){setlinecolor(RGB(25*i,25*i,25*i));//设置圆颜色circle(m.x,m.y,2*i);Sleep(20);//停顿30mscircle(m.x,m.y,2*i);//抹去刚刚画的圆}//按照按钮判断左键单击后的操作switch(button_judge(m.x,m.y)){//复原按钮原型case 1:InputBox(s,30,"请输入碰撞时的能量损失率、球的半径、初始高度、仿真时间");sscanf(s,"%f%f%f%f",&alpha,&R,&h0,&sim_t);//将输入字符串依次扫描到全局变量里面FlushMouseMsgBuffer();//单击事件后清空鼠标消息break;case 2:simulation();//仿真运行FlushMouseMsgBuffer();//单击事件后清空鼠标消息break;case 3:closegraph();//关闭绘图环境exit(0);//正常退出default:FlushMouseMsgBuffer();//单击事件后清空鼠标消息//printf("\r\n(%d,%d)",m.x,m.y);//打印鼠标坐标,方便调试时确定区域break;}break;}}return 0;
}

在这里插入图片描述
在这里插入图片描述
希望本文对您有帮助,谢谢阅读。


http://chatgpt.dhexx.cn/article/IXjg6fMt.shtml

相关文章

Drug Discovery Today| 频繁命中化合物:高通量筛选中需警惕的假阳性结果

今天给大家介绍的是2020年1月在Drug Discovery Today上发表的综述“Frequent hitters: nuisance artifacts in high-throughput screening”。高通量筛选是药物研发的一个重要手段&#xff0c;然而研究中发现一些化合物在不同类型靶点筛选中均表现出阳性结果&#xff0c;这类化…

算法的评价标准:ROC,假阳性,mape

名称含义公式真阳率\召回率\查全率\TPR\Recall表示正确预测的正样本与全部正样本的比值 a a c \frac{a}{ac} aca​假阳性率\FPR表示负样本被预测为正样本与全部负样本的比值 b b d \frac{b}{bd} bdb​精确率\查准率\Precision\表示正确预测的正样本与预测为正样本的比值 a a …

【笔记】 Hard negative:区域建议框中得分较高的False Positive(假阳性)

eg1: 对于目标检测中我们会事先标记处ground truth&#xff0c;然后再算法中会生成一系列proposal&#xff0c;这些proposal有跟标记的ground truth重合的也有没重合的&#xff0c;那么重合度&#xff08;IOU&#xff09;超过一定阈值&#xff08;通常0.5&#xff09;的则认定为…

病毒组学数据分析 -03 DRAM-V 病毒序列识别(剔除假阳性)

DRAM&#xff08;Distilling and Refining Annotations of Metabolism&#xff0c;提取和精练代谢注释&#xff09;是一种用于注释宏基因组组装基因组和VirSorter确定的病毒重叠群的工具。DRAM 使用KEGG、UniRef90、PFAM、dbCAN、RefSeq 病毒、VOGDB和MEROPS注释 MAG&#xff0…

【概率论】理解贝叶斯(Bayes)公式:为什么疾病检测呈阳性,得这种病的概率却不高?

先说结论&#xff1a;因为假阳性的人数相比于真阳性太多了。 具体是怎么回事呢&#xff1f;咱们慢慢分析。 文章目录 一、贝叶斯公式二、典例分析三、贝叶斯公式的本质思考&#xff08;摘自教材&#xff09; 一、贝叶斯公式 定理1&#xff08;贝叶斯公式&#xff09; 设有事件…

全面梳理:准确率,精确率,召回率,查准率,查全率,假阳性,真阳性,PRC,ROC,AUC,F1

二分类问题的结果有四种&#xff1a; 逻辑在于&#xff0c;你的预测是positive-1和negative-0&#xff0c;true和false描述你本次预测的对错 true positive-TP&#xff1a;预测为1&#xff0c;预测正确即实际1 false positive-FP&#xff1a;预测为1&#xff0c;预测错误即实…

imputation-文献:False signals induced by single-cell imputation(scRNA-seq插补引入的假阳性问题)

文章题目 False signals induced by single-cell imputation 中文名&#xff1a; 单细胞插补引起的假信号 文章地址&#xff1a; https://f1000research.com/articles/7-1740/v2 评价插补方法&#xff1a; SAVER,DrImpute,scImpute,DCA,MAGIC,knn-smooth 上述方法基于原…

混淆矩阵、召回率、精确率、正确率、F1、真阳性率、假阳性率、ROC、AUC

C o n f u s i o n M a t r i x : Confusion Matrix: ConfusionMatrix: 真实 1 0 预测 1 TP(命中) FP(虚报) 0 FN(漏报) TN(正确拒绝) 召回率 R e c a l l T P T P F N Recall \dfrac{TP}{TP FN} RecallTPFNTP​&#xff0c;关注真实情况&#xff0c;关注positive。“好瓜被…

准确率,召回率,mAP,ROC,AUC,特异性,敏感性,假阴性,假阳性

P/R和ROC是两个不同的评价指标和计算方式&#xff0c;一般情况下&#xff0c;检索用准确率、召回率、F1、AP和mAP&#xff0c;分类、识别等用ROC和AUC&#xff08;特异性和敏感性是ROC当中的一个部分&#xff09;。 准确率、召回率、F1、AP和mAP这几个指标需要依次看&#xff0…

扩增子测序引入的假阳性稀有类群干扰对微生物群落多样性、构建机制及相互作用的研究...

# 01 2022年8月17日&#xff0c;青岛华大基因研究院、深圳华大生命科学研究院联合中国农业科学院北京畜牧兽医研究所、山东大学微生物技术国家重点实验室、丹麦哥本哈根大学等单位在 Environmental Microbiome (IF 6.36) 上发表了题为 “Sequencing introduced false positive …

敏感性、特异度、α、β、阳性预测值(PPV)、阴性预测值(NPV)等指标及置信区间计算(附R语言代码)

这个虽然简单但老是被绕进去,所以整理一下方便查阅。 首先画一个22的混淆矩阵confusion matrix: TP = True positive(真阳性) FP = False positive (假阳性) FN = False negative(假阴性) TN = True negative(真阴性) 敏感性(sensitivity)= 真阳性率 = 真阳/实…

真阳性假阳性假阴性分割可视化

1.分割掩码二值化 分割掩码转化为图像格式时会在分割边界处有很多灰度像素点&#xff0c;这将导致后续利用分割掩码和预测分割掩码进行处理时会在边界处出现很多噪声点&#xff0c;因此利用阈值将分割掩码转换为二值图&#xff0c;消除边界上的灰度像素点。 代码 import nump…

(精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标

1、概念 金标准&#xff08;标准集&#xff09; 预测算法&#xff08;预测集&#xff09; 验证存在&#xff08;T&#xff09; 验证不存在&#xff08;F&#xff09; 合计 预测存在&#xff08;P&#xff09; 预测为正&#xff0c;真实为正&#xff08;TP&#xff09; …

fNIRS中的假阳性和假阴性:问题、挑战和方法

导读 本文强调了在进行功能性近红外光谱(fNIRS)研究时需要考虑和解决的一个重要问题&#xff0c;即无意中测量非神经血管耦合引起的fNIRS血流动力学反应的可能性。这些可能被误解为大脑活动&#xff0c;即“假阳性”(由于错误地将检测到的血流动力学反应分配给功能性大脑活动而…

精确度、召回率、真阳性、假阳性

1) 精确度( precision )&#xff1a;TP / ( TPFP ) TP / P 2) 召回率&#xff08;recall&#xff09;&#xff1a;TP / (TP FN ) TP / T 3) 真阳性率&#xff08;True positive rate&#xff09;&#xff1a;TPR TP / ( TPFN ) TP / T &#xff08;敏感性 sensiti…

每天五分钟机器学习:如何计算模型的假阳性率和真阳性率?

本文重点 如上所示&#xff0c;我们学习了查准率和召回率&#xff0c;本文我们将学习真阳性率和假阳性率&#xff0c;学会这个对将来构建ROC曲线非常有帮助 真阳性率和假阳性率 假如使用测试集来评估一个分类模型&#xff08;二分问题&#xff09;&#xff1a;所以样本实际值…

统计学中的真阳性(TP),假阴性(FN),假阳性(FP),真阴性(TN)怎么理解?

举个例子,假如要在一个地区进行1000人的疾病检测,我们站在上帝视角,知道这1000人中,有10人是疾病感染者,占比1%。 但实际的检测结果可能存在误差,误差包括两种情况 疾病感染者,被错误诊断为健康身体健康,但却被错误诊断为感染者对应了两种情况 检测出来的是阴性,就一…

敏感性、特异性、假阳性、假阴性

敏感性、特异性、假阳性、假阴性是医学领域常用的评估指标。 敏感性&#xff1a;在金标准判断有病&#xff08;阳性&#xff09;的人群中&#xff0c;检测出阳性的几率。真阳性&#xff08;检测出确实有病的能力&#xff09; TPR TP / ( TPFN ) TP / T 特异性&#xff1a;在金…

ADODB简介

ADODB简介 ADODB 是 Active Data Objects Data Base 的简称&#xff0c;它是一种 PHP 存取数据库的函式组件。现在 SFS3 系统 (校园自由软件交流网学务系统) 计划的主持人陈莹光老师&#xff0c;决定采用此一组件&#xff0c;为了让更多有心参与该项目的伙伴们能够顺利加入发展…

Padavan固件添加adbyby去广告功能

2019独角兽企业重金招聘Python工程师标准>>> 在路由-》自定义脚本》wan上下行启动后执行&#xff0c;添加下面脚本 #!/bin/shsleep 30###Adbyby去广告脚本### Adbyby1 ### 0关闭&#xff1b;1启动 ########以下脚本请勿更改##### if [ "$Adbyby" "0…