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

news2024/9/25 1:23:04

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);

        //image
        lv_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);
    

        //text
        lv_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);
    //left
    lv_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);

    //right
    m_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 list
    m_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.coloradmin.cn/o/1079296.html

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

相关文章

北邮22级信通院数电:Verilog-FPGA(4)第三周实验:按键消抖、呼吸灯、流水灯 操作流程注意事项

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.注意事项 二.按键消抖 2.1 LED_deboun…

面试题补充

1.公司有几套环境&#xff1a;测试环境&#xff08;测试人员使用&#xff09;&#xff0c;开发环境&#xff08;开发人员使用&#xff09;&#xff0c;预生产环境&#xff08;测试人员使用&#xff09;&#xff0c;生产环境&#xff08;用户使用&#xff09; 2.作为一名测试&a…

关于GP7 release版在麒麟V10信创操作系统编译不过的问题解决

背景 大家期盼已久的Greenplum 7 最终版终于发布了&#xff01;好消息&#xff01;&#xff01; 很多同学已经忍不住想快速试用GP 7新版本了&#xff0c;同时&#xff0c;为了满足信创要求&#xff0c;需要在国产的操作系统服务器上运行GP。 然后官方的GP 7并没有明确声明支持…

run_main_loop 到 cmd_process处理说明三

一. run_main_loop 到 cmd_process处理过程 之前文章了解了 uboot的命令格式组成。本文简单分析下 cmd_process函数对 uboot命令的处理过程。 本文继上一篇文章的学习&#xff0c;地址如下&#xff1a; uboot启动流程-run_main_loop 到 cmd_process处理说明二-CSDN博客 二. …

扎克伯格:希望借助数字助理、智能眼镜和AI帮助推动元宇宙发展

Meta推出了新的人工智能工具和名人代言的数字助手&#xff0c;首席执行官马克扎克伯格希望这些工具可以帮助推动元宇宙的发展。 9月30日消息&#xff0c;据外媒报道&#xff0c;Meta推出了新的人工智能工具和名人代言的数字助手&#xff0c;首席执行官马克扎克伯格希望这些工具…

Swagger3.0 与spring boot2.7x 整合避免swagger2.0与boot2.7冲突

注释掉2.0引入的俩包 直接引入3.0 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency> swagger配置文件粘贴即用哦 import org.springfram…

提取Android盒子dtb文件

概述 最近从某鱼上掏了一个CM201-1 YS的盒子&#xff0c;动手倒腾倒腾&#xff0c;准备安装Armbian&#xff0c;用来做矿机&#xff0c;但该型号的盒子ophub上面没有完全适配的镜像&#xff0c;故而想尝试下&#xff0c;看能否整个适配镜像出来。 操作系统 Windows Linux 工…

JMeter—逻辑控制器

JMeter逻辑控制器 JMeter逻辑控制器可以对元件的执行逻辑进行控制&#xff0c;除仅一次控制器外&#xff0c;其他可以嵌套别的种类的逻辑控制器  一、ForEach控制器 定义一个循环规则&#xff0c;关键参数说明&#xff1a;   输入变量前缀&#xff1a;可以在“用户自定义的…

10月TIOBE榜Java跌出前三!要不我转回C#吧

前言 Java又要完了&#xff0c;又要没了&#xff0c;你没看错&#xff0c;10月编程语言榜单出炉&#xff0c;Java跌出前三&#xff0c;并且即将被C#超越&#xff0c;很多资深人士预测只需两个月&#xff0c;Java就会跌出前五。 看到这样的文章&#xff0c;作为一名Java工程师我…

Cmake 3.27.5 发布,开源构建系统

导读CMake 是一个跨平台的自动化构建系统&#xff0c;它使用一个名为 CMakeLists.txt 的文件来描述构建过程&#xff0c;可以产生标准的构建文件&#xff0c;如 Unix 的 Makefile 或 Windows Visual C 的 projects/workspaces 。文件 CMakeLists.txt 需要手工编写&#xff0c;也…

静电地桩的安装和使用说明

静电地桩的安装使用需要遵循以下步骤&#xff1a; 确定静电地桩的位置&#xff1a;静电地桩应该安装在需要消除静电的区域&#xff0c;如易燃易爆场所、电子厂、医院等。在安装前需要对地面进行清洁和处理&#xff0c;确保地面平整、干燥、无灰尘等杂物。 安装静电地桩&#xf…

FPM-FORM

FPM DEMO&#xff1a;FPM_OVP_COMPONENT FORM&#xff1a; IF_FPM_GUIBB_FORM TABLE LIST&#xff1a; IF_FPM_GUIBB_LIST TREE&#xff1a; IF_FPM_GUIBB_TREE SEARCH LIST&#xff1a; IF_FPM_GUIBB_SEARCH 需求&#xff1a;FPM启动时默认从EKPO去一条采购订单数据&#xff…

想要用Chat GPT写申请文书?先看各大名校招生官对它的态度是什么?

新的申请季已经正式开始&#xff0c;一些热门项目的ED截止日期也不再遥远&#xff0c;因此很多准留学生们都已经开始了关于文书的创作。 而随着科技的不断发展&#xff0c;以ChatGPT为首的一众AI工具也作为一种辅助手段愈发融入了我们的生活。 那么不免就会有一些同学在准备申…

提升后端API性能的几种解决方案

&#x1f514;目的 提升后端API性能的主要目的是为了提高系统整体的响应速度、并发能力以及可用性。主要原因包括: 提高用户体验 后端API性能好可以减少响应延迟,给用户流畅的体验。 提高系统吞吐量 优化API性能可以提高系统的整体吞吐量,处理更多用户请求。 节省服务器资源…

wps演示时图片任意位置拖动

wps演示时图片任意位置拖动 1.wps11.1版本&#xff0c;其他版本的宏插件可以自己下载。2.先确认自己的wps版本是不是11.13.检查是否有图像工具4.检查文件格式和安全5.开发工具--图像6.选中图像控件&#xff0c;右击选择查看代码&#xff0c;将原有代码删除&#xff0c;将下边代…

经典面试题第十更---instanceof与typeof

前言&#xff1a; &#x1f921; 作者简介&#xff1a;我是Morning&#xff0c;计算机的打工人&#xff0c;想要翻身做主人 &#x1f648; &#x1f648; &#x1f648; &#x1f3e0; 个人主页&#xff1a; Morning的主页 &#x1f4d5;系列专栏&#xff1a; 前端…

「Qt中文教程指南」如何创建基于Qt Widget的应用程序(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文描述了如何使用…

计算机毕业设计选什么题目好?springboot 班级事务管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

JS里字符串全部替换

突然在需要处理一个字符串&#xff0c;使用了替换函数之后&#xff0c;发现只替换了第一个位置的字符串&#xff0c;如下结果&#xff1a; 就想要全部替换&#xff0c;可以这样处理: 使用 str.replace(/需要替换的字符串/g&#xff0c;"新字符串")或者使用replaceA…

CSP-J/S第二轮认证注意事项

金九银十日&#xff0c;复赛进行时。 CSP-J/S复赛马上就要开始了&#xff0c;但是每年都有很多孩子因为一些不起眼的失误导致一年的努力付之东流。下面为大家准备了一些复赛的注意事项&#xff0c;避免踩坑。 在哪里写代码 第二轮比赛与我们平时在OJ上做题形式不同&#xff0…