inux基础项目开发1:量产工具——业务系统(七)

前言:

前面我们已经构造出来显示系统、输入系统、文字系统、UI系统、页面系统,这个项目百分之八十需要实现的都已经构建出来了,最后让我们对这个项目进行最后一项系统的搭建,也就是业务系统,说到业务大家应该就知道我们要干什么了,那就是把所有的代码整合到一起实现一些我们想要实现的功能。

目录

一、流程代码框架

1.业务系统流程图

 2.主页面流程图:

3.main.c

4.main_page.c 

二、处理配置文件

1.配置文件的样子 

2. 怎么处理配置文件

3.config.h

4.config.c 

三、生成界面 

1.计算每个按钮的Region

 2.main_page.c

 四、处理输入事件

 man_page.c


一、流程代码框架

1.业务系统流程图

 2.主页面流程图:

3.main.c


#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdlib.h>#include <disp_manager.h>
#include <font_manager.h>int main(int argc, char **argv)
{PDispBuff ptBuffer;int error;if (argc != 2){printf("Usage: %s <font_file>\n", argv[0]);return -1;}/* 初始化显示系统 */		DisplayInit();SelectDefaultDisplay("fb");InitDefaultDisplay();ptBuffer = GetDisplayBuffer();/* 初始化输入系统 */		InputInit();IntpuDeviceInit();/* 初始化文字系统 */		FontsRegister();error = SelectAndInitFont("freetype", argv[1]);if (error){printf("SelectAndInitFont err\n");return -1;}/* 初始化页面系统 */		PagesRegister();/* 运行业务系统的主页面 */Page("main")->Run(NULL);return 0;	
}

第22~26行:打印用法 

第29~35行:初始化显示系统

        第29行:初始化显示设备

        第30行:选择默认的显示设备

        第31行:初始化这个默认的设备

        第35行:获得显示区域

第38、39行:初始化输入系统

        第38行:初始化输入设备

        第39行:选择默认输入设备

第43~50行:初始化文字系统

        第45行:选择字库

第53行:初始化页面系统

第55行:运行业务系统的主页面

4.main_page.c 


#include <page_manager.h>
#include <stdio.h>static void MainPageRun(void *pParams)
{/* 读取配置文件 *//* 根据配置文件生成按钮、界面 */while (1){/* 读取输入事件 *//* 根据输入事件找到按钮 *//* 调用按钮的OnPressed函数 */}
}static PageAction g_tMainPage = {.name = "main",.Run  = MainPageRun,
};void MainPageRegister(void)
{PageRegister(&g_tMainPage);
}

二、处理配置文件

        对于我们要制作的页面,里面有很多按钮,那么我们怎么知道每个按钮里面都存放着什么呢?这时我们就需要配置文件,以后我们想要打开哪个按钮,调整测试模块时,可以直接修改配置文件即可,就不需要重新修改,编译程序就可以带来非常大的灵活性。

1.配置文件的样子 

2. 怎么处理配置文件

对于配置文件的每一行,都创建一个ItemCfg结构体

 并对外提供函数,比如获得某个配置项

3.config.h


#ifndef _CONFIG_H
#define _CONFIG_H#include <common.h>#define ITEMCFG_MAX_NUM 30
#define CFG_FILE  "/etc/test_gui/gui.conf"typedef struct ItemCfg {int index;char name[100];int bCanBeTouched;char command[100];
}ItemCfg, *PItemCfg;int ParseConfigFile(void);
int GetItemCfgCount(void);
PItemCfg GetItemCfgByIndex(int index);
PItemCfg GetItemCfgByName(char *name);#endif

第7行:解析配置文件,得到的结构体保存到数组里,数组的内存大小为30

第8行:提供默认的配置文件

第11行:描述配置文件的哪一项

第12行:描述配置文件的名字

第13行:描述能否被点击

第14行:状态发生变化时调用某个命令

第17行:传入配置文件的名字解析配置文件,得到ItemCfg结构体

第18行:确定有多少行,也就是确定出有多少个按钮

第19行:传入某个index,返回某个配置项

第20行:传入名字,返回某个配置项

4.config.c 

