C/C++图形化编程——EasyX使用教程

avatar
作者
筋斗云
阅读量:1

主打一个清晰易懂教程:

原版移步:EasyX完整版基础教程【语雀文档】

目录

1.创建图形化窗口

a. 包含头文件

ⅰ. 两种头文件:

ⅱ. 几种窗口函数:

1. 打开:initgraph(int x,int y,int style);

2. 关闭窗口函数:closegraph()关闭图形库(窗口有打开就有关闭)

3. 清空绘图函数:cleardevice()

ⅲ. 窗口坐标的知识:

ⅳ. 绘制窗口例子:

2. 基本绘图函数

a. 设置填充样式函数

ⅰ. 以画圆为例

可视化例子:

b. 设置图形样式函数

ⅰ. 代码实现示例:

c. 设置颜色函数

d. 文字绘制函数

3. 图像处理函数

4. 鼠标消息函数

a. 接收鼠标消息代码示例1

b. 接收鼠标消息代码示例2

5. 鼠标画线操作

6. 音乐播放

a. 播放音乐的函数

7. 阻塞式和非阻塞式

a. 阻塞式(Blocking):

b. 非阻塞式(Non-blocking):

c. 相关函数


1.创建图形化窗口

a. 包含头文件

ⅰ. 两种头文件:

graphics.h(包含已经淘汰的函数)

easy.h(只包含最新的)

ⅱ. 几种窗口函数:

1. 打开:initgraph(int x,int y,int style);

initgraph函数的参数的解释:

  • x:窗口宽度,单位是像素
  • y:窗口高度,单位是像素
  • style:窗口样式,以下是常见窗口样式:
  • DEFAULT:默认样式,创建一个可关闭的窗口。
  • NOCLOSE:创建一个无法关闭的窗口,没有关闭按钮。
  • NOMINIMIZE:创建一个无法最小化的窗口,没有最小化按钮。
  • NOMAXIMIZE:创建一个无法最大化的窗口,没有最大化按钮。
  • NORESIZE:创建一个无法改变大小的窗口,没有调整大小的边框。
  • NOCAPTION:创建一个没有标题栏的窗口,没有标题栏和边框。
  • CUSTOMSTYLE:自定义样式,用户可以通过指定参数实现特定需求的窗口样式。

设置窗口的例子:

... #include<graphics.h> int main() { 	initgraph(200, 200,NOCLOSE);//设置宽度为200,高度为200,NOCLOSE指无法关闭的窗口 	//以下语句暂不做解释     getchar(); 	closegraph(); 	return 0; } ...

运行截图:可以看到该窗口是无法关闭的。

2. 关闭窗口函数:closegraph()关闭图形库(窗口有打开就有关闭)
3. 清空绘图函数:cleardevice()

ⅲ. 窗口坐标的知识:

坐标系长这个样子:

确定一个矩形框,只需要给出左上角和右下角的坐标即可

ⅳ. 绘制窗口例子:

#include<stdio.h> //1.包含图形库头文件,就能使用图形库函数 #include<graphics.h> int main() { 	initgraph(640, 480);	//2.初始化图形库,确定矩形窗口大小  	line(100, 100, 200, 200);	//3.画图     (此处画的是由(100,100)和(200,200)这两个点构成的连线) 	     getchar();	//4.暂停,防止窗口闪退 	closegraph();	//5.关闭图形库(窗口有打开就有关闭) 	return 0; }
  • 运行截图:

2. 基本绘图函数

简介:利用不同的函数绘制各种图形

a. 设置填充样式函数

绘图函数从填充样式分类可分为无填充、有边框填充、无边框三种。

ⅰ. 以画圆为例

  1. circle():无填充
  2. fillcircle():有边框填充
  3. solidcircle():无边框填充
可视化例子:

(无边框填充)↑ ↑(有边框填充)

b. 设置图形样式函数

  • 按所画的图形形状分类,有以下常用几类图形函数
  1. circle()画圆
  2. elipse()画椭圆
  3. pie()画扇形
  4. polygon()画多边形
  5. rectangle画矩形
  6. roundrect画圆角矩形
  7. line画线
  8. putpixel画点

