Linux基础项目开发day06:量产工具——业务系统

文章目录

  • 前言
  • 一、流程代码框架
    • 1、业务系统框架流程
    • 2、主页面流程图
    • 3、main.c实现流程
  • 二、处理配置文件
    • 1、配置文件是啥?
      • config.h
    • 2、怎么处理配置文件?
      • config.c
  • 三、生成界面
    • 1、计算每个按钮的Region
    • 2、逐个生成按钮画面->生成页面
  • 四、读取输入事件
  • 五、根据输入事件找到按钮
  • 六、调用按钮的OnPressed函数
    • 完整的main.page.c
  • 七、上机测试

前言

我们目前已经搭建了显示系统、输入系统、文字系统、UI系统、页面系统,这就已经完成了这个项目的百分之80了,之间的都是独立的开发基础,我们就是要利用前面的基础来合成再运用产品所需要的逻辑,就可以实现项目功能!
1.前面实现了各个子系统:显示、输入、文字、UI、页面
2.它们只是提供基础能力,跟业务逻辑没有关系
3.这样的架构很容易扩展,可以在这上面实现各种业务
4.比如可以做收银机、自动售卖机、智能称、取号机;
再加上摄像头显示,就可以做出可视对讲、视频监控、人脸红外测温
5.对于不同的产品,我们只需要写出自己页面函数

一、流程代码框架

1、业务系统框架流程

在这里插入图片描述

2、主页面流程图

在这里插入图片描述

3、main.c实现流程

这里我们在main.c里面做的事情就很明显了,先初始化前面的独立的系统,后面再只要运行业务里面的Run函数即可!


#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>
#include <input_manager.h>
#include <page_manager.h>


int main(int argc, char **argv)
{
	int error;

	if (argc != 2)
	{
		printf("Usage: %s <font_file>\n", argv[0]);
		return -1;
	}
	
	/* 初始化显示系统 */		
	DisplayInit();

	SelectDefaultDisplay("fb");

	InitDefaultDisplay();

	/* 初始化输入系统 */		
	InputInit();
	IntpuDeviceInit();


	/* 初始化文字系统 */		
	FontsRegister();
	
	/* 选择一个文字系统 */
	error = SelectAndInitFont("freetype", argv[1]);
	if (error)
	{
		printf("SelectAndInitFont err\n");
		return -1;
	}

	/* 初始化页面系统 */		
	PagesRegister();

	/* 运行业务系统的主页面 */
	Page("main")->Run(NULL);
	
	return 0;	
}

那么main函数里面的Run函数里面到底在做啥呢?
在这里插入图片描述
要做的东西就只有这些,所以我们后面只需要实现对应作用的函数即可!

二、处理配置文件

1、配置文件是啥?

使用配置文件我们可以使这个代码更有兼容性和更灵活,我们需要修改页面内容时,我们只需要去修改配置文件即可!就不用特地去修改代码,配置文件是怎么样的呢?
在这里插入图片描述
按钮的名称都是有配置文件读取得到。
对于每一行,都对应一个按钮图画,但是这些按钮图画有些是可以通过触摸去改变颜色的,但是有一些是不可以的,只能通过网络发送信息来修改颜色,所以我们就用一个结构体来代指一个按钮图画:
在这里插入图片描述

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); //通过索引查找config结构体
PItemCfg GetItemCfgByName(char *name); //通过name查找config结构体
 

#endif


那我们要怎么处理配置文件呢?

2、怎么处理配置文件?

看到了配置文件的格式,我们就知道了,有#号的第一行知识注释,省略这一行其他的就简单了:

#include <config.h>
#include <stdio.h>
#include <string.h>

static ItemCfg g_tItemCfgs[ITEMCFG_MAX_NUM];
static int g_iItemCfgCount = 0;

/* 处理配置文件函数 */
int ParseConfigFile(void)
{
	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;
}

config.c



#include <config.h>
#include <stdio.h>
#include <string.h>

static ItemCfg g_tItemCfgs[ITEMCFG_MAX_NUM];
static int g_iItemCfgCount = 0;

//处理配置文件函数
int ParseConfigFile(void)
{
	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;
}

//通过索引查找config结构体
PItemCfg GetItemCfgByIndex(int index)
{
	if (index < g_iItemCfgCount)
		return &g_tItemCfgs[index];
	else
		return NULL;
}

