easyx图形库

目录

1、绘制简单的图形化窗口

2、设置窗口属性

2.1 颜色设置

2.2 刷新

3、基本绘图函数

3.1 绘制直线

3.2 绘制圆

3.3 绘制矩形

4、贴图

4.1 原样贴图

4.1.1 IMAGE变量去表示图片

4.1.2 加载图片 

4.1.3 显示图片

4.2 透明贴图

4.2.1 认识素材

4.3 png贴图

5、按键交互

5.1 小球自由移动

5.2 按键控制小球

6、鼠标交互

1、绘制简单的图形化窗口

在之前,我们一运行程序会显示出来的黑框框是控制台窗口,现在,我们要绘制的是另一个窗口,即图形化窗口

首先需要包含头文件,这里有两个头文件可以使用,任意选择一个即可

1. graphics.h : 包含已经被淘汰的的函数

2. easyx.h : 只包含最新的函数

创建图形化窗口只需要两个函数:

1. 打开图形化窗口:initgraph(int x, int y, int style)

2. 关闭图形化窗口:closegraph()

在initgraph中,x和y是要创建的图形化窗口的大小,第三个参数是创建方式,若传入1则表示创建图形化窗口的同时还要创建控制台窗口,若不传或者传入的不是1,则表示只创建图形化窗口

打开完图形化窗口后一定记得要关闭图形化窗口 

void test_graph()
{
	initgraph(800, 600);
	while (1); // 为了防止一闪而过
	closegraph();
}

图形化窗口的坐标:

2、设置窗口属性

2.1 颜色设置

setbkcolor(颜色)

其中这面的颜色有两种形式传入

1. 颜色宏:既使用颜色英语的大写,这是编译器定义好的,可以在编译器内查看

即可查看可以使用的颜色

2. RGB配置

在电脑自带的画图当中,就可以找到一种颜色对应的RGB

所以我们此时可以写出这样的代码

void test_graph()
{
	initgraph(800, 600);
	setbkcolor(RED);
	while (1); // 为了防止一闪而过
	closegraph();
}

 但运行起来后会发现,图形化窗口仍然是黑色的,并没有变成设置的红色,这是为什么呢?

因为我们没有刷新

2.2 刷新

当我们设置完图形化窗口的颜色后,还需要刷新才能看到我们设置的颜色,否则仍然是initgraph打开的图形化窗口默认的黑色

void test_graph()
{
	initgraph(800, 600);
	setbkcolor(RED);
	cleardevice();
	while (1); // 为了防止一闪而过
	closegraph();
}

这样图形化窗口就变成了红色

3、基本绘图函数

3.1 绘制直线

line(int x, int y, int xx, int yy)

第一、二个参数是起点的坐标,第三、四个参数是终点的坐标

可以使用setlinecolor(颜色)来改变线的颜色

3.2 绘制圆

circle(int x, int y, int r)

第一、二个参数是圆心的坐标,第三个参数是半径

使用circle画出的圆是带线的,带线是指带边框线,并且圆内部的颜色是和图形化窗口的背景颜色相同的,若想要填充圆的颜色,需要使用下面的函数

填充圆,设置填充颜色:setfillcolor(颜色)

带线:fillcircle(int x, int y, int r)

不带线:solidcircle(int x, int y, int r)

注意:要填充圆的颜色只能使用下面这两个函数来画圆,不能使用circle

3.3 绘制矩形

rectangle(int x, int y, int xx, int yy)

第一、二个参数是矩形左上角的点的坐标,第三、四个参数是矩形右下角的点的坐标

填充矩形,设置填充颜色:setfillcolor(颜色)

带线:fillrectangle(int x, int y, int xx, int yy)

不带线:solidrectangle(int x, int y, int xx, int yy)

这里的规则与绘制圆中的规则是类似的,就不过多赘述了

void test_graph()
{
	initgraph(800, 600);
	setbkcolor(RED);
	cleardevice();
	line(0, 0, 800, 600);
	setfillcolor(BLUE);
	fillcircle(100, 100, 50);
	solidrectangle(200, 200, 300, 300);
	while (1); // 为了防止一闪而过
	closegraph();
}