#include <config.h>
#include <stdio.h>static ItemCfg g_tItemCfgs[ITEMCFG_MAX_NUM];
static int g_iItemCfgCount = 0;int ParseConfigFile(char *strFileName)
{FILE *fp;char buf[100];char *p = buf;/* 1. open config file */fp = fopen(CFG_FILE, "r");if (!fp){printf("can not open cfg file %s\n", CFG_FILE);return -1;}while (fgets(buf, 100, fp)){/* 2.1 read each line */buf[99] = '\0';		/* 2.2 吃掉开头的空格或TAB */p = buf;while (*p == ' ' || *p =='\t')p++;/* 2.3 忽略注释 */if (*p == '#')continue;/* 2.4 处理 */g_tItemCfgs[g_iItemCfgCount].command[0] = '\0';g_tItemCfgs[g_iItemCfgCount].index = g_iItemCfgCount;sscanf(p, "%s %d %s", g_tItemCfgs[g_iItemCfgCount].name, &g_tItemCfgs[g_iItemCfgCount].bCanBeTouched, \g_tItemCfgs[g_iItemCfgCount].command);g_iItemCfgCount++;		}return 0;
}int GetItemCfgCount(void)
{return g_iItemCfgCount;
}PItemCfg GetItemCfgByIndex(int index)
{if (index < g_iItemCfgCount)return &g_tItemCfgs[index];elsereturn NULL;
}PItemCfg GetItemCfgByName(char *name)
{int i;for (i = 0; i < g_iItemCfgCount; i++){if (strcmp(name, g_tItemCfgs[i].name) == 0)return &g_tItemCfgs[index];}return NULL;
}

第6行:解析配置文件,得到ItemCfg结构体保存到g_tItemCfgs[ITEMCFG_MAX_NUM]这个数组里

第7行:解析配置文件以后,记录配置文件有多少项

int ParseConfigFile(char *strFileName)

第9~45行: 进行解析配置文件

        第13行:读进一行放到buf数组里

        第16行:打开文件 ,只需要读(r)即

        第19行:如果没有打开的话,打印不能打开这个文件,表示配置失败

        第23行:fgets(buf, 100, fp)读入一行

        第26行:读出每一行,最大数量是100

        第29~31行:吃掉开头的空格TAB

        第34~35行:忽略注释

        第38~42行:进行处理

                第38行:根据command[0] 是否为 '\0' 来判断g_tItemCfgs里是否有命令,如果第0项没有command就表明command从配置文件里面得到了他的值

        第44行:返回0表示成功

int GetItemCfgCount(void)

第47~50行:确定有多少行,也就是确定出有多少个按钮,直接获得g_iItemCfgCount即可

PItemCfg GetItemCfgByIndex(int index)

第52~58行:通过index获得某一项

PItemCfg GetItemCfgByName(char *name)

第60~69行:通过名字获得某一项

三、生成界面 

想显示这样的界面

通过配置文件可以知道有哪些按钮,知道每个按钮的名字

只剩最后一项了:怎么确定每个按钮的位置、大小?需要计算!

1.计算每个按钮的Region

 2.main_page.c


#include <config.h>
#include <page_manager.h>
#include <stdio.h>
#include <math.h>#define X_GAP 5
#define Y_GAP 5static Button g_tButtons[ITEMCFG_MAX_NUM];static void GenerateButtons(void)
{int width, height;int n_per_line;int row, rows;int col;int n;PDispBuff pDispBuff;int xres, yres;int start_x, start_y;int pre_start_x, pre_start_y;PButton pButton;int i = 0;/* 算出单个按钮的width/height */n = GetItemCfgCount();pDispBuff = GetDisplayBuffer();xres = pDispBuff->iXres;yres = pDispBuff->iYres;width = sqrt(1.0/0.618 *xres * yres / n);n_per_line = xres / width + 1;width  = xres / n_per_line;height = 0.618 * width;	/* 居中显示:  计算每个按钮的region  */start_x = (xres - width * n_per_line) / 2;rows    = n / n_per_line;if (rows * n_per_line < n)rows++;start_y = (yres - rows*height)/2;/* 计算每个按钮的region */for (row = 0; (row < rows) && (i < n); row++){pre_start_y = start_y + row * height;pre_start_x = start_x - width;for (col = 0; (col < n_per_line) && (i < n); col++){pButton = g_tButtons[i];pButton->tRegion.iLeftUpX = pre_start_x + width;pButton->tRegion.iLeftUpY = pre_start_y;pButton->tRegion.iWidth   = width - X_GAP;pButton->tRegion.iHeigh   = height - Y_GAP;pre_start_x = pButton->tRegion.iLeftUpX;/* InitButton */InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, NULL);i++;}}/* OnDraw */for (i = 0; i < n; i++)g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}static void MainPageRun(void *pParams)
{int error;/* 读取配置文件 */error = ParseConfigFile();if (error)return error;/* 根据配置文件生成按钮、界面 */GenerateButtons();while (1){/* 读取输入事件 *//* 根据输入事件找到按钮 *//* 调用按钮的OnPressed函数 */}
}static PageAction g_tMainPage = {.name = "main",.Run  = MainPageRun,
};void MainPageRegister(void)
{PageRegister(&g_tMainPage);
}

