C++结合EasyX写扫雷(new)

news2024/12/26 22:00:55

【游戏】C++结合EasyX写扫雷(时隔半年后重写)

  • 上一次写扫雷
  • 这一次
  • 实现思路
    • 设置全局变量
    • Grid类
    • Grid类的成员函数
    • 启动画面
    • 死循环监听鼠标事件
  • 全部代码
  • 其他

上一次写扫雷

大约半年之前的寒假期间,我接触了EasyX这个图形库,于是试着写了一个经典小游戏——扫雷
当时大概用了三四天时间,还发布了三篇博客来记录:
【小游戏】用C++结合EasyX制作扫雷1
【小游戏】用C++结合EasyX制作扫雷2
【小游戏】用C++结合EasyX制作扫雷3

这一次

基本上全都是自己重写,没怎么借鉴之前的代码(主要可能是因为看不懂之前自己写的代码了)

编写环境仍然是VS2022,记得把项目字符集改为多字符集

基本思路和之前差不多;引用的图片文件也是一样的(图片文件资源在GitHub储存库中有);另外就是添加了一点点花里胡哨的东西,比如说开始屏幕(Splash Screen)和从命令行传入参数(这个功能还有问题)进行设置等功能

写的过程中,感觉有很多东西忘记了,比如EasyX的一些基础;再就是感觉代码写得更有逻辑了(doge

仍然难免有一些Bug

实现思路

  • 设置几个全局变量
  • 定义Grid类
    • Grid的属性
    • 方法——show 用于显示格子
    • 方法——showMinesNumAround 通过EasyX在对应位置显示出格子周围的雷的数量
    • 方法——onLeftButtonClick 鼠标左键单击时做出的操作
    • 方法——onRightButtonClick 鼠标右键单击时做出的操作
    • 方法——findMinesAround 用遍历的方式找出格子周围雷的数量
  • splashScreen函数实现启动画面
  • main函数
    • 接受来自命令行的参数
    • 初始化画布
    • 加载图像文件
    • 布置雷盘
    • 死循环监测鼠标信息

设置全局变量

(每个变量的作用都在注释中)

// 默认常量
int gridSize = 40;									// 每个格子的大小(长和宽)
int lines = 5, rows = 5;							// 行数和列数
int width = rows * gridSize, height = lines * gridSize; // 窗口宽度和高度
int minesNum = 10;									// 雷的数量
int normalGridsNum = lines * rows - minesNum;		// 除了雷以外的格子数量
IMAGE grid, gridClicked, mine, gridFlag;			// 图像

Grid类

每个属性的作用在注释中都有。
有些成员函数在创建playGround后定义,因为playGround是Grid类型的。(详见全部代码)

// 格子类
class Grid {
public:
	int posX, posY; // 该格子所处的位置(单位:像素)
	bool isFlag = false, isClicked = false, isMine = false;
	int posLine, posRow; // 该格子所处的行和列位置(单位:格子)
	int minesNumAround = 0; // 该格子周围雷的数量
	
	void show(int posLine,int posRow) {
		//显示
		this->posLine = posLine;
		this->posRow = posRow;
		posX = (this->posRow - 1) * gridSize;
		posY = (this->posLine - 1) * gridSize;
		putimage(posX, posY, &grid);
	}
	void showMinesNumAround() {
		if (minesNumAround==0)
			return;
		else if (minesNumAround == 1)
			settextcolor(BLUE);
		else if (minesNumAround == 2)
			settextcolor(GREEN);
		else if (minesNumAround == 3)
			settextcolor(YELLOW);
		else if (minesNumAround == 4)
			settextcolor(RGB(255, 135, 35));
		else
			settextcolor(RED);
		char info = minesNumAround + 48;
		outtextxy(posX+int(gridSize*0.4), posY+int(gridSize*0.1), _T(info));
	}
	void onLeftButtonClick();
	void onRightButtonClick();
	void findMinesAround();
};

Grid类的成员函数

  • onLeftButtonClick函数:判断这个格子是否被左键单击过(通过Grid的属性isClicked),只有没被点击过才执行接下来的操作。点击后normalGridNum-1,isClicked设置为true(说明已经被左键单击过),然后找出周围雷的数量并显示,再把周围不是雷的格子翻开(让它们执行onLeftButtonClick函数)
  • onRightButtonClick函数:判断格子是否被点击(右键单击左键单击)过。如果有,就把isFlag设置为false(相当于取消旗子),然后设置图片为正常格子;如果没有,就把isFlag设置为true(插旗子),然后把图片设置为旗子的图片。
  • findMinesNum函数:如果这个格子自身不是雷,就遍历周围的八个格子,并以minesNumAround属性作为计数器,得出周围格子的数量。
/*定义Grid类的几个函数*/
// 鼠标左键点击
void Grid::onLeftButtonClick() {
	if (!isClicked) { // 如果没有被左键点击过
		isClicked = true;
		normalGridsNum--;
		putimage(posX, posY, &gridClicked);
		
		findMinesAround();		// 找雷数
		showMinesNumAround();	// 显示出来周围雷数

		//翻开周围(4个)不是雷的格子
		vector<vector<int>> minesPosAround = { {posLine - 1,posRow},{posLine,posRow - 1},{posLine,posRow + 1},{posLine + 1,posRow} };
		for (int i = 0; i < 4; i++) {
			if (minesPosAround[i][0] > 0 && minesPosAround[i][0] <= lines && minesPosAround[i][1] > 0 && minesPosAround[i][1] <= rows) {
				if (playGround[minesPosAround[i][0]][minesPosAround[i][1]].isMine == false) {
					playGround[minesPosAround[i][0]][minesPosAround[i][1]].onLeftButtonClick();
				}
			}
		}
	}
}
// 鼠标右键点击
void Grid::onRightButtonClick() {
	if (!isFlag&&!isClicked) { // 如果没有被右键点击过
		isFlag = true;
		putimage(posX, posY, &gridFlag);
	}
	else if(isFlag&&!isClicked) {
		isFlag = false;
		putimage(posX, posY, &grid);
	}
}
// 寻找周围8个(或5个)格子中雷的数量
void Grid::findMinesAround() {
	if (isMine) { // 如果该格子是雷,则返回-1
		return;
	}
	else { // 如果该格子不是雷,继续
		for (int i = posLine - 1; i < posLine + 1; i++) {
			for (int j = posRow - 1; j < posRow + 1; j++) {
				if (i != posLine && j != posRow && playGround[i][j].isMine) {
					minesNumAround++;
				}
			}
		}
	}
}

启动画面

for循环不断重绘开始界面的图像,并且每次绘制前清空画布,每次绘制后停顿1毫秒,实现动画效果。BeginBatchDraw,FlushBatchDraw和EndBatchDraw是EasyX的绘图函数,可以使图像绘制更流畅,从而使动画更流畅

// 启动画面
void splashScreen() {
	IMAGE splashImage;
	loadimage(&splashImage, "images/mineIcon.png",width,height);
	putimage(0, 0, &splashImage);
	Sleep(1500);

	BeginBatchDraw();
	for (int i = 0; i <= height; i+=3) {
		FlushBatchDraw();
		cleardevice();
		putimage(0, i, &splashImage);
		Sleep(1);
	}
	EndBatchDraw();
	cleardevice();
}

死循环监听鼠标事件

如果左键单击,双重for循环判断是点击的哪一个格子。然后判断这个格子是否是雷。如果是,直接判定为;如果不是,执行onLeftButtonClick函数。

如果右键单击,双重for循环判断是点击的哪一个格子。执行onLeftButtonClick函数。

每次循环开始时判断normalGridNum,即正常格子的数量。如果正常格子数量为0,说明所有正常格子已经被翻开,判定为

/*循环监听鼠标事件*/
	while (true) {
		if (normalGridsNum == 0) {
			// 显示提示信息
			settextcolor(GREEN);

			BeginBatchDraw();
			for (int i = height; i >= 10; i -= 3) {
				FlushBatchDraw();
				cleardevice();
				outtextxy(10, i, "你赢啦");
				Sleep(1);
			}
			EndBatchDraw();

			Sleep(2500);
			return 0;
		}
		ExMessage msg = getmessage(EX_MOUSE);
		if (msg.message == WM_LBUTTONDOWN) {
			for (int i = 1; i <= lines; i++) {
				for (int j = 1; j <= rows; j++) {
					if (msg.x > playGround[i][j].posX&&msg.x< playGround[i][j].posX+gridSize&&msg.y>playGround[i][j].posY&&msg.y< playGround[i][j].posY+gridSize) {
						// 判断点击的是那一个格子
						if (playGround[i][j].isMine) { // 如果是雷
							putimage(playGround[i][j].posX, playGround[i][j].posY, &mine);
							for (int i = 0; i < minesNum; i++) {
								putimage(mines[i].posLine, mines[i].posRow, &mine);
							}
							// 显示提示信息
							settextcolor(RED);
							BeginBatchDraw();
							for (int i = height; i >= 10; i -= 3) {
								FlushBatchDraw();
								cleardevice();
								outtextxy(10, i, "你输啦");
								Sleep(1);
							}
							EndBatchDraw();

							Sleep(2500); // 停顿两秒半
							return 0;
						}
						playGround[i][j].onLeftButtonClick();
					}
				}
			}
		}
		else if (msg.message == WM_RBUTTONDOWN) {
			for (int i = 1; i <= lines; i++) {
				for (int j = 1; j <= rows; j++) {
					if (msg.x > playGround[i][j].posX && msg.x< playGround[i][j].posX + gridSize && msg.y>playGround[i][j].posY && msg.y < playGround[i][j].posY + gridSize) {
						// 判断点击的是那一个格子
						playGround[i][j].onRightButtonClick();
					}
				}
			}
		}
	}

全部代码

#include<iostream>
#include<graphics.h>
#include<vector>
#include<string>
#include<tchar.h>
#include<ctime>

using namespace std;

// 默认常量
int gridSize = 40;									// 每个格子的大小(长和宽)
int lines = 5, rows = 5;							// 行数和列数
int width = rows * gridSize, height = lines * gridSize; // 窗口宽度和高度
int minesNum = 10;									// 雷的数量
int normalGridsNum = lines * rows - minesNum;		// 除了雷以外的格子数量
IMAGE grid, gridClicked, mine, gridFlag;			// 图像

// 格子类
class Grid {
public:
	int posX, posY; // 该格子所处的位置(单位:像素)
	bool isFlag = false, isClicked = false, isMine = false;
	int posLine, posRow; // 该格子所处的行和列位置(单位:格子)
	int minesNumAround = 0; // 该格子周围雷的数量
	
	void show(int posLine,int posRow) {
		//显示
		this->posLine = posLine;
		this->posRow = posRow;
		posX = (this->posRow - 1) * gridSize;
		posY = (this->posLine - 1) * gridSize;
		putimage(posX, posY, &grid);
	}
	void showMinesNumAround() {
		if (minesNumAround==0)
			return;
		else if (minesNumAround == 1)
			settextcolor(BLUE);
		else if (minesNumAround == 2)
			settextcolor(GREEN);
		else if (minesNumAround == 3)
			settextcolor(YELLOW);
		else if (minesNumAround == 4)
			settextcolor(RGB(255, 135, 35));
		else
			settextcolor(RED);
		char info = minesNumAround + 48;
		outtextxy(posX+int(gridSize*0.4), posY+int(gridSize*0.1), _T(info));
	}
	void onLeftButtonClick();
	void onRightButtonClick();
	void findMinesAround();
};

vector<vector<Grid>> playGround(lines+1,vector<Grid>(rows+1));	// 创建整个雷盘
vector<Grid> mines; // 定义一个vector储存是雷的格子

/*定义Grid类的几个函数*/
// 鼠标左键点击
void Grid::onLeftButtonClick() {
	if (!isClicked) { // 如果没有被左键点击过
		isClicked = true;
		normalGridsNum--;
		putimage(posX, posY, &gridClicked);
		
		findMinesAround();		// 找雷数
		showMinesNumAround();	// 显示出来周围雷数

		//翻开周围(4个)不是雷的格子
		vector<vector<int>> minesPosAround = { {posLine - 1,posRow},{posLine,posRow - 1},{posLine,posRow + 1},{posLine + 1,posRow} };
		for (int i = 0; i < 4; i++) {
			if (minesPosAround[i][0] > 0 && minesPosAround[i][0] <= lines && minesPosAround[i][1] > 0 && minesPosAround[i][1] <= rows) {
				if (playGround[minesPosAround[i][0]][minesPosAround[i][1]].isMine == false) {
					playGround[minesPosAround[i][0]][minesPosAround[i][1]].onLeftButtonClick();
				}
			}
		}
	}
}
// 鼠标右键点击
void Grid::onRightButtonClick() {
	if (!isFlag&&!isClicked) { // 如果没有被右键点击过
		isFlag = true;
		putimage(posX, posY, &gridFlag);
	}
	else if(isFlag&&!isClicked) {
		isFlag = false;
		putimage(posX, posY, &grid);
	}
}
// 寻找周围8个(或5个)格子中雷的数量
void Grid::findMinesAround() {
	if (isMine) { // 如果该格子是雷,则返回-1
		return;
	}
	else { // 如果该格子不是雷,继续
		for (int i = posLine - 1; i < posLine + 1; i++) {
			for (int j = posRow - 1; j < posRow + 1; j++) {
				if (i != posLine && j != posRow && playGround[i][j].isMine) {
					minesNumAround++;
				}
			}
		}
	}
}
// 启动画面
void splashScreen() {
	IMAGE splashImage;
	loadimage(&splashImage, "images/mineIcon.png",width,height);
	putimage(0, 0, &splashImage);
	Sleep(1500);

	BeginBatchDraw();
	for (int i = 0; i <= height; i+=3) {
		FlushBatchDraw();
		cleardevice();
		putimage(0, i, &splashImage);
		Sleep(1);
	}
	EndBatchDraw();
	cleardevice();
}
//主函数
int main(int argc, char* argv[]) {
	/*接收来自命令行的参数*/
	if (argc == 2 && argv[1] == "-h") { // 输出帮助信息
		cout << "帮助" << endl;
		cout << "-s:每个格子的大小" << endl;
		cout << "-l:雷盘的行数" << endl << "-r:雷盘的列数" << endl;
		cout << "-n:雷的个数" << endl;
	}
	else if (argc > 2) {
		for (int i = 1; i < argc-1; i++) {
			if (argv[i] == "-s") {
				gridSize = atoi(argv[i + 1]);
			}
			else if (argv[i] == "-l") {
				lines = atoi(argv[i + 1]);
			}
			else if (argv[i] == "-r") {
				rows = atoi(argv[i + 1]);
			}
			else if (argv[i] == "-n") {
				minesNum = atoi(argv[i + 1]);
			}
			else {
				cout << "参数错误" << endl;
			}
		}
	}
	/*初始化画布*/
	initgraph(gridSize * rows, height);
	loadimage(&grid, "images/grid.png", gridSize, gridSize);
	loadimage(&gridClicked, "images/gridClicked.png", gridSize, gridSize);
	loadimage(&mine, "images/mine.png", gridSize, gridSize);
	loadimage(&gridFlag, "images/gridFlag.png", gridSize, gridSize);
	setbkmode(TRANSPARENT);
	settextstyle(int(gridSize*0.9), int(gridSize * 0.4), _T("微软雅黑"));
	setbkcolor(WHITE);
	cleardevice();
	/*启动画面*/
	splashScreen();
	/*布置雷盘*/
	// 显示格子
	for (int i = 1; i <= lines; i++) {
		for (int j = 1; j <= rows; j++) {
			playGround[i][j].show(i, j);
			Sleep(10);
		}
	}
	// 随机布雷
	srand(time(nullptr));
	for (int i = 0; i < minesNum; i++) {
		int x = rand() % rows + 1, y = rand() % lines + 1;
		playGround[x][y].isMine = true;
		mines.push_back(playGround[x][y]);
	}
	/*循环监听鼠标事件*/
	while (true) {
		if (normalGridsNum == 0) {
			// 显示提示信息
			settextcolor(GREEN);

			BeginBatchDraw();
			for (int i = height; i >= 10; i -= 3) {
				FlushBatchDraw();
				cleardevice();
				outtextxy(10, i, "你赢啦");
				Sleep(1);
			}
			EndBatchDraw();

			Sleep(2500);
			return 0;
		}
		ExMessage msg = getmessage(EX_MOUSE);
		if (msg.message == WM_LBUTTONDOWN) {
			for (int i = 1; i <= lines; i++) {
				for (int j = 1; j <= rows; j++) {
					if (msg.x > playGround[i][j].posX&&msg.x< playGround[i][j].posX+gridSize&&msg.y>playGround[i][j].posY&&msg.y< playGround[i][j].posY+gridSize) {
						// 判断点击的是那一个格子
						if (playGround[i][j].isMine) { // 如果是雷
							putimage(playGround[i][j].posX, playGround[i][j].posY, &mine);
							for (int i = 0; i < minesNum; i++) {
								putimage(mines[i].posLine, mines[i].posRow, &mine);
							}
							// 显示提示信息
							settextcolor(RED);
							BeginBatchDraw();
							for (int i = height; i >= 10; i -= 3) {
								FlushBatchDraw();
								cleardevice();
								outtextxy(10, i, "你输啦");
								Sleep(1);
							}
							EndBatchDraw();

							Sleep(2500); // 停顿两秒半
							return 0;
						}
						playGround[i][j].onLeftButtonClick();
					}
				}
			}
		}
		else if (msg.message == WM_RBUTTONDOWN) {
			for (int i = 1; i <= lines; i++) {
				for (int j = 1; j <= rows; j++) {
					if (msg.x > playGround[i][j].posX && msg.x< playGround[i][j].posX + gridSize && msg.y>playGround[i][j].posY && msg.y < playGround[i][j].posY + gridSize) {
						// 判断点击的是那一个格子
						playGround[i][j].onRightButtonClick();
					}
				}
			}
		}
	}
	/*关闭绘图窗口*/
	closegraph();
	return 0;
}

其他

上次的扫雷代码详见储存库,图像资源也在上面,这次的用的图像一样的。不过这次写代码时改了一下图片文件的名字。

效果图

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

antd design 4 版本,表格操作列文字间隔小竖线

组件库可以直接使用 <Divider typevertical /> 时小记&#xff0c;终有成。

23 MFC 富文本

文章目录 ui 设置 使用AfxInitRichEdit2(); 初始化否则不显示 //初始化 BOOL CnotePadDlg::OnInitDialog() {CDialogEx::OnInitDialog();// 设置此对话框的图标。 当应用程序主窗口不是对话框时&#xff0c;框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标…

数学建模——TOPSIS法

TOPSIS法&#xff08;Technique for Order Preference by Similarity to ldeal Solution&#xff09; 可翻译为逼近理想解排序法&#xff0c;国内常简称为优劣解距离法 TOPSIS法是一种常用的综合评价方法&#xff0c;其能充分利用原始数据的信息&#xff0c;其结果能精确的反应…

一款基于JAVA开发的Echarts后台生成框架

目录 前言 一、Echarts后台生成框架 1、简介 2、开源地址 3、支持类型 二、图表生成实战 1、项目使用 2、后台折线图生成 3、Echarts改造 4、最终效果 总结 前言 之前的博文主要分享了一些关于Echarts的基本开发知识&#xff0c;在之前的博客中主要介绍的是在前端页面进…

魏副业而战:她又办了2套图书证

我是魏哥&#xff0c;与其躺平&#xff0c;不如魏副业而战&#xff01; 社群成员董姐又办了2套图书证&#xff0c;加上之前的1套&#xff0c;她已经有3套图书证了。 3套图书证意味着可以开9个闲鱼图书店铺。是不是感觉很NB。 董姐说&#xff0c;2套图书证等了快一个多月&…

Flink基本原理剖析讲解

1.Flink简介 Flink是一个批处理和流处理结合的统一计算框架&#xff0c;其核心是一个提供了数据分发以及并行化计算的流数据处理引擎。它的最大亮点是流处理&#xff0c;是业界最顶级的开源流处理引擎。 Flink最适合的应用场景是低时延的数据处理&#xff08;Data Processing…

面试题更新之-伪元素和伪类

文章目录 伪元素和伪类是什么&#xff1f;伪元素&#xff08;Pseudo-elements&#xff09;:伪类&#xff08;Pseudo-classes&#xff09;: css伪元素和伪类的区别使用css伪元素的好处使用css伪类的好处 伪元素和伪类是什么&#xff1f; 在CSS中&#xff0c;伪元素&#xff08;…

星云零售信贷基于 Apache Doris 的 OLAP 演进之路

本文导读&#xff1a; 腾梭科技是国内领先的零售金融数字化及安全服务提供商&#xff0c;是腾讯投资且在金融领域的战略合作伙伴&#xff0c;并与腾讯联合研发了“星云智慧信贷解决方案。在其信贷业务转型过程中&#xff0c;随着系统规模不断扩大&#xff0c;早期架构无法再满…

centos7根分区、文件系统扩容

1、 输入lsblk&#xff0c;查看到新硬盘sde&#xff0c;根目录现71G. 2、 创建分区fidisk /dev/sde 3、 刷新分区 partprobe /dev/sde&#xff0c;并创建物理卷 pvcreate /dev/sde1 4、 查看卷组名 vgdisplay 5、 将物理卷扩展到卷组 vgextend centos /dev/sde1 6、 查看逻辑巻…

linux系统安装步骤教程详解

linux是现在常用的一类操作系统&#xff0c;我们可以通过U盘、光驱、或者虚拟机进行安装。 具体步骤如下&#xff1a; 1.去https://www.centos.org/download/下载centos系统&#xff0c;其中CentOS-7.0-x86_64-DVD-1503-01.iso 是标准安装版&#xff0c;推荐下载这个; 2.使用U盘…

OCR技术的昨天今天和明天!2023年最全OCR技术指南!

OCR是一项科技革新&#xff0c;通过自动化大幅减少人工录入的过程&#xff0c;帮助用户从图像或扫描文档中提取文字&#xff0c;并将这些文字转换为计算机可读格式。这一功能在许多需要进一步处理数据的场景中&#xff0c;如身份验证、费用管理、自动报销、业务办理等都显得尤为…

MySQL常见笔试题

前言 数据库的考察在面试时可是十分常见的&#xff0c;MySQL作为一种常用的关系型数据库管理系统&#xff0c;对于它的介绍在面试时可是必不可少的&#xff0c;下面就是一些常见笔试题的模拟&#xff0c;希望可以帮助到你&#x1f642;&#x1f642; 所用到的表如下&#xff…

国产MCU-CW32F030开发学习-BH1750模块

国产MCU-CW32F030开发学习-BH1750模块 硬件平台 CW32_48F大学计划板CW32_IOT_EVA物联网开发评估套件BH1750数字型光照强度传感器 BH1750 BH1750是一款数字型光照强度传感器&#xff0c;能够获取周围环境的光照强度。其测量范围在0~65535 lx。lx勒克斯&#xff0c;是光照强…

界面设计利器!10款Sketch插件合集,助你事半功倍!

在界面设计领域&#xff0c;Sketch以其高效、小巧的优势获得了不少设计团队的喜爱&#xff0c;帮助全球设计师创造了许多不可思议的作品。在使用Sketch的过程中&#xff0c;辅助使用一些Sketch插件&#xff0c;可以让我们更加高效地完成设计任务。本篇文章&#xff0c;我们将揭…

torch分布式通信基础

torch分布式通信基础 1. 点到点通信2. 集群通信 官网文档&#xff1a;WRITING DISTRIBUTED APPLICATIONS WITH PYTORCH 1. 点到点通信 # 同步&#xff0c;peer-2-peer数据传递 import os import torch import torch.distributed as dist import torch.multiprocessing as mpdef…

热点探测技术架构设计与实践

1. 概述 说到热点问题&#xff0c;首先我们先理解一下什么是热点&#xff1f; 热点通常意义来说&#xff0c;是指在一段时间内&#xff0c;被广泛关注的物品或事件&#xff0c;例如微博热搜&#xff0c;热卖商品&#xff0c;热点新闻&#xff0c;明星直播等等&#xff0c;所以…

领域知识图谱的医生推荐系统:利用BERT+CRF+BiLSTM的医疗实体识别,建立医学知识图谱,建立知识问答系统

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

Xcode报错--访问keychain,出现弹窗处理方案

情景 访问keychain弹出弹窗&#xff0c;不想人工点击&#xff0c;比如自动化测试中使用keychain中的证书的情况 原因 Mac的保护机制 处理 1、人工&#xff1a;输入Password&#xff0c;点击Allow或者Always Allow 2、命令行处理 security unlock-keychain -p "<…

Spring @RequestMapping 工作原理

Spring RequestMapping 工作原理 配置基础启动类及Controller类 SpringBootApplication public class DemoServiceApplication {public static void main(String[] args) {SpringApplication.run(DemoServiceApplication.class, args);} }RestController public class HelloC…

列表定义状态比较不错的UI写法

<el-table-columnprop"status"label"状态"align"left":formatter"formatTd" ><template slot-scope"scope"><span class"grayStatus" v-if"scope.row.status 1">未开始</span>…