我们可以使用刚刚学习的知识来绘制一个棋盘

void draw()
{
	initgraph(400, 400);
	for (int i = 0; i <= 400; i += 20)
	{
		line(0, i, 400, i);
		line(i, 0, i, 400);
	}
	while (1);
	closegraph();
}

此时画出来的是黑底白线,也可以修饰一下

void draw()
{
	initgraph(400, 400);
	setbkcolor(BLUE);
	cleardevice();
	setlinecolor(BLACK);
	for (int i = 0; i <= 400; i += 20)
	{
		line(0, i, 400, i);
		line(i, 0, i, 400);
	}
	while (1);
	closegraph();
}

此时就变成了蓝底黑线了

4、贴图

4.1 原样贴图

原样贴图就是将一张图片直接原封不动的贴到图形化窗口中

要使用原样贴图有三个步骤:

4.1.1 IMAGE变量去表示图片

图片是一个IMAGE类型的变量,类似于1是一个int类型的变量,所以可以int a = 1,用a来存储1

所以需要先创建一个IMAGE变量来存储图片

4.1.2 加载图片 

使用函数loadimage(IMAGE* img, URL, int width, int height)

第一个参数是指向图片的指针,传参时传的就是图片的地址,第二个参数是图片所在的路径(可以用相对路径,也可以用绝对路径),第三、四个参数可传可不传,不传是就是将图片原本的大小贴到图形化窗口中,若传了则可以修改图片在图形化窗口上的大小

4.1.3 显示图片

putimage(int x, int y, IMAGE* img)

第一、二个参数是图片左上角的坐标,第三个参数是指向图片的指针

此时演示一下。通常,我们会在.cpp的路径下创建一个文件夹,然后将相关资源放到这个文件夹里面,这里我们就可以将图片放到这个文件夹里面

编译器还要修改一下属性,修改成“使用多字节字符集”

void test_maps()
{
	initgraph(800, 600);
	IMAGE img;
	loadimage(&img, "./Res/qiqi.jpg");
	putimage(0, 0, &img);
	while (1); // 为了防止一闪而过
	closegraph();
}

此时会发现,图片太大了,设置的这个图形化窗口太小了,无法完全显示,所以我们可以设置图片的大小。缩放是为了解决图片大小与窗口大小不一致

void test_maps()
{
	initgraph(800, 600);
	IMAGE img;
	loadimage(&img, "./Res/qiqi.jpg", 800, 600);
	putimage(0, 0, &img);
	while (1); // 为了防止一闪而过
	closegraph();
}

此时就可以将图片完全显示了

4.2 透明贴图

当我们需要将两张图片放到同一个图形化窗口中时,其中一张作为背景图,另一张只需要一部分,此时会发现只需要一部分的那一张图片的一部分会遮挡住背景图

让第一张作为背景图,第二种放在其中

void test_maps()
{
	initgraph(800, 600);
	IMAGE img;
	loadimage(&img, "./Res/qiqi.jpg", 800, 600);
	putimage(0, 0, &img);
	IMAGE hz;
	loadimage(&hz, "./Res/hz.jpg",100,100);
	putimage(100, 100, &hz);
	while (1); // 为了防止一闪而过
	closegraph();
}

 

此时第二张图片的背景图也会影响第一张图片,那要如何才能去除第二张图片的背景图呢?

4.2.1 认识素材

首先,我们需要将第二章图片分别做成掩码图和背景图,利用PS

掩码图:想要显示的部分弄成黑色,不想显示的部分弄成白色

背景图:想要显示的部分不动,不想显示的部分弄成黑色

弄好了掩码图和背景图后,按照特定步骤贴图即可

SRCAND  贴掩码图

SRCPAINT  贴背景图   

要先贴掩码图,再贴背景图