第77~75行:读取配置文件

第80~89行:根据配置文件生成按钮、界面

static void GenerateButtons(void)

第13~69行:生成按钮

        第28~36行:算出单个按钮的width/height

                第28行:算出有多少个按钮

                第30~32行:获得屏幕分辨率

                第33行:算出按钮理想宽度

                第34行:算出每一行最多显示出多少个按钮

                第35行:再反算出实际按钮宽度

                第36行:根据宽度算出高度

        第39~44行:居中显示:  计算每个按钮的区域region

                第39~44行:算出左上角的具体位置

                          第40行:算出有多少行

                          第41行:如果rows * n_per_line < n则有小数出现,需要给rows++

        第46~64行:计算每个按钮的区域region

                第49、50行:前一个按钮的位置

                第54、55行:计算下一个按钮的位置

                第56、57行:计算下一个按钮的宽度和高度,并且留5个距离的间隙 

                第58行:更新起始位置

                第61行:初始化按钮

                                GetItemCfgByIndex(i)->name从配置文件中得到

                        

void InitButton(PButton ptButton, char *name, PRegion ptRegion, ONDRAW_FUNC OnDraw, ONPRESSED_FUNC OnPressed)
{ptButton->status = 0;ptButton->name = name;if (ptRegion)ptButton->tRegion = *ptRegion;ptButton->OnDraw    = OnDraw ? OnDraw : DefaultOnDraw;ptButton->OnPressed = OnPressed ? OnPressed : DefaultOnPressed;
}

        第67~68行:显示出按钮

  

 四、处理输入事件

我们得到的输入事件,可能来自触摸屏,也可能是其他APP发来的网络数据

对于触摸屏事件,根据iXiY找到按钮 

对于网络数据,我们限定为这样的格式:

  “name ok”、“name err”、“name 70%

  根据name找到按钮

对于按钮,我们要提供自己的OnPressed函数,不适用UI系统默认的函数

 man_page.c


