PUPANVR-UI主菜单及设置窗体框架(9)

PUPA NVR UI主菜单及设置窗体框架

在设计UI时,竟量把数据、控制、显示,分开,即MVC的一个模式吧!使用MVC这样的模式思想,会让代码简洁不少,逻辑也很清析!
具体的代码见: PUPANVR这个项目 https://gitee.com/jhting/pupanvr.git

UI主菜单

主菜单设计为NVR上比较传统的界面,宫格方式,如下图:
在这里插入图片描述

定义菜单数据(M)

对于这样的菜单项目,每一项目信息要求基本是一样的,如有一个标题,有一个图标,对应的一个操作,

所以,可以定义一个针对项目定一个结构体:

typedef struct{int     menuItemID;char    menuItemText[256];char    menuItemImage[256];char    menuItemFontAwesome[10];StViewConfigWinBaseFrameParamsItemInfo* itemConfigInfo;
}StMainMenuItemInfo;

然后针对产品所有主菜单定义一个列表:

StMainMenuItemInfo gStMainMenuItemInfoList[] = {{1, "基本设置",     "",     "\uf2c3", testiteminfo},{2, "通道管理",     "",     "\uf03d", NULL},{4, "录相回放",     "",     "\uf1c8", NULL},{4, "存储管理",     "",     "\uf1c0", NULL},{5, "报警设置",     "",     "\uf071", NULL},{6, "网络设置",     "",     "\uf26b", NULL},{7, "云平台",       "",     "\uf0ee", NULL},{8, "设备设置",     "",     "\uf085", NULL},
};

这样后续,如果新增、删除、或修改菜单项目,只需要修改这个列表数据即可!

在以上的数据结构中 StMainMenuItemInfo :

​ menuItemID: 定义菜单对应的ID值,这样在单击时,通过这个ID找到对应的数据;

​ menuItemText: 菜单显示的名称;

​ menuItemImage:菜单图片,如果指定图标;

​ menuItemFontAwesome: 没有图标时,使用fontAwesome的图标;

​ itemConfigInfo: 菜单里对应的菜单二级菜单项目,这个对应数据会设置具体的菜单设置框加中!这个定义见 TViewConfigWinBaseFrame 定义!

定义菜单显示(V)

定义好上面的数据后,再创建UI的绘制!

对应的这个窗体类为:TViewSysSetFrame

LVGL提供了方便的LAYOUT功能,所以使用行、列的布局功能,可以方便的自动排布好!

在TViewSysSetFrame即初始化整个UI的控件创建及布局、数据加载!