void test_maps()
{
	initgraph(800, 600);
	IMAGE img;
	loadimage(&img, "./Res/qiqi.jpg", 800, 600);
	putimage(0, 0, &img);
	IMAGE test[2];
	loadimage(test + 0, "./Res/ym.jpg", 100, 100);
	loadimage(test + 1, "./Res/bj.jpg", 100, 100);
	putimage(100, 100, test + 0, SRCAND);
	putimage(100, 100, test + 1, SRCPAINT);
	while (1); // 为了防止一闪而过
	closegraph();
}

此时运行结果就是正常的

4.3 png贴图

#pragma once
#include<easyx.h>
// 把像素的颜色拆解出来
typedef struct _ARGB
{
	byte a;
	byte r;
	byte g;
	byte b;
}ARGB;
// 颜色拆解
ARGB color2Argb(DWORD c)
{
	ARGB res;
	res.r = (byte)c;
	res.g = (byte)(c >> 8);
	res.b = (byte)(c >> 16);
	res.a = (byte)(c >> 24);
	return res;
}
DWORD argb2Color(ARGB c)
{
	DWORD t = RGB(c.r, c.g, c.b);
	return ((DWORD)c.a) << 24 | t;
}
// 把彩色图转成黑白图
void toGray(IMAGE* src)
{
	DWORD* psrc = GetImageBuffer(src);
	for (int i = 0; i < src->getwidth() * src->getheight(); i++)
	{
		// 获取每一个像素点的颜色值
		ARGB t = color2Argb(psrc[i]);
		// 灰度圈,求三个或者四个颜色值的均值
		byte arv = (t.r + t.g + t.b) / 3;
		ARGB res = { t.a,arv,arv,arv };
		psrc[i] = argb2Color(res);
	}
}
// @png透明贴图
void drawImg(int x, int y, IMAGE* src)
{
	// 变量初始化
	DWORD* pwin = GetImageBuffer();
	DWORD* psrc = GetImageBuffer(src);
	int win_w = getwidth();
	int win_h = getheight();
	int src_w = src->getwidth();
	int src_h = src->getheight();

	// 计算贴图的实际长度
	int real_w = (x + src_w > win_w) ? win_w - x : src_w;       // 处理超出右边界
	int real_h = (y + src_h > win_h) ? win_h - y : src_h;       // 处理超出下边界
	if (x < 0) { psrc += -x;           real_w -= -x; x = 0; }   // 处理超出左边界
	if (y < 0) { psrc += (src_w + -y); real_h -= -y; y = 0; }   // 处理超出上边界

	// 修正贴图起始位置
	pwin += (win_w * y + x);

	// 实现透明贴图
	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix] >> 24);// 计算透明通道的值[0,256) 0为完全透明 255为完全不透明
			if (a > 100) pwin[ix] = psrc[ix];
		}
		// 换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}

5、按键交互

案件交互分为阻塞按键交互和非阻塞按键交互

阻塞按键交互:不按按键时图片不会动

C语言中很多函数都是阻塞型的,如scanf,没有输入时程序就停止在哪里了

非阻塞按键交互:不按按键时图片可以动

接下来我们来实现两个案例

5.1 小球自由移动

struct Ball // 球的结构体
{
	int x;   // 球的横坐标
	int y;   // 球的纵坐标
	int r;   // 球的半径
	int dx;  // 球一次向x轴正方向移动的距离
	int dy;  // 球一次向y轴正方向移动的距离
};
struct Ball ball = { 400,400,15,5,-4 }; // 定义一个球
void DrawBall(struct Ball ball) // 画出球的函数
{
	setfillcolor(RED);
	solidcircle(ball.x, ball.y, ball.r);
}
void MoveBall() // 控制球移动的函数
{
	ball.x += ball.dx;
	ball.y += ball.dy;
}
int main()
{
	initgraph(800, 800);
	while (1)
	{
		DrawBall(ball); // 首先画出一个球
		MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		Sleep(20); // 延时20ms
	}
	return 0;
}

