文章目录
- EasyX图形库基础使用教程(快速上手)
EasyX图形库基础使用教程(快速上手)
前言:本文简单详细的介绍了EasyX图形库的常用函数和操作,帮助EasyX的快速上手
1、绘制简单的图形窗口
1.1头文件
graphics.h
:包含已经被淘汰的函数
easyx.h
: 只包含最新的函数
1.2创建图形化窗口
initgraphy函数
HWND initgraph(
int width, //绘图窗口的宽度
int height, //绘图窗口的高度
int flag=NULL //绘图窗口的样式,默认为NULL,
);
flag的值还可以为:
值 | 含义 |
---|---|
EX_DBLCLKS | 在绘图窗口中支持鼠标双击事件。 |
EX_NOCLOSE | 禁用绘图窗口的关闭按钮。 |
EX_NOMINIMIZE | 禁用绘图窗口的最小化按钮。 |
EX_SHOWCONSOLE | 显示控制台窗口。 |
简单句两个例子,其他同理:
创建一个尺寸为 640x480 的绘图窗口:
initgraph(640, 480);
创建一个禁用绘图窗口的关闭按钮并且尺寸为 640x480 的绘图窗口:
initgraph(640, 480,EX_NOCLOSE);
closegraph函数
用于关闭绘图窗口void closegraph();
1.3窗口坐标
坐标轴及原点可按如图理解:
2、设置图形窗口属性
2.1颜色设置
setbkcolo
void setbkcolo(COLORREF color);
注:在设置背景颜色后并不会改变现有的背景色,只是改变了背景色的值,之后再执行绘图语句,例如outtextxy,才会使用新设置的背景色值。
函数()中的值就是各种颜色对应的英文,在VS中可以右键—跳转到定义查看,以setbkcolo(RED)
为例,右键RED跳转,可以看到各种颜色的值。
RGB
COLORREF RGB(
BYTE byRed, // 颜色的红色部分
BYTE byGreen, // 颜色的绿色部分
BYTE byBlue // 颜色的蓝色部分
);
使用三原色进行调光,原理同画图中的调色板,可以找到喜欢的颜色把三原色的数字输入,注意使用RGB时也要在外面加setbkcolor(),例:
setbkcolor(RGB(200,100,100));
cleardevice 刷新
void cleardevice();
使用当前别景色清空绘图设备,刷新颜色。
3、使用EasyX实现基本绘图功能
3.1 line 画线
void line(
int x1, int y1, int x2, int y2,
);
在(x1,y1)和(x2,y2)两点间画一条线段。
3.1 circle 画圆
void circle(
int x, int y, int radius
);
以坐标(x,y)为圆心,画一个半径为radius的圆
3.2 rectangle 画矩形
void rectangle(
int left, int top, int right, int bottom
);
确定举行的左上角和右下角坐标,画一个矩形
3.3 setfillcolor 填充颜色
void setfillcolor(COLORREF color);
填充圆
- 带线:
fillcircle(int x, int y, int r);
- 不带线:
solidcircle(int x, int y, int r);
填充矩形
-
带线:
fillrectangle(int x1, int y1, int x2, int y2);
-
不带线:
solidrectangle(int x1, int y1, int x2, int y2);
代码举例:
int main()
{
initgraph(700, 550); //初始化图形界面尺寸
setfillcolor(LIGHTBLUE); //设置填充颜色
fillcircle(150, 150, 50); //画一个带线的圆
solidcircle(300, 150, 50); //画一个不带线的圆
fillrectangle(150, 300, 280, 450); //画一个带线的矩形
solidrectangle(150, 300, 280, 450); //画一个不带线的矩形
while (1); //防止图形化窗口一闪而过
closegraph(); //关闭窗口
return 0;
}
效果如图:
4、使用EasyX实现贴图功能
4.1 原样贴图
putimage 绘制图像
void putimage(
int dstX, // 绘制位置的 x 坐标
int dstY, // 绘制位置的 y 坐标
IMAGE *pSrcImg, // 要绘制的 IMAGE 对象指针
DWORD dwRop = SRCCOPY // 三元光栅操作码
);
void putimage(
int dstX, // 绘制位置的 x 坐标
int dstY, // 绘制位置的 y 坐标
int dstWidth, // 绘制的宽度
int dstHeight, // 绘制的高度
IMAGE *pSrcImg, // 要绘制的 IMAGE 对象指针
int srcX, // 绘制内容在 IMAGE 对象中的左上角 x 坐标
int srcY, // 绘制内容在 IMAGE 对象中的左上角 y 坐标
DWORD dwRop = SRCCOPY // 三元光栅操作码
);
如果要实现简单的贴图只需要写putimage(0,0,&img);
即在坐标(0,0)的位置绘制img图像,结合下文更清晰。
loadimage 加载图像
loadimage(IMAGE* img,URL);//IMAGE是一种图像对象
其中,IMAGE是一种图像对象,可以参考IMAGE,URL是想要贴上的图片的相对位置,注意将图片放到源文件的路径下,如下代码中,"./Source/1.jpg"就是源文件同路径下的Source文件夹下的文件名叫做1.jpg的图片。
代码实例:
int main()
{
initgraph(700, 600);
int a = 1;
IMAGE img;
loadimage(&img, "./Source/1.jpg");
putimage(0, 0, &img);
while (1);
closegraph();
return 0;
}
效果如下:
但是使用上述方法贴图效果无法做到合适窗口的尺寸,因此有下面的方法来进行缩放
loadimage(IMAGE* img,URL,int width,int height);
代码实例(将上面的代码中的loading函数增加两个参数即可,其余不变)
int main()
{
initgraph(700, 600);
int a = 1;
IMAGE img;
loadimage(&img, "./Source/1.jpg",700,600);
putimage(0, 0, &img);
while (1);
closegraph();
return 0;
}
效果如下:
4.2 透明贴图
-
通过图像的二进制运算达到去背景的效果
-
认识素材
- 掩码图
- 背景图
-
三元光栅操作码(仅介绍用得上的其中两个,其余可以参考putimage和Ternary raster operations)
- SRCAND 目标图像 = 目标图像 AND 源图像 贴掩码图
- SRCPAINT 目标图像 = 目标图像 OR 源图像 贴背景图
-
实例:
int main() { initgraph(800, 600); int a = 1; IMAGE img; loadimage(&img, "./Source/1.jpg",1000,600); putimage(0, 0, &img); IMAGE pic[2];//创建一个IMAGE类型的数组 loadimage(&pic[0], "./Source/掩码图.png",400,400); loadimage(&pic[1], "./Source/背景图.png", 400, 400); putimage(150, 50, &pic[0],SRCAND); //先贴掩码图 putimage(150, 50, &pic[1],SRCPAINT); //再贴背景图 while (1); closegraph(); return 0; }
4.3双缓冲贴图
BeginBatchDraw 开始双缓冲
void BeginBatchDraw();
在一个图形化的物体移动过程中,如果直接打印,会出现明显的闪烁,如以下代码(可以实现一个圆从左到右的移动):
#include <graphics.h>
int main()
{
initgraph(640,480);
setlinecolor(WHITE);
setfillcolor(RED);
for(int i=50; i<600; i++)
{
cleardevice();
circle(i, 100, 40);
floodfill(i, 100, WHITE);
Sleep(10);
}
closegraph();
}
要解决这个问题就可以使用双缓冲贴图,简单来说,开始双缓冲后,绘画操作会暂时不输出到绘画窗口上,知道执行FlusBatchDraw函数或EndBatchDraw函数才将之前的绘图输出,这两个函数见下文。
EndBatchDraw 结束双缓冲
void EndBatchDraw();
当需要结束双缓存贴图并执行指定区域内未完成的绘制任务时,可参照以下:
void EndBatchDraw(
int left, //指定区域左边的x坐标
int top, //指定区域上边的y左边
int right, //指定区域右边的x坐标
int bottom //指定区域下边的y坐标
);
FlushBatchDraw 显示一帧
void FlushBatchDraw();
当需要执行指定区域内未完成的绘制任务时,可参考以下:
void FlushBatchDraw(
int left, //指定区域左边的x坐标
int top, //指定区域上边的y左边
int right, //指定区域右边的x坐标
int bottom //指定区域下边的y坐标
);
使用以上的三个函数再将上面的圆的移动的代码进行优化,如下:
#include <graphics.h>
int main()
{
initgraph(640,480);
BeginBatchDraw(); //开始双缓冲贴图
setlinecolor(WHITE);
setfillcolor(RED);
for(int i=50; i<600; i++)
{
cleardevice();
circle(i, 100, 40);
floodfill(i, 100, WHITE);
FlushBatchDraw(); //绘画出当前帧的图案
Sleep(10);
}
EndBatchDraw(); //双缓冲贴图结束
closegraph();
}
5、实现EasyX按键件交互功能
阻塞按键交互
简单理解就是在程序运行过程中有输入等交互环节的,会在中途暂停程序直到输入完成互动再继续
比如在一个小程序中有一个可以通过上下左右控制运动的小球,按下→键,小球向右动了一下停下,等待下面的指令,直到再按下一个按键才继续,这就是一个阻塞。
非阻塞按键交互
简单理解是在一个程序中按键输入等交互动作不中断程序的运行
我们可以使用conic.h
头文件下的getch()
函数来读取键盘的内容,getch()函数(详情可见getch() 函数的简单使用)
通过使用getch()和EasyX再加上打印图形的配合使用,可以达到一个通过键盘输入值控制窗口物体移动的效果。除了使用getch()函数,还可以使用Win 32 API下的GetAsyncKeyState函数来获取键盘键值达到键盘控制的效果,详情可以参考贪吃蛇小游戏中二、10下的内容。
6、在EasyX中进行鼠标操作
ExMessage 保存鼠标信息
ExMessage是一个结构体,用来保存鼠标信息,定义如下:
struct ExMessage
{
USHORT message; // 消息标识
union
{
// 鼠标消息的数据
struct
{
bool ctrl :1; // Ctrl 键是否按下
bool shift :1; // Shift 键是否按下
bool lbutton :1; // 鼠标左键是否按下
bool mbutton :1; // 鼠标中键是否按下
bool rbutton :1; // 鼠标右键
short x; // 鼠标的 x 坐标
short y; // 鼠标的 y 坐标
short wheel; // 鼠标滚轮滚动值,为 120 的倍数
};
// 按键消息的数据
struct
{
BYTE vkcode; // 按键的虚拟键码
BYTE scancode; // 按键的扫描码(依赖于 OEM)
bool extended :1; // 按键是否是扩展键
bool prevdown :1; // 按键的前一个状态是否按下
};
// 字符消息的数据
TCHAR ch;
// 窗口消息的数据
struct
{
WPARAM wParam;
LPARAM lParam;
};
};
};
PeekMessage 获取鼠标信息
bool peekmessage(ExMessage *msg, BYTE filter = -1, bool removemsg = true);
msg是指向ExMessage的指针,用来保存获取到的信息
filter指定获取的信息范围,默认-1获取所有类别的消息,还可以用以下值:
标志 描述 EX_MOUSE 鼠标消息。 EX_KEY 按键消息。 EX_CHAR 字符消息。 EX_WINDOW 窗口消息。 removemsg:在peekmessage处理完消息后,是否将其从消息队列中移除
如果获取到了消息,则返回true,否则返回false
案例:
#include <graphics.h>
int main()
{
initgraph(800, 800);
ExMessage msg;
while (1) {
while (peekmessage(&msg)) {
switch (msg.message) {
case WM_LBUTTONDOWN: {
circle(msg.x, msg.y, 10);
break;
}
//按下左键,在鼠标按下的位置画圆
case WM_RBUTTONDOWN: {
rectangle(msg.x - 5, msg.y - 5, msg.x + 5, msg.y + 5);
break;
//按下右键,在鼠标按下的位置画方
}
}
}
}
return 0;
}
OW | 窗口消息。 |
- removemsg:在peekmessage处理完消息后,是否将其从消息队列中移除
如果获取到了消息,则返回true,否则返回false
案例:
#include <graphics.h>
int main()
{
initgraph(800, 800);
ExMessage msg;
while (1) {
while (peekmessage(&msg)) {
switch (msg.message) {
case WM_LBUTTONDOWN: {
circle(msg.x, msg.y, 10);
break;
}
//按下左键,在鼠标按下的位置画圆
case WM_RBUTTONDOWN: {
rectangle(msg.x - 5, msg.y - 5, msg.x + 5, msg.y + 5);
break;
//按下右键,在鼠标按下的位置画方
}
}
}
}
return 0;
}
标签:教程,窗口,函数,int,IMAGE,EasyX,msg,图形库,鼠标
From: https://blog.csdn.net/TTKunn/article/details/141072177