主打一个清晰易懂教程:
原版移步:EasyX完整版基础教程【语雀文档】
目录
1. 打开:initgraph(int x,int y,int style);
2. 关闭窗口函数:closegraph()关闭图形库(窗口有打开就有关闭)
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. 设置填充样式函数
绘图函数从填充样式分类可分为无填充、有边框填充、无边框三种。
ⅰ. 以画圆为例
circle()
:无填充fillcircle()
:有边框填充solidcircle()
:无边框填充
可视化例子:
(无边框填充)↑ ↑(有边框填充)
b. 设置图形样式函数
- 按所画的图形形状分类,有以下常用几类图形函数:
circle()
画圆elipse()
画椭圆pie()
画扇形polygon()
画多边形rectangle
画矩形roundrect
画圆角矩形line
画线putpixel
画点
ⅰ. 代码实现示例:
问:如何画?怎么写代码?
答:以画圆为例:
根据数学知识,确定一个圆只需圆心坐标+半径即可:
所以输入的三个参数依次为:
- 圆心的x坐标(x)
- 圆心的y坐标(y)
- 圆的半径(radius)
这里以圆心坐标(500,500),半径为200,为例子。
- 运行结果截图:
c. 设置颜色函数
- 设置填充颜色函数:
setfillcolor(颜色)
- 设置线条颜色函数:
setlinecolor(颜色)
- 设置线条样式函数:
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. 文字绘制函数
- 输出字符串函数:
outtextxy(int x, int y, LPCTSTR str);
作用:在指定位置输出字符串
参数解释:(x,y)是坐标,str决定文本内容
例子:outtextxy(50,50,'a');//在(50,50)位置输出字符a
若改为outtextxy(50,50,"asarfewf");
即把单个字符换为字符串,可能出现错误,以下是解决方案:
- 在字符串前面加上大写 L
- 用TEXT( )或_T( )把字符串括住,原理同上
- 不需要添加任何代码,进项目→属性→配置属性→常规→项目默认值→字符集→改为多字节字符集(推荐使用这个方式)
2.设置文字样式函数:settextstyle(int font, int direction, int charsize)
参数解释:
- font: 这个参数是一个整数,代表要使用的字体类型。
- direction: 这个参数是一个整数,用于指定文本的方向。
通常,0 表示水平方向(HORIZ_DIR),1 表示垂直方向(VERT_DIR)
3.charsize: 这个参数是一个字符串,用于指定字体的大小。
settextstyle(50,0,20)//表示字体类型为编号为50,方向水平,大小20
3.设置文字背景模式:setbkmode(int mode);
参数解释:
参数mode
可以是以下两个值之一:
TRANSPARENT
:表示文本绘制时背景是透明的,即文本绘制时不修改背景。这意味着文本绘制的地方保持原来的背景,不会被覆盖。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;
- 图像加载函数:
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. 鼠标画线操作
- 画图功能:(定时器逻辑)
- 画图过程可拆解为两个步骤:鼠标点击+鼠标拖动→画线
- 停止画线的逻辑:即鼠标停止拖动(不松开),并且再拖动可以继续画
做一个画图工具,要求包含以上逻辑示例:
#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()) {
// 等待键盘按键消息发生
}