但此时小球移动会有轨迹存在,所以在开始画出更新完状态之后的小球时,要先刷新

int main()
{
	initgraph(800, 800);
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		Sleep(20); // 延时20ms
	}
	return 0;
}

此时小球只会往一个方向移动,所以我们需要控制一下小球在碰撞到图形化窗口边界时,要反弹

void MoveBall() // 控制球移动的函数
{
	if (ball.x - ball.r <= 0 || ball.x + ball.r >= 800) { ball.dx = -ball.dx; }
	if (ball.y - ball.r <= 0 || ball.y + ball.r >= 800) { ball.dy = -ball.dy; }
	ball.x += ball.dx;
	ball.y += ball.dy;
}

5.2 按键控制小球

当用户按下按键时,也会产生一个值,可以用_getch()来获取,头文件是<conio.h>,然后根据这个值,来对小球做出处理

struct Ball // 球的结构体
{
	int x;   // 球的横坐标
	int y;   // 球的纵坐标
	int r;   // 球的半径
	int dx;  // 球一次向x轴正方向移动的距离
	int dy;  // 球一次向y轴正方向移动的距离
};
struct Ball ball = { 400,400,15,5,-4 }; // 定义一个球
void DrawBall(struct Ball ball) // 画出球的函数
{
	setfillcolor(RED);
	solidcircle(ball.x, ball.y, ball.r);
}
void MoveBall() // 控制球移动的函数
{
	if (ball.x - ball.r <= 0 || ball.x + ball.r >= 800) { ball.dx = -ball.dx; }
	if (ball.y - ball.r <= 0 || ball.y + ball.r >= 800) { ball.dy = -ball.dy; }
	ball.x += ball.dx;
	ball.y += ball.dy;
}
struct Ball myball = { 500,500,15,5,5 }; // 定义一个自己用按键控制的球,不调用MoveBall,而是自己用按键控制小球移动
void KeyDown() // 控制自己用按键控制的球的函数,通过接收按下的按键,来对小球的参数进行修改
{
	int userKey = _getch();
	switch (userKey)
	{
	case 'w':
	case 'W':
	case '72': // 键盘上的方向键
		myball.y -= 5;
		break;
	case 's':
	case 'S':
	case '80': // 键盘上的方向键
		myball.y += 5;
		break;
	case 'a':
	case 'A':
	case '75': // 键盘上的方向键
		myball.x -= 5;
		break;
	case 'd':
	case 'D':
	case '77': // 键盘上的方向键
		myball.x += 5;
		break;
	}
}
void test_myball()
{
	initgraph(800, 800);
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		DrawBall(myball);
		MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		KeyDown();
		Sleep(20); // 延时20ms
	}
    closegraph();
}
int main()
{
	test_myball();
	return 0;
}

此时会发现,自己移动的小球也不动了,只有当我们按了按键让按键控制的球动了之后,自己移动的小球也会移动,一旦我们没按按键,自己移动的小球又停了

这是因为KeyDown函数中的_getch函数是阻塞型函数,当我们没有按按键时,程序会停止在这一步,循环无法继续,所以自己动的小球也不会继续走,这时候我们可以使用_kbhit()函数来判断我们是否按了按键,当我们按了按键,才会去走KeyDown

void test_myball()
{
	initgraph(800, 800);
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		DrawBall(myball);
		MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		if(_kbhit())
			KeyDown();
		Sleep(20); // 延时20ms
	}
    closegraph();
}

此时就正常了

玩过之后,会发现自己移动的小球移动起来不是很流畅,这是因为Sleep也是阻塞的,通常会使用定时器去控制自由移动的东西,而不使用Sleep