void TViewSysSetFrame::viewMenuItemInit()
{unsigned int i = 0;int itemWidth = 120;int itemHeight = 120;int colNumber = 4;//int rowNumber = 2;int col = 0;int row = 0;static lv_coord_t col_dsc[] = {itemWidth, itemWidth, itemWidth, itemWidth, LV_GRID_TEMPLATE_LAST};static lv_coord_t row_dsc[] = {itemHeight, itemHeight, LV_GRID_TEMPLATE_LAST};StMainMenuItemInfo* pItem = NULL;lv_obj_set_style_pad_all(m_viewHandle, 0, 0);lv_obj_t* lvObjMenuPanel = lv_obj_create(m_viewHandle);int ctwidth = lv_obj_get_content_width(m_viewHandle) - 20;int ctheight = lv_obj_get_content_height(m_viewHandle) * 0.8;lv_obj_set_size(lvObjMenuPanel, ctwidth, ctheight);lv_obj_center(lvObjMenuPanel);lv_obj_set_style_border_width(lvObjMenuPanel, 0, 0);lv_obj_set_style_radius(lvObjMenuPanel, 0, 0);lv_obj_set_style_bg_color(lvObjMenuPanel, TViewStyle::DialogFrameBgColor, 0);lv_obj_set_layout(lvObjMenuPanel, LV_LAYOUT_GRID);lv_obj_set_style_grid_column_dsc_array(lvObjMenuPanel, col_dsc, 0);lv_obj_set_style_grid_row_dsc_array(lvObjMenuPanel, row_dsc, 0);lv_obj_set_grid_align(lvObjMenuPanel, LV_GRID_ALIGN_SPACE_AROUND, LV_GRID_ALIGN_SPACE_AROUND);for(i = 0; i < sizeof(gStMainMenuItemInfoList) / sizeof(gStMainMenuItemInfoList[0]); i++){col = i % colNumber;row = i / colNumber;pItem = &gStMainMenuItemInfoList[i];//item lv_obj_t* lvObjItem = lv_obj_create(lvObjMenuPanel);lv_obj_set_style_bg_color(lvObjItem, TViewStyle::DialogFrameBgColor, 0);lv_obj_set_scrollbar_mode(lvObjItem, LV_SCROLLBAR_MODE_OFF);lv_obj_set_style_border_width(lvObjItem, 0, 0);lv_obj_set_style_pad_all(lvObjItem, 0, 0);/*设置布局*/lv_obj_set_layout(lvObjItem, LV_LAYOUT_FLEX);lv_obj_set_flex_flow(lvObjItem, LV_FLEX_FLOW_COLUMN);/*让项目中的文本和图片分别都居中排列,这样设置后,图片,文本项都自动在水平,垂直上都居中自动分配空间了*/lv_obj_set_flex_align(lvObjItem, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);lv_obj_set_user_data(lvObjItem, pItem);lv_obj_add_event_cb(lvObjItem, _menuitem_event_process, LV_EVENT_PRESSED, this);lv_obj_add_event_cb(lvObjItem, _menuitem_event_process, LV_EVENT_RELEASED, this);lv_obj_add_event_cb(lvObjItem, _menuitem_event_process, LV_EVENT_CLICKED, this);//imagelv_obj_t* plabItemImg = lv_label_create(lvObjItem);lv_obj_set_style_text_color(plabItemImg, lv_color_hex(0xffffff), 0);lv_obj_set_style_text_font(plabItemImg, TViewFontUtils::getInstance()->getViewFont(VF_FONT_FontAwesome, 50), 0);lv_label_set_text(plabItemImg, pItem->menuItemFontAwesome);//textlv_obj_t* plabItemText = lv_label_create(lvObjItem);lv_obj_set_style_text_color(plabItemText, lv_color_hex(0xffffff), 0);    lv_obj_set_style_text_font(plabItemText, TViewFontUtils::getInstance()->getDefaultFont(16, 0), 0);lv_label_set_text(plabItemText, pItem->menuItemText);/*设置项目在行,列位置*/lv_obj_set_grid_cell(lvObjItem, LV_GRID_ALIGN_STRETCH, col, 1,LV_GRID_ALIGN_STRETCH, row, 1);}//TViewFontUtils::getInstance()->releaseViewFont(VF_FONT_FontAwesome, 50, 0);
}

以上代码根据定义好的 gStMainMenuItemInfoList 这个菜单数据列表,自动的把每一项创建及排列好!对 lvObjItem 具体项目分别绑定具体的事件!

定义菜单操作逻辑©

事件控制如下:

void TViewSysSetFrame::__menuitem_event_process(lv_event_t *event)
{lv_obj_t *obj = event->target;  if(event->code == LV_EVENT_PRESSED){lv_obj_set_style_bg_color(obj, lv_palette_darken(LV_PALETTE_BLUE, 2), 0);}else if(event->code == LV_EVENT_RELEASED){  lv_obj_set_style_bg_color(obj, TViewStyle::DialogFrameBgColor, 0);}else if(event->code == LV_EVENT_CLICKED){  StMainMenuItemInfo* pItem = (StMainMenuItemInfo*)obj->user_data;if(pItem){_menuitem_clicked_process(pItem->menuItemID);     }}
}void TViewSysSetFrame::_menuitem_event_process(lv_event_t *event)
{TViewSysSetFrame* obj = (TViewSysSetFrame*)event->user_data;    obj->__menuitem_event_process(event);
}void TViewSysSetFrame::_menuitem_clicked_process(int id)
{TViewConfigWinBaseFrame* win = NULL;StMainMenuItemInfo* itemInfo = getMainMenuItemInfoByID(id);if(itemInfo){win = new TViewConfigWinBaseFrame();win->setViewConfigWinTitle(itemInfo->menuItemText);win->setViewConfigWinBaseFrameParams(itemInfo->itemConfigInfo);win->viewShow();}}

