欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

用C语言实现图形化界面:包含图形、按钮、鼠标和进度条等功能的创建教程(附详尽示例代码与详解注释)

最编程 2024-02-21 08:41:52
...

目录

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

0.引言

\qquad 看了****上很多关于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]};//矩形指针R1
	RECT R2={r2[0],r2[1],r2[2],r2[3]};//矩形指针R2
	RECT R3={r3[0],r3[1],r3[2],r3[3]};//矩形指针R3
	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]);
	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);//停顿2ms
				circle(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