//通过name查找config结构体
PItemCfg GetItemCfgByName(char *name)
{
	int i;
	for (i = 0; i < g_iItemCfgCount; i++)
	{
		if (strcmp(name, g_tItemCfgs[i].name) == 0)
			return &g_tItemCfgs[i];
	}
	return NULL;
}

三、生成界面

1、计算每个按钮的Region

在这里插入图片描述

2、逐个生成按钮画面->生成页面

这个函数是写在main_page.c里面的

static void GenerateButtons(void)
{
	int width, height; //宽度高度
	int n_per_line;    //一行可以画的下多少个按钮
	int row, rows;     //行(for循环用), 行数
	int col;           //列数
	int n;             //按钮个数
	PDispBuff pDispBuff;
	int xres, yres;   //屏幕XY分辨率
	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逐个Draw按钮图画 */
	for (i = 0; i < n; i++)
		g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}

四、读取输入事件

对于读取输入事件我们之前在输入系统就已经实现了,忘记的可以看看:Linux基础项目开发day02:量产工具——输入系统

五、根据输入事件找到按钮

这些函数都是在main.page.c里面实现的


static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion);
static PButton GetButtonByName(char *name);

static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)
{
	int i;
	char name[100];
	
	/* 输入事件是触摸屏事件 */
	if (ptInputEvent->iType == INPUT_TYPE_TOUCH)
	{
		for (i = 0; i < g_tButtonCnt; i++)
		{
		    /* 拿触摸点的坐标一个个的去和按钮Region对比,在区域内就返回这个按钮 */
			if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_tButtons[i].tRegion))
				return &g_tButtons[i];//返回这个按钮
		}
	}
	/* 输入事件是网络输入事件 */
	else if (ptInputEvent->iType == INPUT_TYPE_NET)
	{
	    //从网络数据中读取数据到name数组中
		sscanf(ptInputEvent->str, "%s", name);
		//拿网络输入的数据和按钮Region的名称对比,找到一样的返回这个按钮Botton
		return GetButtonByName(name);
	}
	else
	{
		return NULL;
	}
	return NULL;
}


 /* 拿触摸点的坐标一个个的去和按钮Region对比,在区域内就返回这个按钮 */
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;
}

//拿网络输入的数据和按钮Region的名称对比,找到一样的返回这个按钮Botton
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;
}

六、调用按钮的OnPressed函数

通过第五步我们已经找到了按钮,最后一步就简单了,只需要调用里面的函数即可!
在这里插入图片描述
我们在生成按钮界面的时候就已经初始化了Botton结构体里面的函数了
在这里插入图片描述
所以我们这里只需要实现函数MainPageOnPressed即可!

static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{
	unsigned int dwColor = BUTTON_DEFAULT_COLOR;
	char name[100];
	char status[100];
	char *strButton;

	strButton = ptButton->name;
	
	/* 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;
	}
	else if (ptInputEvent->iType == INPUT_TYPE_NET)
	{
		/* 2. 对于网络事件 */
		
		/* 根据传入的字符串修改颜色 : 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;			
		}
		else
			return -1;
	}
	else
	{
		return -1;
	}

	/* 绘制底色 */
	DrawRegion(&ptButton->tRegion, dwColor);

	/* 居中写文字 */
	DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);

	/* flush to lcd/web */
	FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);
	return 0;
}

完整的main.page.c

#include <config.h>
#include <stdio.h>
#include <ui.h>
#include <page_manager.h>
#include <math.h>
#include <string.h>
 
#define X_GAP 5
#define Y_GAP 5
 
static 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;
 
	strButton = ptButton->name;
	
	/* 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;
	}
	else if (ptInputEvent->iType == INPUT_TYPE_NET)
	{
		/* 2. 对于网络事件 */
		
		/* 根据传入的字符串修改颜色 : 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;			
		}
		else
			return -1;
	}
	else
	{
		return -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;
	}
	return NULL;
}
 
static void MainPageRun(void *pParams)
{
	int error;
	InputEvent tInputEvent;
	PButton ptButton;
	PDispBuff ptDispBuff = GetDisplayBuffer();
	
	/* 读取配置文件 */
	error = ParseConfigFile();
	if (error)
		return ;
 
	/* 根据配置文件生成按钮、界面 */
	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);
}