#include<iostream>
#include<graphics.h>
#include<conio.h>
#include<time.h>
using namespace std;
struct Ball // 球的结构体
{
	int x;   // 球的横坐标
	int y;   // 球的纵坐标
	int r;   // 球的半径
	int dx;  // 球一次向x轴正方向移动的距离
	int dy;  // 球一次向y轴正方向移动的距离
};
struct Ball ball = { 400,400,15,5,-4 }; // 定义一个球
void DrawBall(struct Ball ball) // 画出球的函数
{
	setfillcolor(RED);
	solidcircle(ball.x, ball.y, ball.r);
}
void MoveBall() // 控制球移动的函数
{
	if (ball.x - ball.r <= 0 || ball.x + ball.r >= 800) { ball.dx = -ball.dx; }
	if (ball.y - ball.r <= 0 || ball.y + ball.r >= 800) { ball.dy = -ball.dy; }
	ball.x += ball.dx;
	ball.y += ball.dy;
}
struct Ball myball = { 500,500,15,5,5 }; // 定义一个自己用按键控制的球,不调用MoveBall,而是自己用按键控制小球移动
void KeyDown() // 控制自己用按键控制的球的函数,通过接收按下的按键,来对小球的参数进行修改
{
	int userKey = _getch();
	switch (userKey)
	{
	case 'w':
	case 'W':
	case '72': // 键盘上的方向键
		myball.y -= 5;
		break;
	case 's':
	case 'S':
	case '80': // 键盘上的方向键
		myball.y += 5;
		break;
	case 'a':
	case 'A':
	case '75': // 键盘上的方向键
		myball.x -= 5;
		break;
	case 'd':
	case 'D':
	case '77': // 键盘上的方向键
		myball.x += 5;
		break;
	}
}
int Timer(int duration, int id)
{
	static int startTime[10]; // 创建10个定时器
	int endTime = clock();
	if (endTime - startTime[id] > duration)
	{
		startTime[id] = endTime;
		return 1;
	}
	return 0;
}
void test_myball()
{
	initgraph(800, 800);
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		DrawBall(myball);
		if(Timer(20,0))
			MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		if(_kbhit())
			KeyDown();
		// Sleep(20); // 延时20ms
	}
	closegraph();
}
int main()
{
	test_myball();
	return 0;
}

定时器的原理就是使用静态数组,因为静态变量只会初始化一次,所以每当函数调用时,数组中储存的还是上一次的值,并且静态数组不需要初始化,因为静态变量会被自动初始化为0。定时器的第一个参数是多少毫秒就需要让自己移动的小球移动一次,第二个参数是使用下标为id的定时器。clock()函数是基类程序运行到这里用了多长的时间,头文件是time.h。当程序运行到这里的时间减去选中的那个定时器的值大于给定的时间duration时,就表示自己移动的小球需要移动了,将下标为id的那个定时器的值改成clock()的结果,并返回1,表示需要移动。

为了不让用按键控制的小球一闪一闪的,还可以使用双缓冲绘图

开始双缓冲:BeginBatchDraw()

结束双缓冲:EndBatchDraw()

显示一帧:FlushBatchDraw()

void test_myball()
{
	initgraph(800, 800);
	BeginBatchDraw();
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		DrawBall(myball);
		if(Timer(20,0))
			MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		if(_kbhit())
			KeyDown();
		// Sleep(20); // 延时20ms
		FlushBatchDraw();
	}
	EndBatchDraw();
	closegraph();
}

因为_getch()是阻塞型的函数,所以在移动自己控制的小球时,会一卡一卡的,为了让小球更流畅,可以使用非阻塞型函数来接收按键的值
 