#include <config.h>
#include <page_manager.h>
#include <stdio.h>
#include <math.h>#define X_GAP 5
#define Y_GAP 5static Button g_tButtons[ITEMCFG_MAX_NUM];
static int g_tButtonCnt;static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{unsigned int dwColor = BUTTON_DEFAULT_COLOR;char name[100];char status[100];char *strButton;/* 1. 对于触摸屏事件 */if (ptInputEvent->iType == INPUT_TYPE_TOUCH){/* 1.1 分辨能否被点击 */if (GetItemCfgByName(ptButton->name)->bCanBeTouched == 0)return -1;/* 1.2 修改颜色 */ptButton->status = !ptButton->status;if (ptButton->status)dwColor = BUTTON_PRESSED_COLOR;strButton = ptButton->name;}else if (ptInputEvent->iType == INPUT_TYPE_NET){/* 2. 对于网络事件 */strButton = ptButton->name;/* 根据传入的字符串修改颜色 : wifi ok, wifi err, burn 70 */sscanf(ptInputEvent->str, "%s %s", name, status);if (strcmp(status, "ok") == 0)dwColor = BUTTON_PRESSED_COLOR;else if (strcmp(status, "err") == 0)dwColor = BUTTON_DEFAULT_COLOR;else if (status[0] >= '0' && status[0] <= '9'){			dwColor = BUTTON_PERCENT_COLOR;strButton = status;			}elsereturn -1;}/* 绘制底色 */DrawRegion(&ptButton->tRegion, dwColor);/* 居中写文字 */DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);return 0;
}static void GenerateButtons(void)
{int width, height;int n_per_line;int row, rows;int col;int n;PDispBuff pDispBuff;int xres, yres;int start_x, start_y;int pre_start_x, pre_start_y;PButton pButton;int i = 0;/* 算出单个按钮的width/height */g_tButtonCnt = n = GetItemCfgCount();pDispBuff = GetDisplayBuffer();xres = pDispBuff->iXres;yres = pDispBuff->iYres;width = sqrt(1.0/0.618 *xres * yres / n);n_per_line = xres / width + 1;width  = xres / n_per_line;height = 0.618 * width;	/* 居中显示:  计算每个按钮的region  */start_x = (xres - width * n_per_line) / 2;rows    = n / n_per_line;if (rows * n_per_line < n)rows++;start_y = (yres - rows*height)/2;/* 计算每个按钮的region */for (row = 0; (row < rows) && (i < n); row++){pre_start_y = start_y + row * height;pre_start_x = start_x - width;for (col = 0; (col < n_per_line) && (i < n); col++){pButton = g_tButtons[i];pButton->tRegion.iLeftUpX = pre_start_x + width;pButton->tRegion.iLeftUpY = pre_start_y;pButton->tRegion.iWidth   = width - X_GAP;pButton->tRegion.iHeigh   = height - Y_GAP;pre_start_x = pButton->tRegion.iLeftUpX;/* InitButton */InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, MainPageOnPressed);i++;}}/* OnDraw */for (i = 0; i < n; i++)g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion)
{if (iX < ptRegion->iLeftUpX || iX >= ptRegion->iLeftUpX + ptRegion->iWidth)return 0;if (iY < ptRegion->iLeftUpY || iY >= ptRegion->iLeftUpY + ptRegion->iHeigh)return 0;return 1;
}static PButton GetButtonByName(char *name)
{int i;for (i = 0; i < g_tButtonCnt; i++){if (strcmp(name, g_tButtons[i].name) == 0)return &g_tButtons[i];}return NULL;
}static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)
{int i;char name[100];if (ptInputEvent->iType == INPUT_TYPE_TOUCH){for (i = 0; i < g_tButtonCnt; i++){if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_tButtons[i].tRegion))return &g_tButtons[i];}}else if (ptInputEvent->iType == INPUT_TYPE_NET){sscanf(ptInputEvent->str, "%s", name);return GetButtonByName(name);}else{return NULL;}
}static void MainPageRun(void *pParams)
{int error;InputEvent tInputEvent;PButton ptButton;PDispBuff ptDispBuff = GetDisplayBuffer();/* 读取配置文件 */error = ParseConfigFile();if (error)return error;/* 根据配置文件生成按钮、界面 */GenerateButtons();while (1){/* 读取输入事件 */error = GetInputEvent(&tInputEvent);if (error)continue;/* 根据输入事件找到按钮 */ptButton = GetButtonByInputEvent(&tInputEvent);if (!ptButton)continue;/* 调用按钮的OnPressed函数 */ptButton->OnPressed(ptButton, ptDispBuff, &tInputEvent);}
}static PageAction g_tMainPage = {.name = "main",.Run  = MainPageRun,
};void MainPageRegister(void)
{PageRegister(&g_tMainPage);
}

第82行:计算按钮的个数 

第115行:初始化按钮时候提供我们自己的处理函数 MainPageOnPressed

第190~204行:

        第193~195行:读取输入事件,得到的数据保存在tInputEvent这个结构体里

        第198~200行:根据输入事件找到按钮

        第203行:调用按钮的OnPressed函数

static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)

第151~173行:根据输入事件找到按钮

        第156~163行:判断事件的类型是否为触摸屏

                第160行:遍历每个按钮并且找寻触点

        第164~168行:判断事件的类型是否为网络数据

                第166行:将网络数据名字提取出来

                第167行:根据名字找到按钮

        

static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion)

第125~134行:寻找触点 

static PButton GetButtonByName(char *name)

 第137~148行:根据网络数据输入的名字找到按钮