七、上机测试

到这里我们就已经完成了基础开发项目了——量产工具

book@100ask:~/28_business_test$ make
book@100ask:~/28_business_test$ arm-buildroot-linux-gnueabihf-gcc -o client unittest/client.c

[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
[root@100ask : /mnt/28_business_test] # mkdir /etc/test_gui
[root@100ask : /mnt/28 business test] # cp etc/test_gui/gui.conf /etc/
[root@100ask : /mnt/28 business test] # ./test ./simsun.ttc &
[root@100ask : /mnt/28 business test] # ./client 192.168.5.9 “net1 ok”
[root@100ask : /mnt/28 business test] # ./client 192.168.5.9 “ALL ok”
[root@100ask : /mnt/28 business test] # ./client 192.168.5.9 “net1 err”
[root@100ask : /mnt/28 business test] # ./client 192.168.5.9 “ALL err”

触摸点击测试:
在这里插入图片描述
点击后:
在这里插入图片描述

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

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

相关文章

记录一次hiveserver2卡死(假死)问题

问题描述 给开发人员开通了个账号&#xff0c;连接hive进行查询&#xff0c;后来发现&#xff0c;hive服务有时候会卡死&#xff0c;查询不了&#xff0c;连不上&#xff08;所有账号/客户端都连不上hive&#xff09;&#xff0c;但在chd里面看监控&#xff0c;服务器资源状态…

物联网之超声波测距模块、arduino、esp32

MENU 原理硬件电路设计软件程序设计 原理 超声波是一种频率高于20000Hz的声波&#xff0c;功率密度为p≥0.3W/cm&#xff0c;它的方向性好&#xff0c;反射能力强&#xff0c;易于获得较集中的声能。超声波用于许多不同的领域&#xff0c;比如检测物体和测量距离&#xff0c;清…

Unity 2d UI 实时跟随场景3d物体

2d UI 实时跟随场景3d物体位置&#xff0c;显示 3d 物体头顶信息&#xff0c;看起来像是场景中的3dUI&#xff0c;实质是2d UIusing System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using UnityEngine.UI; /// <summary>…

【JS】无法阻止屏幕滚动

监听滚轮事件&#xff0c;阻止默认行为&#xff0c;但未生效&#xff0c;且控制台报错。 window.addEventListener(wheel, (e) > {e.preventDefault(); })这是因为现代浏览器使用 Passive 事件监听器&#xff0c;默认启用了 passive 模式以确保性能&#xff0c;不会调用 pr…

Cancer Cell|最新发表的单细胞成纤维细胞分析代码,速来学习!!!

简介 成纤维细胞在维持组织稳态、应对炎症和纤维化状况、帮助伤口愈合以及促进癌症进展的复杂舞蹈中起着关键作用。在癌症领域&#xff0c;成纤维细胞已成为肿瘤微环境&#xff08;TME&#xff09;中的核心人物&#xff0c;发挥着多方面的作用。这些作用包括细胞外基质&#xf…

【深度学习实战—12】:基于MediaPipe的手势识别

✨博客主页&#xff1a;王乐予&#x1f388; ✨年轻人要&#xff1a;Living for the moment&#xff08;活在当下&#xff09;&#xff01;&#x1f4aa; &#x1f3c6;推荐专栏&#xff1a;【图像处理】【千锤百炼Python】【深度学习】【排序算法】 目录 &#x1f63a;一、Med…

Java设计模式梳理:行为型模式(策略,观察者等)

行为型模式 行为型模式关注的是各个类之间的相互作用&#xff0c;将职责划分清楚&#xff0c;使得我们的代码更加地清晰。 策略模式 策略模式太常用了&#xff0c;所以把它放到最前面进行介绍。它比较简单&#xff0c;我就不废话&#xff0c;直接用代码说事吧。 下面设计的…

电能表预付费系统-标准传输规范(STS)(16)

6.3.9 MPL: MaximumPowerLimit&#xff08;最大功率限制&#xff09; The maximum power limit field is a 1 6-bit field that indicates the maximum power that the load may draw, in watts. Calculation of this field is identical to that of the TransferAmount field…

【JavaEE】——自定义协议方案、UDP协议

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;自定义协议 1&#xff1a;自定义协议 &#xff08;1&#xff09;交互哪些信息 &…

数据库设计与开发—初识SQLite与DbGate

一、SQLite与DbGate简介 &#xff08;一&#xff09;SQLite[1][3] SQLite 是一个部署最广泛、用 C 语言编写的数据库引擎&#xff0c;属于嵌入式数据库&#xff0c;其作为库被软件开发人员嵌入到应用程序中。 SQLite 的设计允许在不安装数据库管理系统或不需要数据库管理员的情…

C++中的继承(1)

1.继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许我们在保持原有类特性的基础上进行扩展&#xff0c;增加⽅法(成员函数)和属性(成员变量)&#xff0c;这样产生新的类&#xff0c;称派生类&#xff08;也被称为子类&…

Vue 3集成海康Web插件实现视频监控

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;组件封装篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来组件封装篇专栏内容:Vue 3集成海康Web插件实现视频监控 引言 最近在项目中使用了 Vue 3 结合海康Web插件来实…

Django项目创建

安装 pip install django 创建项目 首先打开powershell打开项目与创建到的文件夹 django-admin startproject django_demo01 django-admin startproject 项目名 多出了一个django_demo01的文件夹&#xff0c;这就是我们的项目了 打开项目文件夹&#xff0c;发现一个文件和…

必读推荐:掌握大模型应用的精华书籍,非常详细收藏我这一篇就够了

在这个信息爆炸的时代&#xff0c;人工智能正以前所未有的速度和规模渗透到我们生活的方方面面。其中&#xff0c;大模型应用作为 AI 领域的一大亮点&#xff0c;不仅在学术界引起广泛关注&#xff0c;更在工业界展现出巨大的应用潜力。从自然语言处理到图像识别&#xff0c;从…

最新必应Bing开户条件、流程及注意事项介绍

有效的广告推广对于企业提升品牌影响力和市场占有率至关重要。微软旗下的必应Bing搜索引擎&#xff0c;作为全球知名的搜索平台之一&#xff0c;为企业提供了精准、高效的广告推广服务。那么&#xff0c;如何在必应上开设广告账户呢&#xff1f;下面将详细介绍必应广告开户的条…

springboot 整合 快手 移动应用 授权 发布视频 小黄车

前言&#xff1a; 因快手文档混乱&#xff0c;官方社区技术交流仍有很多未解之谜&#xff0c;下面3种文档的定义先区分。 代码中的JSON相关工具均用hutool工具包 1.快手 移动双端 原生SDK 文档https://mp.kuaishou.com/platformDocs/develop/mobile-app/ios.html 2.快手 Api 开…

探索光耦:光耦——不间断电源(UPS)系统中的安全高效卫士

在现代社会&#xff0c;不间断电源&#xff08;UPS&#xff09;系统已成为保障关键设备和数据安全的关键设施&#xff0c;广泛应用于企业数据中心、家庭电子设备等场景。UPS能在电力中断或波动时提供稳定电力&#xff0c;确保设备持续运行。而在这套系统中&#xff0c;光耦&…

深入理解AQS:并发编程中的利器及其在业务场景中的应用

1. 什么是AQS&#xff08;AbstractQueuedSynchronizer&#xff09;&#xff1f; AQS&#xff0c;全称为AbstractQueuedSynchronizer&#xff0c;是Java并发包中核心的基础框架&#xff0c;用于构建锁和同步器。它是java.util.concurrent.locks包中的基础组件&#xff0c;为多个…

屏幕画面卡住不动声音正常怎么办?电脑屏幕卡住不动解决方法

在数字时代&#xff0c;电脑作为我们日常生活与工作中不可或缺的伙伴&#xff0c;偶尔也会遇到一些小状况。其中&#xff0c;“屏幕画面卡住不动&#xff0c;但是声音依然正常”的情况就是一种常见的问题。本文将探讨这一现象的原因&#xff0c;并提供几种可能的解决方案&#…

FSCapture 9.3 | 全能截图与录屏解决方案。

FastStone Capture 是一款轻量级但功能全面的屏幕捕捉工具&#xff0c;能够轻松捕获并标注屏幕上的一切内容&#xff0c;包括窗口、对象、菜单、全屏、矩形/自由区域以及滚动窗口或网页。此外&#xff0c;它还支持录制屏幕活动、声音和网络摄像头&#xff0c;并将这些内容保存为…