struct Ball // 球的结构体
{
	int x;   // 球的横坐标
	int y;   // 球的纵坐标
	int r;   // 球的半径
	int dx;  // 球一次向x轴正方向移动的距离
	int dy;  // 球一次向y轴正方向移动的距离
};
struct Ball ball = { 400,400,15,5,-4 }; // 定义一个球
void DrawBall(struct Ball ball) // 画出球的函数
{
	setfillcolor(RED);
	solidcircle(ball.x, ball.y, ball.r);
}
void MoveBall() // 控制球移动的函数
{
	if (ball.x - ball.r <= 0 || ball.x + ball.r >= 800) { ball.dx = -ball.dx; }
	if (ball.y - ball.r <= 0 || ball.y + ball.r >= 800) { ball.dy = -ball.dy; }
	ball.x += ball.dx;
	ball.y += ball.dy;
}
struct Ball myball = { 500,500,15,5,5 }; // 定义一个自己用按键控制的球,不调用MoveBall,而是自己用按键控制小球移动
void KeyDown() // 控制自己用按键控制的球的函数,通过接收按下的按键,来对小球的参数进行修改
{
	int userKey = _getch();
	switch (userKey)
	{
	case 'w':
	case 'W':
	case '72': // 键盘上的方向键
		myball.y -= 5;
		break;
	case 's':
	case 'S':
	case '80': // 键盘上的方向键
		myball.y += 5;
		break;
	case 'a':
	case 'A':
	case '75': // 键盘上的方向键
		myball.x -= 5;
		break;
	case 'd':
	case 'D':
	case '77': // 键盘上的方向键
		myball.x += 5;
		break;
	}
}
void KeyDown2()
{
	if (GetAsyncKeyState(VK_UP))    { myball.y -= 5; }
	if (GetAsyncKeyState(VK_DOWN))  { myball.y += 5; }
	if (GetAsyncKeyState(VK_LEFT))  { myball.x -= 5; }
	if (GetAsyncKeyState(VK_RIGHT)) { myball.x += 5; }
}
int Timer(int duration, int id)
{
	static int startTime[10]; // 创建10个定时器
	int endTime = clock();
	if (endTime - startTime[id] > duration)
	{
		startTime[id] = endTime;
		return 1;
	}
	return 0;
}
void test_myball()
{
	initgraph(800, 800);
	BeginBatchDraw();
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		DrawBall(myball);
		if(Timer(20,0))
			MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		/*if(_kbhit())
			KeyDown();*/
		KeyDown2();
		// Sleep(20); // 延时20ms
		FlushBatchDraw();
	}
	EndBatchDraw();
	closegraph();
}
int main()
{
	test_myball();
	return 0;
}

用KeyDown2来替代KeyDown,并且因为是非阻塞型的,所以可以不需要if(_kbhit())来判断了

但此时自己控制的小球会移动的非常快,为了让小球速度正常,可以使用定时器

void test_myball()
{
	initgraph(800, 800);
	BeginBatchDraw();
	while (1)
	{
		cleardevice(); // 刷新
		DrawBall(ball); // 首先画出一个球
		DrawBall(myball);
		if(Timer(20,0))
			MoveBall(); // 移动完成后更新了小球的状态,等待下一次进入循环后打印出新状态的小球
		/*if(_kbhit())
			KeyDown();*/
		if(Timer(20,1))
			KeyDown2();
		// Sleep(20); // 延时20ms
		FlushBatchDraw();
	}
	EndBatchDraw();
	closegraph();
}

此时使用的是下标为1的定时器

6、鼠标交互

当用户点击鼠标的按键时,就会产生一个值,类型是ExMessage,称为鼠标消息,鼠标消息实际上是一个结构体

获取鼠标消息peekmessage(&变量)

讨论鼠标消息 

msg.message:区分鼠标消息的类型,用户按下的值存储在结构体变量msg的message中

msg.x   msg.y: 鼠标当前的坐标

 