static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)

 第13~64行:之前是默认的处理函数,现在我们要提供自己自定义的处理函数

         第15行:设置默认按钮颜色为红色

         第21行:判断是否是触摸屏事件

                 第24行:判断是否能被点击

                        第28行:修改颜色

        第34行:判断是否为网络事件  

                第40~51行:根据传入的字符串进行判断是否修改颜色

                在ui.h里面多定义一个颜色”蓝色“

#define BUTTON_PERCENT_COLOR 0x0000ff

 献上韦东山老师对以上代码流程的梳理过程

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

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

相关文章

解决ZED SDK安装后不可用,出现“核心已转储”的闪退问题

在陈述问题简单回顾下ZED SDK安装的步骤 ZED的运行需要显卡支持&#xff0c;cuda加速&#xff0c;因此需要提前安装好显卡驱动以及对应的cuda和cudnn&#xff0c;基础工作在此不再赘述&#xff0c;以下步骤默认已经完成上述准备工作。 建议新建一个虚拟环境以限定ZED使用的py…

飞行员兄弟

飞行员兄弟 思路&#xff1a; 这里一共有16个格子&#xff0c;如果暴力的话也就是2^16次方种排列组合。 这题和之前的开关不一样&#xff0c;这题是会影响到周围很多格子&#xff0c;而开关那题可以利用上方只改变一个的操作来解题&#xff0c;这题我想到的就是暴搜&#xff…

阿里微服务质量保障系列:性能监控最佳实践

建设一体化性能监控平台 随着互联网技术的不断发展&#xff0c;企业的业务规模和复杂度也在不断增加。为了保证业务的稳定性和可靠性&#xff0c;企业需要对其系统进行全面的性能监控。而一体化性能监控就是一种集成了多种监控工具和技术的综合性监控方案&#xff0c;可以帮助…

电源需要考虑的因素

做产品的都离不开电源&#xff0c;产品出问题也首先检查供电是否正常。今天给大家分享的是做好一个电源需要考虑哪些因素。 一&#xff0e; 描述输入电压影响输出电压几个指标形式 1&#xff0e; 稳压系数 A&#xff0e;稳压系数&#xff1a;表示负载不变时&#xff0c;稳压电源…

深度解析:整数和浮点数在内存中的存储

深度解析&#xff1a;整数和浮点数在内存中的存储 引言 在计算机科学中&#xff0c;理解整数和浮点数在内存中的存储方式是深入学习的关键一步。这篇博客将带你深入探讨整数和浮点数的内存表示&#xff0c;并通过代码实例详细解析其存储结构。 整数的内存存储 对于整形来说&a…

Redis命令详解

文章目录 Key&#xff08;键&#xff09; DEL EXISTS EXPIRE EXPIREAT PEXPIRE PEXPIREAT PERSIST KEYS TTL PTTL RENAME RENAMENX TYPE SCAN HSCAN SSCAN ZSCAN DUMP String&#xff08;字符串&#xff09; SET GET INCR DECR MSET MGET APPEND SETNX STRLEN INCRBY DECRBY IN…

Spark大数据集群日常开发过程遇到的异常及解决思路汇总

原创/朱季谦 在开发Spark任务过程中&#xff0c;遇到过不少新人经常可能会遇到的坑&#xff0c;故而将这些坑都总结了下来&#xff0c;方便日后遇到时&#xff0c;可以快速定位解决&#xff0c;壁面耗费过多时间在查找问题之上。 一、出现java.lang.IllegalAccessError: tried…

阻抗匹配电阻原理及其应用

一、匹配电阻的作用 1、阻抗匹配 当信号频率比较高&#xff0c;上升沿比较陡时&#xff0c;电子信号经过阻抗不同的地方时也会产设反射。 PCB的单线阻抗一般会设计成50Ω&#xff0c;发射端阻抗一般是17到40&#xff0c;而接收端一般是MOS管的输入&#xff0c;阻抗是比较大的…

【字符串匹配】【KMP算法】Leetcode 28 找出字符串中第一个匹配项的下标

【字符串匹配】【KMP算法】Leetcode 28 找出字符串中第一个匹配项的下标 &#xff08;1&#xff09;前缀和后缀&#xff08;2&#xff09;前缀表&#xff08;最长相同的前缀和后缀的长度&#xff09;&#xff08;3&#xff09;匹配过程示意&#xff08;4&#xff09;next数组的…

分享几个国内免费使用的 gpt 网站