ⅰ. 代码实现示例:

问:如何画?怎么写代码?

答:以画圆为例:

根据数学知识,确定一个圆只需圆心坐标+半径即可:

所以输入的三个参数依次为:

  1. 圆心的x坐标(x)
  2. 圆心的y坐标(y)
  3. 圆的半径(radius)

这里以圆心坐标(500,500),半径为200,为例子。

  • 运行结果截图:

c. 设置颜色函数

  1. 设置填充颜色函数:setfillcolor(颜色)
  2. 设置线条颜色函数:setlinecolor(颜色)
  3. 设置线条样式函数:setlinestyle(线型, 宽度)

常见的线条样式:

  • PS_SOLID:实线型
  • PS_DASH:短划线型
  • PS_DOT:点线型
  • PS_DASHDOT:短划线加点线型
  • PS_DASHDOTDOT:短划线加两个点线型
  • PS_NULL:不画线,只移动当前点
setlinestyle(PS_SOLID,5);//设置线条样式:实线,宽度5 setfillcolor(YELLOW);//设置填充颜色:黄色 setlinecolor(BLUE);//设置线条颜色:蓝色

 4.设置背景颜色函数:setbkcolor(颜色);

  • 注意:设置背景颜色通常需要两步,简称两部曲
initgragh(200,200);设置窗口大小 setbkcolor(WHITE);//第一步:设置颜色 cleardevice();//第二步:清屏

注:该文章中,为了表达简洁,一般不展示头文件等其他内容,只展示重要代码

  • 运行截图:

d. 文字绘制函数

  1. 输出字符串函数:outtextxy(int x, int y, LPCTSTR str);

作用:在指定位置输出字符串

参数解释:(x,y)是坐标,str决定文本内容

例子:outtextxy(50,50,'a');//在(50,50)位置输出字符a

若改为outtextxy(50,50,"asarfewf");即把单个字符换为字符串,可能出现错误,以下是解决方案:

  1. 在字符串前面加上大写 L
  2. 用TEXT( )或_T( )把字符串括住,原理同上
  3. 不需要添加任何代码,进项目→属性→配置属性→常规→项目默认值→字符集→改为多字节字符集(推荐使用这个方式)

2.设置文字样式函数:settextstyle(int font, int direction, int charsize)

参数解释:

  1. font: 这个参数是一个整数,代表要使用的字体类型
  2. direction: 这个参数是一个整数,用于指定文本的方向

通常,0 表示水平方向(HORIZ_DIR),1 表示垂直方向(VERT_DIR)

     3.charsize: 这个参数是一个字符串,用于指定字体的大小

settextstyle(50,0,20)//表示字体类型为编号为50,方向水平,大小20

3.设置文字背景模式:setbkmode(int mode);

参数解释:

参数mode可以是以下两个值之一:

  1. TRANSPARENT:表示文本绘制时背景是透明的,即文本绘制时不修改背景。这意味着文本绘制的地方保持原来的背景,不会被覆盖。
  2. OPAQUE:表示文本绘制时背景是不透明的,即文本绘制时会先用当前背景色填充背景区域,然后在其上绘制文本。
/*...*/ setbkmode(TRANSPARENT);//设置文字背景为透明 outtextxy(50,50,"dsadd");//在(50,50)位置输出dsadd字样 /*...*/

 4.设置文字颜色函数:settextcolor(COLORREF color);

通常使用 RGB(r, g, b) 宏来创建颜色值,其中 r、g、b 分别代表红色、绿色和蓝色的分量。

例如,如果你想要将文本颜色设置为红色,可以这样调用settextcolor() 函数:

settextcolor(RGB(255, 0, 0)); // 红色

  • RGB配置指颜色调色板中三原色对应的数值:

5.获取文本宽和高函数:textheight(LPCTSTR str) textwidth(LPCTSTR str)

char arr[]= "我是字符串"; textheight(arr);//获取字符串宽度 textwidth(arr);//获取字符串高度

3. 图像处理函数

在使用图像之前,需要定义一个对象,然后把图片加载进变量才能使用。

  • 在使用图片的时候需要EasyX提供给我们的类型:IMAGE ,如IMAGE img;
  1. 图像加载函数:loadimage(IMAGE *img, LPCTSTR filename, int width, int height, BOOL shared = FALSE);