通过以上代码,一个主菜单窗体即完成了!代码量很少!主要在设计UI时,使用MVC这样的模式思想,会让代码简洁不少,逻辑也很清析!

具体设置界面框架

在同一个产品中,每一个设置界面的主体框架的风格应该是一致的,所以就没有必要,每一个设置界面,都重复的窗体界面的代码!

这里先造一个模子,后面每一个设置界面套在这个模子里即可!

具体设置窗体的风格如下 :

在这里插入图片描述

上方为一个标题栏:中间显示窗体名称,右边显示一个关闭按钮,可以通过这个按钮退出!

窗体的内容区左、右布局,左边为一个二级菜单列表项,右边为二级菜单的内容显示区。

有了上面的布局后,代码也比较简单: TViewConfigWinBaseFrame 中先创建一个窗体,先上、下布局的PANEL,再对上下的Panel分另左、右布局分别创建!

TViewConfigWinBaseFrame::TViewConfigWinBaseFrame()
{lv_obj_set_width(m_viewHandle, 800);lv_obj_set_height(m_viewHandle, 600);m_view_titleObj = NULL;m_viewMenuItemList = NULL;m_lastListItemBtnObj = NULL;m_lvObjBodyRightPanel = NULL;m_title = "";m_lastListItemBtnObj = NULL;m_stViewConfigWinBaseFrameParams = NULL;lv_obj_center(m_viewHandle);lv_obj_refr_size(m_viewHandle);lv_obj_set_scrollbar_mode(m_viewHandle, LV_SCROLLBAR_MODE_OFF);lv_obj_clear_flag(m_viewHandle, LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_style_pad_all(m_viewHandle, 0, 0);TViewStyle::getInstance()->setDalogModelViewWindowStyle(this);lv_obj_set_layout(m_viewHandle, LV_LAYOUT_FLEX);lv_obj_set_flex_flow(m_viewHandle, LV_FLEX_FLOW_COLUMN_WRAP);lv_obj_set_flex_align(m_viewHandle, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);lv_obj_set_style_pad_gap(m_viewHandle, 0, 0);/*top panel*/lv_obj_t* lvObjTopPanel = lv_obj_create(m_viewHandle);lv_obj_set_width(lvObjTopPanel, this->getViewWidth());lv_obj_set_style_bg_color(lvObjTopPanel, lv_palette_darken(LV_PALETTE_BLUE_GREY, 2), 0);lv_obj_set_height(lvObjTopPanel, TOPPANNEL_HEIGHT);lv_obj_set_width(lvObjTopPanel, lv_obj_get_width(m_viewHandle));lv_obj_set_style_border_width(lvObjTopPanel, 0, 0);lv_obj_set_style_pad_all(lvObjTopPanel, 0, 0);lv_obj_set_style_radius(lvObjTopPanel, 0, 0);m_view_titleObj = lv_label_create(lvObjTopPanel);lv_obj_set_style_text_color(m_view_titleObj, lv_color_hex(0xffffff), 0);    lv_obj_set_style_text_font(m_view_titleObj, TViewFontUtils::getInstance()->getDefaultFont(20, 0), 0);lv_label_set_text(m_view_titleObj, "基本框架");lv_obj_set_style_text_align(m_view_titleObj, LV_TEXT_ALIGN_CENTER, 0);lv_obj_center(m_view_titleObj);/*关闭按钮*/lv_obj_t* btnObj = lv_btn_create(lvObjTopPanel);lv_obj_set_width(btnObj, TOPPANNEL_HEIGHT - 10);lv_obj_set_height(btnObj, TOPPANNEL_HEIGHT - 10);lv_obj_set_pos(btnObj, this->getViewWidth() - TOPPANNEL_HEIGHT + 10, 5);lv_obj_set_style_bg_color(btnObj, lv_palette_darken(LV_PALETTE_BLUE_GREY, 2), 0);lv_obj_set_style_border_width(btnObj, 0, 0);lv_obj_set_style_pad_all(btnObj, 0, 0);lv_obj_set_style_radius(btnObj, 0, 0);lv_obj_add_event_cb(btnObj, _closeBtn_event_handler, LV_EVENT_CLICKED, this);lv_obj_t * labelbtn = lv_label_create(btnObj);lv_obj_set_style_text_font(labelbtn, TViewFontUtils::getInstance()->getDefaultFont(20, 0), 0);lv_label_set_text(labelbtn, " X ");lv_obj_center(labelbtn);/*body*/lv_obj_t* lvObjBodyPanel = lv_obj_create(m_viewHandle);lv_obj_set_width(lvObjBodyPanel, this->getViewWidth());lv_obj_set_flex_grow(lvObjBodyPanel, 1);lv_obj_set_style_bg_color(lvObjBodyPanel, TViewStyle::DialogFrameBgColor, 0);lv_obj_set_style_border_width(lvObjBodyPanel, 0, 0);lv_obj_set_style_pad_all(lvObjBodyPanel, 0, 0);lv_obj_set_style_radius(lvObjBodyPanel, 0, 0);view_bodyPanelInit(lvObjBodyPanel);
}TViewConfigWinBaseFrame::~TViewConfigWinBaseFrame()
{LOG(INFO) << "TViewConfigWinBaseFrame:" << m_title  << ", close!" << endl;
}void TViewConfigWinBaseFrame::setViewConfigWinTitle(const char* titleText)
{m_title = titleText;lv_label_set_text(m_view_titleObj, titleText);
}void TViewConfigWinBaseFrame::setViewConfigWinBaseFrameParams(StViewConfigWinBaseFrameParamsItemInfo params[])
{m_stViewConfigWinBaseFrameParams = params;view_configLoad();
}void TViewConfigWinBaseFrame::view_configLoad()
{int i = 0;lv_obj_t* btn = NULL;if(!m_stViewConfigWinBaseFrameParams){return;}if(!m_viewMenuItemList){return;}StViewConfigWinBaseFrameParamsItemInfo* item = &m_stViewConfigWinBaseFrameParams[i++];while(item){if(!item->itemText){break;}if(strlen(item->itemText) == 0){break;}printf("add lv_list_add_btn:%s\n", item->itemText);btn = lv_list_add_btn(m_viewMenuItemList, NULL, item->itemText);lv_obj_set_style_border_width(btn, 0, 0);lv_obj_set_style_pad_all(btn, 20, 0);lv_obj_set_style_text_font(btn, TViewFontUtils::getInstance()->getDefaultFont(16, 0), 0);lv_obj_set_style_bg_color(btn, lv_palette_darken(LV_PALETTE_BLUE_GREY, 3), 0);lv_obj_set_style_text_color(btn, lv_color_hex(0xFFFFFF), 0);/*set item to button userdata, when button click can get item config!*/lv_obj_set_user_data(btn, item);lv_obj_add_event_cb(btn, _menuItem_event_handler, LV_EVENT_CLICKED, this);item = &m_stViewConfigWinBaseFrameParams[i++];}
}void TViewConfigWinBaseFrame::view_bodyPanelInit(lv_obj_t* bodyPanel)
{lv_obj_set_layout(bodyPanel, LV_LAYOUT_FLEX);lv_obj_set_flex_flow(bodyPanel, LV_FLEX_FLOW_ROW);lv_obj_set_flex_align(bodyPanel, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);lv_obj_set_style_pad_gap(bodyPanel, 0, 0);lv_obj_refr_size(m_viewHandle);lv_obj_refr_size(bodyPanel);//leftlv_obj_t* lvObjBodyLeftPanel = lv_obj_create(bodyPanel);    lv_obj_set_width(lvObjBodyLeftPanel, 150);lv_obj_set_height(lvObjBodyLeftPanel, lv_obj_get_height(m_viewHandle) - TOPPANNEL_HEIGHT - 5); lv_obj_set_style_border_width(lvObjBodyLeftPanel, 0, 0);lv_obj_set_style_pad_all(lvObjBodyLeftPanel, 0, 0);lv_obj_set_style_radius(lvObjBodyLeftPanel, 0, 0);  lv_obj_set_style_bg_color(lvObjBodyLeftPanel, lv_palette_darken(LV_PALETTE_BLUE_GREY, 3), 0);//rightm_lvObjBodyRightPanel = lv_obj_create(bodyPanel); lv_obj_set_flex_grow(m_lvObjBodyRightPanel, 1);   lv_obj_set_height(m_lvObjBodyRightPanel, lv_obj_get_height(m_viewHandle) - TOPPANNEL_HEIGHT - 5); lv_obj_set_style_border_width(m_lvObjBodyRightPanel, 0, 0);lv_obj_set_style_pad_all(m_lvObjBodyRightPanel, 0, 0);lv_obj_set_style_radius(m_lvObjBodyRightPanel, 0, 0); lv_obj_set_style_bg_color(m_lvObjBodyRightPanel, TViewStyle::DialogFrameBgColor, 0);//left listm_viewMenuItemList = lv_list_create(lvObjBodyLeftPanel);lv_obj_set_width(m_viewMenuItemList, 150);lv_obj_set_style_border_width(m_viewMenuItemList, 0, 0);lv_obj_set_style_pad_all(m_viewMenuItemList, 0, 0);lv_obj_set_style_radius(m_viewMenuItemList, 0, 0); //lv_obj_set_size(list2, lv_pct(40), lv_pct(100));//lv_obj_align(list, LV_ALIGN_TOP_RIGHT, 0, 0);lv_obj_set_style_bg_color(m_viewMenuItemList, lv_palette_darken(LV_PALETTE_BLUE_GREY, 3), 0);lv_obj_set_flex_flow(m_viewMenuItemList, LV_FLEX_FLOW_COLUMN);view_configLoad();
}void TViewConfigWinBaseFrame::_closeBtn_event_handler(lv_event_t* event)
{TViewConfigWinBaseFrame* obj = (TViewConfigWinBaseFrame*)event->user_data;    obj->viewHide();delete obj;   /*delete instance of TViewConfigWinBaseFrame*/
}void TViewConfigWinBaseFrame::_menuItem_event_handler(lv_event_t* event)
{TViewConfigWinBaseFrame* obj =  (TViewConfigWinBaseFrame*)event->user_data;if(obj->m_lastListItemBtnObj){lv_obj_set_style_bg_color(obj->m_lastListItemBtnObj, lv_palette_darken(LV_PALETTE_BLUE_GREY, 3), 0);}obj->m_lastListItemBtnObj =  event->target;printf("_menuItem_event_handler click!\n");lv_obj_set_style_bg_color(obj->m_lastListItemBtnObj, TViewStyle::DialogFrameBgColor, 0);StViewConfigWinBaseFrameParamsItemInfo* item = (StViewConfigWinBaseFrameParamsItemInfo*)lv_obj_get_user_data(obj->m_lastListItemBtnObj);if(!item){return;}if(item && item->funGetFrame){item->funGetFrame(obj->m_lvObjBodyRightPanel);}}

TViewConfigWinBaseFrame 这个UI类中对外提供了两个方法,一个是设置当前窗体的标题,及具体内容项目:

void    setViewConfigWinTitle(const char* titleText);
void    setViewConfigWinBaseFrameParams(StViewConfigWinBaseFrameParamsItemInfo params[]);

在回到 TViewSysSetFrame 这个类中的事件中,主菜单中的一个项目单击时,具体的窗体,即是如下创建的:

void TViewSysSetFrame::_menuitem_clicked_process(int id)
{TViewConfigWinBaseFrame* win = NULL;StMainMenuItemInfo* itemInfo = getMainMenuItemInfoByID(id);if(itemInfo){win = new TViewConfigWinBaseFrame();win->setViewConfigWinTitle(itemInfo->menuItemText);win->setViewConfigWinBaseFrameParams(itemInfo->itemConfigInfo);win->viewShow();}}

对于设置窗体的关闭及窗体对像的Free,是通过 TViewConfigWinBaseFrame 中的 _closeBtn_event_handler 事件触发的!

void TViewConfigWinBaseFrame::_closeBtn_event_handler(lv_event_t* event)
{TViewConfigWinBaseFrame* obj = (TViewConfigWinBaseFrame*)event->user_data;    obj->viewHide();delete obj;   /*delete instance of TViewConfigWinBaseFrame*/
}

总体的原则即,在新增加菜单及新增设置界面时,只需要修改对应的菜单数据配置即可!不需要改动其他的代码部分!这样来方便开发及维护!

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

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

相关文章

第三次作业

自己实现扫描全盘的函数 def scan_disk(dir): global count,dir_count if os.path.isdir(dir): files os.listdir(dir) for file in files: print(file) dir_count 1 if os.path.isdir(dir os.sep file): …

等精度频率计verilog,quartus仿真视频,原理图,代码

名称&#xff1a;等精度频率计设计verilog quartus仿真 软件&#xff1a;Quartus 语言&#xff1a;Verilog 要求&#xff1a; A&#xff1a;测量范围信号:方波 频率:100Hz~1MHz; B&#xff1a;测试误差:<0.1%(全量程) C&#xff1a;时钟频率:50kHz D&#xff1a;预闸…

(2021|NIPS,VQ-VAE,精度瓶颈松弛,三明治层归一化,CapLoss)CogView:通过转换器掌握文本到图像的生成

CogView: Mastering Text-to-Image Generation via Transformers 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 0. 摘要 通用领域中的文本到图像生成长期以来一直是一个悬而未决的问题&#…

十、pygame小游戏开发

目录 一、安装pygame二、pygame快速入门2.1 坐标系认识2.2 创建游戏主窗口2.3 实现图像绘制2.4 游戏循环和游戏时钟2.5 简单动画实现的实现2.6 监听事件2.7 精灵和精灵组三、游戏框架搭建3.1 实现飞机大战主游戏类3.2 完成游戏初始化部分3.3 使用常量代替固定的数值3.4 完成游戏…

2023年DDoS攻击发展趋势的分析和推断

DDoS是一种非常“古老”的网络攻击技术&#xff0c;随着近年来地缘政治冲突对数字经济格局的影响&#xff0c;DDoS攻击数量不断创下新高&#xff0c;其攻击的规模也越来越大。日前&#xff0c;安全网站Latest Hacking News根据DDoS攻击防护服务商Link11的统计数据&#xff0c;对…

Java代码hello word

一、安装java环境 开始学习java之前&#xff0c;我们的第一步就是安装java环境&#xff0c;即常说的JDK和JRE&#xff0c;此处就不在详细介绍配置环境过程&#xff0c;可以到网上搜索java开发环境配置。 二、编写第一个程序 工具&#xff1a; 常用的java编写工具有IDE、Notep…

机器学习:随机森林

集成学习 集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习方法&#xff0c;通过将多个基本学习算法的预测结果进行组合&#xff0c;以获得更好的预测性能。集成学习的基本思想是通过结合多个弱分类器或回归器的预测结果&#xff0c;来构建一个更强大的集成模…

Window Anaconda 安装pytorch 启用cuda 终究手段

1.首先你的电脑要有NVIDIA 的显卡.没有就走吧,你如果不是window &#xff0c;也走吧&#xff0c;不一定教程管用。 2.然后要明白&#xff0c;有两种CUDA版本&#xff0c;一个叫运行时api&#xff0c;一个是驱动api 2.1 运行时cuda 版本查看 &#xff08;是你跑深度学习模型或其…

Android用户登录与数据存储:从权限请求到内外部存储的完整实践【完整实践步骤、外部存储、内部存储】

步骤 1: 登录页面布局 在 MainActivity 中实现用户登录功能&#xff0c;首先创建一个布局文件 activity_main.xml 包含用户名和密码的输入字段以及登录按钮。 <!-- activity_main.xml --> <LinearLayoutxmlns:android"http://schemas.android.com/apk/res/andr…

单元测试该怎么写

单元测试对于开发人员来说很熟悉&#xff0c;各种语言都提供了单元测试的框架&#xff0c;用于自动化执行单元测试并生成测试报告。它通常提供了一组API和工具&#xff0c;使开发人员能够编写和运行测试用例&#xff0c;比较预期行为和实际行为之间的差异&#xff0c;并准确地识…

【已验证】微信小程序介绍及创建过程23.10.08

1、环境准备 开发微信⼩程序之前&#xff0c;必须要准备好相应的环境 1.1.注册账号 建议使用全新的邮箱&#xff0c;没有注册过其他小程序或者公众号的。访问注册⻚⾯&#xff0c;耐⼼完成注册即可。 1.2.获取APPID 由于登录&#xff0c;然后获取APPID 2.开发工具 下载地…

ElementUI结合Vue完成主页的CUD(增删改)表单验证

目录 一、CUD ( 1 ) CU讲述 ( 2 ) 编写 1. CU 2. 删除 二、验证 前端整合代码 : 一、CUD 以下的代码基于我博客中的代码进行续写 : 使用ElementUI结合Vue导航菜单和后台数据分页查询 ( 1 ) CU讲述 在CRUD操作中&#xff0c;CU代表创建&#xff08;Create&#xff09…

设备搭建(waf、蜜罐、ids和ips)

文章目录 防火墙waf网闸蜜罐idsips 防火墙 DMZ区域叫非军事化区减&#xff0c;DMZ有web服务或者MySQL服务&#xff0c;从互联网到dmz的流量一般不拦截&#xff08;因为需要互联网用户访问web服务&#xff09;&#xff0c;如果dmz沦陷&#xff0c;攻击者想要继续横向移动到内网…

Vue中实现自定义编辑邮件发送到指定邮箱(纯前端实现)

formspree里面注册账号 注册完成后进入后台新建项目并且新建表单 这一步完成之后你将得到一个地址 最后就是在项目中请求这个地址 关键代码如下&#xff1a; submitForm() {this.fullscreenLoading true;this.$axios({method: "post",url: "https://xxxxxxx…

什么是数据库锁(Lock)?有哪些类型的锁

数据库锁&#xff08;Lock&#xff09;&#xff1a;保护数据完整性与并发性的关键 数据库锁&#xff08;Lock&#xff09;是在数据库管理系统中用于管理并发访问数据的重要机制。它们确保了多个用户或事务可以同时访问数据库&#xff0c;同时保护数据的完整性。在本文中&#…

7.wifi开发【智能家居:终】,实践总结:智能开关,智能采集温湿,智能灯。项目运行步骤与运行细节,技术归纳与提炼,项目扩展

一。项目运行步骤与运行细节 1.项目运行步骤&#xff08;一定有其他的运行方式&#xff0c;我这里只提供一种我现在使用的编译方式&#xff09; &#xff08;1&#xff09;项目运行使用软件与技术&#xff1a; 1.Virtual linux 使用这个虚拟机进行程序的编译 2.Makefile与shl…

【Navicat】win 10 / win 11:Navicat 15 安装完整教程(navicat 连接 mysql 出现 2059 报错问题解决)

目录 一、Navicat 连接 mysql 出现 2059 报错问题解决 二、Navicat 15 的下载 三、Navicat 15 的安装 四、Navicat 15 的使用 一、Navicat 连接 mysql 出现 2059 报错问题解决 之前使用的是完整版本 navicat 12&#xff0c;但是随着 MySQL 的升级&#xff0c;再连接 MySQL…

【SpringCloud】认识微服务

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 认识微服务 一、 服务架构演变1.1 单体架构…

库存管理与策略模式

库存管理是个难题&#xff0c;涉及到采购、销售、仓储、门店、网站订单各个环节&#xff0c;实物库存和系统库存很难保证完全一致&#xff0c;记得系统刚上线第一天&#xff0c;因为实物库存与导入系统的库存有差异&#xff0c;系统又做了限制系统库存必须大于0才允许销售普通订…

Spring的beanName生成器AnnotationBeanNameGenerator

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…