void test_mouse()
{
	initgraph(800, 800);
	ExMessage msg;
	// 按左键画圆,按右键画矩形
	while (1)
	{
		while (peekmessage(&msg))
		{
			switch(msg.message) // 根据用户按下的按键,判断在当前鼠标位置画哪一个
			{
			case WM_LBUTTONDOWN:
				circle(msg.x, msg.y, 30);
				break;
			case WM_RBUTTONDOWN:
				rectangle(msg.x - 10, msg.y - 10, msg.x + 10, msg.y + 10);
				break;
			}
		}
	}
	closegraph();
}
int main()
{
	test_mouse();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/778566.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用块的网络 VGG

一、AlexNet与VGG 1、深度学习追求更深更大&#xff0c;使用VGG将卷积层组合为块 2、VGG块&#xff1a;3*3卷积&#xff08;pad1&#xff0c;n层&#xff0c;m通道&#xff09;、2*2最大池化层 二、VGG架构 1、多个VGG块后接全连接层 2、不同次数的重复块得到不同的架构&a…

go语言day10 接口interface 类型断言 type关键字

接口&#xff1a; 空接口类型&#xff1a; 要实现一个接口&#xff0c;就要实现该接口中的所有方法。因为空接口中没有方法&#xff0c;所以自然所有类型都实现了空接口。那么就可以使用空接口类型变量去接受所有类型对象。 类比java&#xff0c;有点像Object类型的概念&#x…

使用Docker、Docker-compose部署单机版达梦数据库(DM8)

安装前准备 Linux Centos7安装&#xff1a;https://blog.csdn.net/andyLyysh/article/details/127248551?spm1001.2014.3001.5502 Docker、Docker-compose安装&#xff1a;https://blog.csdn.net/andyLyysh/article/details/126738190?spm1001.2014.3001.5502 下载DM8镜像 …

数据按月分表

当数据量过大&#xff0c;从数据层面可以按月分表&#xff0c;报表查询时可以根据&#xff0c;查询时间来计算查询的年月&#xff0c;查询对应的表 1、按月分表&#xff1a; 存储过程SP_BRANCH_TABLE_TEST 以下存储过程分表&#xff0c;加了索引可以方便后续查询 USE [DASHBOAR…

三分钟内了解卷轴模式

在数字化时代的浪潮中&#xff0c;卷轴商业模式巧妙地将积分体系、互动任务、社交裂变、虚拟经济体系以及个性化成长路径等多元要素融为一体。 积分体系&#xff1a;激发参与动力的源泉 卷轴商业模式的核心在于其精心构建的积分系统。新用户踏入平台&#xff0c;即获赠一笔启…

Windows上Docker的安装与初体验

Docker Desktop下载地址 国内下载地址 一、基本使用 1. 运行官方体验镜像 docker run -d -p 80:80 docker/getting-started执行成功 停止体验服务 docker stop docker/getting-started删除体验镜像 docker rmi docker/getting-started2. 修改docker镜像的存储位置 3. …

vofa+:一款超级好用的可视化串口调试软件

目录 一、软件配置 1、先配置好usart1串口 2、重定向printf: 3&#xff0c;勾选魔术棒中的LIB 二、vofa的使用 1、RawData模式 2、FireWater 一、软件配置 1、先配置好usart1串口 2、重定向printf: 在 stm32f4xx_hal.c中添加&#xff1a; #include <stdio.h> e…

【nvm管理nodejs版本,切换node指定版本】

nvm管理nodejs版本 nvm管理nodejs版本主要功能使用 nvm nvm管理nodejs版本 nvm&#xff08;Node Version Manager&#xff09;顾名思义node版本管理器&#xff0c;无须去node管网下载很多node安装程序;用于管理多个 Node.js 版本的工具。它允许你在同一台机器上同时安装和管理…

文件上传(本地、OSS)

什么是文件上传&#xff1a;将文件上传到服务器。 文件上传-本地存储 前端 <template> <div><!-- 上传文件需要设置表单的提交方式为post&#xff0c;并设置enctype属性、表单项的type属性设置为file --><form action"http://localhost:8080/wedu/…

使用Python绘制和弦图

使用Python绘制和弦图 和弦图效果代码 和弦图 和弦图用于展示数据的多对多关系&#xff0c;适合用于社交网络、交通流量等领域的分析。 效果 代码 import pandas as pd import holoviews as hv from holoviews import opts hv.extension(bokeh)# 示例数据 data [(A, B, 2),…

价格预言机的使用总结(一):Chainlink篇

文章首发于公众号&#xff1a;Keegan小钢 前言 价格预言机已经成为了 DeFi 中不可获取的基础设施&#xff0c;很多 DeFi 应用都需要从价格预言机来获取稳定可信的价格数据&#xff0c;包括借贷协议 Compound、AAVE、Liquity &#xff0c;也包括衍生品交易所 dYdX、PERP 等等。…

vb.netcad二开自学笔记1:万里长征第一步Hello CAD!

已入门的朋友请绕行&#xff01; 今天开启自学vb.net 开发autocad&#xff0c;网上相关资料太少了、太老了。花钱买课吧&#xff0c;穷&#xff01;又舍不得&#xff0c;咬牙从小白开始摸索自学吧&#xff0c;虽然注定是踏上了一条艰苦之路&#xff0c;顺便作个自学笔记备忘!积…

网络安全领域国标分类汇总大全V1.0版:共计425份标准文档,全部可免费下载

《网络安全法》、《数据安全法》、《个人信息保护法》落地实施需要大量国家标准的支撑&#xff0c;博主耗时三周时间&#xff0c;吐血整理了从1999年至今相关的所有涉及安全的国家标准&#xff0c;梳理出《网络安全领域国标分类汇总大全V1.0版》&#xff0c;共计 425 项现行标准…

深度解析 Raft 分布式一致性协议

本文参考转载至&#xff1a;浅谈 Raft 分布式一致性协议&#xff5c;图解 Raft - 白泽来了 - 博客园 (cnblogs.com) 深度解析 Raft 分布式一致性协议 - 掘金 (juejin.cn) raft-zh_cn/raft-zh_cn.md at master maemual/raft-zh_cn (github.com) 本篇文章将模拟一个KV数据读写服…

ShardingSphere实战

ShardingSphere实战 文章目录 ShardingSphere实战分库分表实战建表建表sql利用存储过程建表Sharding-jdbc分库分表配置 基于业务的Sharding-key考虑订单id用户id分片策略订单id的设计与实现**设计思想**&#xff1a;设计思路&#xff1a; 具体分片策略实现测试数据插入商户商品…

【pyqt-实训训练】串口助手

串口助手 前言一、ui设计二、ui的控件命名三、ui转py使用类的方法【扩展】使用ui文件导入&#xff01;P7的小错误解决办法 总结 前言 我的惯例就是万物之始&#xff0c;拜见吾师&#x1f970;⇨pyqt串口合集 最开始的时候我想的是&#xff0c;学了那么久的pyqt&#xff0c;我…

进程的控制-孤儿进程和僵尸进程

孤儿进程 &#xff1a; 一个父进程退出&#xff0c;而它的一个或多个子进程还在运行&#xff0c;那么那些子进程将成为孤儿进程。孤儿进程将被 init 进程( 进程号为 1) 所收养&#xff0c;并由 init 进程对它们完成状态收集工作 为了释放子进程的占用的系统资源&#xff1a; …

VS code修改底部的行号的状态栏颜色

VSCode截图 相信很多小伙伴被底部的蓝色状态栏困扰很久了 处理的方式有两种&#xff1a; 1、隐藏状态栏 2、修改其背景颜色 第一种方法大伙都会&#xff0c;今天就使用第二种方法。 1、点击齿轮进入setting 2、我现在用的新版本&#xff0c;设置不是以前那种json格式展示&…

ubuntu系统盘扩容

目录 1 介绍 2 步骤 2.1 关闭虚拟机 2.2 编辑虚拟机设置 2.3 设置扩展大小 2.4 打开虚拟机 2.5 找到磁盘管理 2.6 扩展 1 介绍 本部分主要记述怎么给ubuntu系统盘扩展存储容量&#xff0c;整个过程相对简单&#xff0c;扩容方式轻松、容易。 2 步骤 2.1 关闭虚拟机 2…

尚庭公寓——数据库设计

1. 数据的关系 一对一&#xff0c;一对多&#xff08;多对一&#xff09;&#xff0c;多对多 2. 实体关系模型 实体关系模型常用ER图&#xff08;enity relationship graph&#xff09;表示&#xff1b; 矩形表示实体&#xff08;类似Java中的对象&#xff0c;如学生就是一…