int loadimage(     IMAGE *img,           // 指向 IMAGE 结构体的指针,用于存储加载的图像数据     LPCTSTR filename,     // 指定图片文件的路径     int width,            // 指定图片的宽度     int height,           // 指定图片的高度     BOOL shared = FALSE  // 指定是否加载为共享图像,默认为 FALSE ); 

2.图像输出函数:BOOL putimage( HDC hdcDest, int xDest, int yDest, constvoid *img, DWORD rop = SRCCOPY )

BOOL putimage(     HDC hdcDest,         // 目标设备上下文句柄     int xDest,           // 目标矩形区域左上角的 x 坐标     int yDest,           // 目标矩形区域左上角的 y 坐标     const void *img,     // 要输出的图像数据     DWORD rop = SRCCOPY  // 光栅操作码,指定如何将图像数据输出到目标设备上下文 ); 

加载并输出一张图片示例:

//实例化一个img对象 IMAGE img; //加载图片 //相对路径:"./"表示当前文件夹,"../"表示当前文件夹的上一级文件夹,比如:./图片名.png  //绝对路径:比如:D:\\biancheng\\Project31\\图片名.png,得用双反斜杠 loadimage(&img,"./图片.png");//以相对路径加载一张图片 //loadimage(&img,"D:\\biancheng\\Project31\\图片名.png");以绝对路径加载一张图片 putimage(0,0,&img);//从窗口的(0,0)位置输出图片

4. 鼠标消息函数

//包含在easyx.h头文件中 // Message Structure struct ExMessage { 	USHORT message;	// 用于区分鼠标消息 	union 	{ 		// Data of the mouse message 		struct 		{ 			bool ctrl		:1;		// 指示CTRL键是否按下 			bool shift		:1;		// 指示SHIFT键是否按下 			bool lbutton	:1;		// 指示鼠标左键是否按下 			bool mbutton	:1;		// 指示鼠标中键是否按下 			bool rbutton	:1;		// 指示鼠标右键是否按下 			short x;				// 鼠标光标的y的坐标 			short y;				// 鼠标光标的x的坐标 			short wheel;			// The distance the wheel is rotated, expressed in multiples or divisions of 120 		}; };
  • 常见鼠标消息宏定义:

若想了解更多的关于鼠标消息的定义,可以鼠标右键点击该定义→转到定义,即可。

#define WM_MOUSEMOVE       //鼠标移动消息             #define WM_LBUTTONDOWN      //鼠标左键按下消息     #define WM_LBUTTONUP        //鼠标左键弹起消息         #define WM_LBUTTONDBLCLK     // 鼠标左键双击消息          #define WM_RBUTTONDOWN       //鼠标左键按下消息             #define WM_RBUTTONUP       //鼠标左键弹起消息               #define WM_RBUTTONDBLCLK    //鼠标右键双击消息             #define WM_MBUTTONDOWN    //鼠标中键按下消息                #define WM_MBUTTONUP     //鼠标中键弹起消息                 #define WM_MBUTTONDBLCLK  //鼠标中键双击消息  

一般记住以下四种就行了,其他不会了可以速查:

WM_MOUSEMOVE: m.message== WM_MOUSEMOVE; //鼠标移动 WM_LBUTTONDOWN: 左键按下 WM_RBUTTONDOWN: 右键按下 WM_LBUTTONUP: 左键弹起

a. 接收鼠标消息代码示例1

程序功能介绍:若点击左键,会在控制台打印出“左键按键......”;若点击右键,会在控制台打印出“右键按键......”

#include<stdio.h> #include<easyx.h> #include<stdbool.h> int main() {     ExMessage m; // 定义一个ExMessage类型的变量m,用于存储消息     initgraph(640, 480, 1); // 初始化图形窗口,设置窗口大小为640x480像素,1表示使用默认模式      while (1) // 进入无限循环     {         peekmessage(&m, EM_MOUSE); // 检查是否有鼠标消息,将消息存储在m中          if (m.message == WM_LBUTTONDOWN) // 如果检测到鼠标左键按下消息         {             printf("左键按键......\n"); // 输出提示信息:左键按键         }         else if (m.message == WM_RBUTTONDOWN) // 如果检测到鼠标右键按下消息         {             printf("右键按键......\n"); // 输出提示信息:右键按键         }     }      return 0; } 

b. 接收鼠标消息代码示例2

程序介绍:这个程序不显示控制台,若在淡蓝色窗口中点击左键,会立即在鼠标点击位置绘制出半径为10的红色的圆;若在窗口中点击右键,会立即在鼠标点击位置绘制出半径为10的黑色的圆;

在C++的easyx库中,当使用`flag = 1`来设置全屏模式时,控制台不会显示。全屏模式下,窗口会占据整个屏幕,控制台将不可见。

  • 以下是一些常见的flag参数取值及其含义:
  • flag = 0: 普通窗口模式,窗口有标题栏和边框。
  • flag = 1: 全屏模式,窗口占据整个屏幕,没有标题栏和边框。
  • flag = 2: 窗口模式,窗口有标题栏但没有边框。
  • flag = 3: 最大化窗口模式,窗口占据整个屏幕但有标题栏。
#include<easyx.h> #include<stdbool.h> int main() {          ExMessage m; // 定义一个ExMessage类型的变量m,用于存储消息     initgraph(640, 480); // 初始化图形窗口,设置窗口大小为640x480像素,1表示使用默认模式     setbkcolor(LIGHTBLUE); // 设置背景颜色为白色 	cleardevice(); // 清空屏幕     while (1) // 进入无限循环     {         peekmessage(&m, EM_MOUSE); // 检查是否有鼠标消息,将消息存储在m中          if (m.message == WM_LBUTTONDOWN) // 如果检测到鼠标左键按下消息         {             setfillcolor(RED); // 设置填充颜色为红色             solidcircle(m.x, m.y, 10); // 绘制一个实心圆,圆心坐标为m.x, m.y,半径为10         }         else if (m.message == WM_RBUTTONDOWN) // 如果检测到鼠标右键按下消息         {             setfillcolor(BLACK);// 设置填充颜色为黑色             solidcircle(m.x, m.y, 10);// 绘制一个实心圆,圆心坐标为m.x, m.y,半径为10         }          if (m.message == WM_MOUSEMOVE)         {              line(0, 0, m.x, m.y);         }     }     closegraph();     return 0; }

知识拓展:hook(钩子)是什么?

编程中的“hook”指的是一种机制,允许你拦截和修改系统或应用程序的行为。通过使用钩子,开发人员可以在程序执行流程的特定点注入自己的代码,以执行额外的操作、改变程序的行为或响应事件。钩子通常以函数指针、回调函数、事件监听器或框架或库提供的特定接口的形式实现。在软件开发中,钩子经常用于事件驱动编程、图形用户界面、Web开发(例如React钩子)以及其他需要定制和扩展性的场景中。

比如:自动鼠标点击软件通常会使用钩子来实现自动化点击功能。通过钩子,这类软件可以拦截鼠标事件并模拟鼠标点击操作,从而实现自动点击的功能。钩子在这种情况下被用来监视和干预鼠标事件,以便程序能够自动执行点击操作。

5. 鼠标画线操作

  • 画图功能:(定时器逻辑)
  1. 画图过程可拆解为两个步骤:鼠标点击+鼠标拖动→画线
  2. 停止画线的逻辑:即鼠标停止拖动(不松开),并且再拖动可以继续画

做一个画图工具,要求包含以上逻辑示例:

#include<iostream> // 引入基本输入输出流 #include<graphics.h> // 引入图形库头文件(可能是指EasyX或其他图形库) #include<stdio.h> // 引入标准输入输出库 #include<stdlib.h> // 引入标准库,用于内存分配等 #include<conio.h> // 引入控制台输入输出库 #include<easyx.h> // 引入EasyX图形库头文件 #include<stdbool.h> // 引入标准布尔库 #include<assert.h>//包含assert.h以使用assert宏  struct Point    // 定义一个结构体,用于存储点的坐标 {     int x; // 横坐标     int y; // 纵坐标 };  void setPoint(struct Point* point, int x, int y) // 设置点的坐标函数 {     point->x = x; // 设置横坐标     point->y = y; // 设置纵坐标 }  struct LineTool  // 定义一个画线工具的结构体 {     int size; // 线的大小(粗细)     COLORREF color; // 线的颜色     bool isDown;  // 标记鼠标是否按下     Point begin;    // 起始点坐标 };  // 创建画线工具的函数 struct LineTool* creatLineTool(int size, COLORREF color) {     struct LineTool* pLine = (struct LineTool*)malloc(sizeof(struct LineTool)); // 分配内存     assert(pLine); // 确保内存分配成功     pLine->size = size; // 设置线的大小     pLine->color = color; // 设置线的颜色     pLine->isDown = false; // 初始化鼠标未按下     return pLine; // 返回工具指针 }  // 设置线的颜色 void setLineColor(struct LineTool* pLine, COLORREF color) {     pLine->color = color; }  // 设置线的粗细 void setLineSize(struct LineTool* pLine, int size) {     pLine->size = size; }  // 根据鼠标事件绘制线条的函数 void drawLine(struct LineTool* pLine, ExMessage m) {     // 鼠标左键按下,记录位置     if (m.message == WM_LBUTTONDOWN)     {         pLine->isDown = true;         pLine->begin.x = m.x;         pLine->begin.y = m.y;     }     // 鼠标左键弹起     if (m.message == WM_LBUTTONUP)     {         pLine->isDown = false;     }     // 鼠标移动且左键按下,绘制线条     if (pLine->isDown == true && m.message == WM_MOUSEMOVE)     {         setlinestyle(PS_ENDCAP_ROUND, pLine->size); // 设置线条样式和粗细         setlinecolor(pLine->color); // 设置线条颜色         line(pLine->begin.x, pLine->begin.y, m.x, m.y); // 绘制线条         // 更新起始点坐标,以便连续绘制         pLine->begin.x = m.x;         pLine->begin.y = m.y;     }     // 鼠标右键按下,清空画布     if (m.message == WM_RBUTTONDOWN)     {         setbkcolor(WHITE); // 设置背景色为白色         cleardevice(); // 清空画布     } }  int main() {     initgraph(800, 800); // 初始化图形窗口大小为800x800     setbkcolor(WHITE); // 设置背景色为白色     struct LineTool* pLine = creatLineTool(5, BLACK); // 创建一个线条工具,线条为黑色,粗细为5     ExMessage m; // 定义一个消息结构体,用于接收鼠标消息     cleardevice(); // 清空画布     while (1) // 无限循环     {         peekmessage(&m, EM_MOUSE); // 获取鼠标消息         drawLine(pLine, m); // 根据鼠标消息绘制线条          if (_kbhit())//判断是否存在按键,存在按键则按键操作 返回非零值表示存在  {      char userKey = _getch();//阻塞函数      switch (userKey)      {      case'+':          //setLineSize(pLine,pLine->size++);          pLine->size++;          break;      case'-':          break;      case'\r':          exit(0);          break;      }     }     closegraph(); // 关闭图形窗口     return 0; } 

6. 音乐播放

● #include<windows.h> //如果包含这个graphics.h,windows.h可以不包含 ● 包含多媒体库:#include<mmsystem.h>  ● 包含静态库资源:#pragma comment("lib","winmm.lib")  

a. 播放音乐的函数

mciSendString("指令",0,0,0);(只支持MP3)

指令:open:打开 pause:暂停 resume:继续 close:关闭

  • play:播放:repeat /wait方式
  • 函数原型:
// 函数原型 DWORD mciSendString(   LPCTSTR  lpszCommand,  // 指向以 NULL 结尾的字符串,包含要发送的命令   LPTSTR   lpszReturnString, // 接收命令执行的结果的缓冲区   UINT     cchReturn,   // 指定 lpszReturnString 缓冲区的大小   HANDLE   hwndCallback // 指定用于接收通知消息的窗口句柄,通常为 NULL );  

mciSendString函数的第一个参数是LPCWSTR类型,它是一个指向常量宽字符的指针

  • 示例用法:做一个简单音乐播放程序
#include <Windows.h> // 包含 Windows.h 头文件,提供 Windows 平台下的 API 支持 #include <stdio.h> // 包含标准输入输出库头文件 #include <mmsystem.h> // 包含多媒体系统 API 头文件 #pragma comment(lib,"winmm.lib") // 指定链接到 winmm.lib 库  void makeMenu() // 定义函数 makeMenu,用于打印菜单 {     printf("-------[音乐播放]-------\n"); // 打印菜单标题     printf("\t\t0.退出\n"); // 打印退出选项     printf("\t\t1.播放音乐\n"); // 打印播放音乐选项     printf("\t\t2.暂停音乐\n"); // 打印暂停音乐选项     printf("\t\t3.继续音乐\n"); // 打印继续音乐选项     printf("\t\t4.关闭音乐\n"); // 打印关闭音乐选项     printf("-------------------\n"); // 打印分隔线 }  void keyDown() // 定义函数 keyDown,用于处理用户输入并执行相应操作 {     int userkey = 0; // 定义变量 userkey 存储用户输入     scanf_s("%d", &userkey); // 读取用户输入     switch (userkey) // 根据用户输入执行相应操作     {     case 0: // 用户输入为 0,退出程序         exit(0);     case 1: // 用户输入为 1,播放音乐         mciSendString(L"play ./music/1.mp3 repeat", NULL, 0, NULL); // 播放音乐文件,并设置为循环播放         break;     case 2: // 用户输入为 2,暂停音乐         mciSendString(L"pause ./music/1.mp3 ", NULL, 0, NULL); // 暂停音乐播放         break;     case 3: // 用户输入为 3,继续音乐         mciSendString(L"resume ./music/1.mp3 ", NULL, 0, NULL); // 继续音乐播放         break;     case 4: // 用户输入为 4,关闭音乐         mciSendString(L"close ./music/1.mp3 ", NULL, 0, NULL); // 关闭音乐文件         break;     } }  int main() // 主函数 {     mciSendString(L"open ./music/1.mp3", NULL, 0, NULL); // 打开音乐文件     while (1) // 进入主循环,持续显示菜单并处理用户输入     {         makeMenu(); // 显示菜单         keyDown(); // 处理用户输入     } } 

7. 阻塞式和非阻塞式

a. 阻塞式(Blocking):

    • 在阻塞式事件处理中,程序会一直等待某个事件的发生,直到该事件发生后才会继续执行后续代码。
    • 例如,在游戏中,如果采用阻塞式事件处理,程序会等待玩家的按键输入,直到玩家按下某个键后才会响应并继续执行游戏逻辑。
    • 在 EasyX 中,常见的阻塞式事件处理函数是 GetMouseMsg() 和 GetKey(),它们会一直等待鼠标消息和键盘消息的到来。

b. 非阻塞式(Non-blocking):

    • 在非阻塞式事件处理中,程序会定期地轮询或检查事件是否发生,如果发生了则立即处理,如果没有则继续执行后续代码。
    • 例如,在游戏中,如果采用非阻塞式事件处理,程序会定期检查玩家是否按下了某个键,如果按下了则立即响应,如果没有则继续执行游戏逻辑。
    • 在 EasyX 中,可以通过定时器来实现非阻塞式事件处理,比如使用 SetTimer() 设置一个定时器,然后在定时器回调函数中处理事件。

c. 相关函数

1.使用 kbhit() 等待键盘输入:

while (!kbhit()) {     // 等待键盘输入事件发生 }


这段代码会使程序进入一个循环,直到键盘输入事件发生(用户按下键盘上的任意键)才会跳出循环继续执行后续代码。

2. 使用 GetMouseMsg() 等待鼠标消息:

MOUSEMSG m; while (!MouseHit()) {     m = GetMouseMsg(); // 获取鼠标消息     // 处理鼠标消息 }


这段代码会不断地获取鼠标消息,直到有鼠标消息到达才会跳出循环继续执行后续代码。

3.使用 GetKey() 等待键盘按键消息:

while (!kbhit()) {     // 等待键盘按键消息发生 }

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!