可放心阅读点击&#xff0c;无邀请链接、邀请码等 今天主要分享几个个免费的GPT网站。 1、智晓星AiStar 智晓星AiStar 个人长期自用&#xff0c;界面简单&#xff0c;使用比较方便&#xff0c;支持验证码、微信登录。 对于免费用户来说&#xff0c;登录之后每天可以使用50…

系统地自学 Python

文章目录 如何系统地自学 Python1. 选择合适的 Python 版本2. 安装 Python 和必要的工具3. 学习 Python 的基础知识4. 学习 Python 的高级特性5. Python 的应用领域6. 保持良好的学习习惯 如何系统地自学 Python Python 是一种广泛使用的编程语言&#xff0c;它具有简洁、易读、…

flutter使用动态路由传参的最小案例

flutter中使用动态路由传递参数的封装案例&#xff0c;子组件页面只需要接收arguments参数即可&#xff0c;参数是一个map&#xff0c;里面包含有所需要的参数&#xff0c;类似于json。在MaterialApp中配置onGenerateRoute&#xff0c;然后动态判断传递参数&#xff1a; route…

Rust国内sparse镜像源配置

文章目录 1. 遇到问题1.1 问题现象1.2 解决办法 2. 重新设置最新 sparse源3. 更多参考资料3.1 字节源3.2 ustc 源3.3 清华源3.4 其他人的总结 1. 遇到问题 有好一阵子没有更新源和安装软件了&#xff0c; 使用ustc的源&#xff0c; 更新了好一阵子&#xff0c; 最后安装居然还出…

费解的开关

费解的开关 模拟一下开关的过程&#xff1a; 直接对第一行进行开关灯即可&#xff0c;那么第一行开关等的方案有多少个呢&#xff1f; 可以第一个想到的是5次&#xff0c;但实际上是25次&#xff0c;因为没有规定说只能开关一次吧。 那么如何获得这32种方案呢&#xff1f; 可…

十五届海峡两岸电视主持新秀大会竞赛流程

海峡两岸电视主持新秀会是两岸电视媒体共同举办的一项活动&#xff0c;旨在为两岸年轻的电视主持人提供一个展示才华的舞台&#xff0c;促进两岸文化交流和青年交流。本届新秀会是第十二届海峡两岸电视艺术节的重要活动之一。本次竞赛赛制流程如下&#xff1a; &#xff08;1&…

springboot助农管理系统

springboot助农管理系统 成品项目已经更新&#xff01;同学们可以打开链接查看&#xff01;需要定做的及时联系我&#xff01;专业团队定做&#xff01;全程包售后&#xff01; 2000套项目视频链接&#xff1a;https://pan.baidu.com/s/1N4L3zMQ9nNm8nvEVfIR2pg?pwdekjv 提…

初探Java之旅:探寻Java的奥秘

✨个人主页&#xff1a;全栈程序猿的CSDN博客 &#x1f4a8;系列专栏&#xff1a;Java从入门到精通 ✌座右铭&#xff1a;编码如诗&#xff0c;Bug似流星&#xff0c;持续追求优雅的代码&#xff0c;解决问题如同星辰般自如 在计算机编程的世界中&#xff0c;有一门被誉为“千变…

分享87个节日PPT,总有一款适合您

分享87个节日PPT&#xff0c;总有一款适合您 87个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1eUxA59uQ-hZWWpFzzDuCkQ?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

affinity好用还是ps好用?2024年最新功能解析

多年来&#xff0c;ps已经有了大量竞争对手。然而每次Photoshop都足以保持其领先地位。开源GIMP和Pixelmator都试图取代Photoshop&#xff0c;不过Photoshop对此不屑一顾。英国Serif公司研发了一款名为Affinity Photo的软件&#xff0c;声称可以叫板ps。今天我们看看有最有可能…

【CPU 架构】x86、x86_64、x64、arm64、aarch64

x86、x86_64、x64、arm64、aarch64 1.服务器分类2.CPU 架构2.1 x86 架构&#xff1a;x86、x86_64、x642.2 arm 架构&#xff1a;arm64 和 aarch64 3.发展历史 1.服务器分类 按照 CPU 体系架构来区分&#xff0c;服务器主要分为两类&#xff1a; 非 x86 服务器&#xff1a;使用…