开源项目:SXGUI——针对嵌入式开发的简单易用跨平台多级菜单

        对于嵌入式开发者而言,GUI想必都不陌生,但GUI的引入通常会耗费我们大量的精力去处理菜单之间的关系,而且占用往往会很大,所以我开发了一款GUI库,目的是让GUI的引入变得方便快捷,并能够让程序员集中注意力于功能的开发

开源地址:

GitHub:https://github.com/SuiXinSc/SXGUI--Simple.X.GUI

Gitee:https://gitee.com/SuiXinSc/SXGUI--Simple.X.GUI

交流Q群:659512171


目录

Demo演示:

一,程序功能: 

1,菜单管理:

2,可拓展性:

3,兼容性:

4,动画:

二,程序设计思路:

1,数据结构及处理:

2, 跨平台的实现:

3,显示屏驱动:

4,调用方式:

三,结构体:

1,SXGUI_MenuItem:

2,SXGUI_APPItem:

3,SXGUI_KeyItem:

四,主要函数:

1,SXGUI_Interface:

2, SXGUI_CreateRoot:

3,SXGUI_CreateMenu:

4,SXGUI_CreateApp:

5,删除项:

6,添加项:

 7,SXGUI_Init:

8,SXGUI_Main:

五,常用图形库函数:

六,结语: 


        关于该GUI库的简要介绍和数据结构图在之前的开源预告中有,推荐先看一遍(原谅我鸽了这么长时间才写文,是真的抽不开空):传送门

Demo演示:

【开源】【人人可复刻】丝滑GUI库

一,程序功能: 

1,菜单管理:

        该GUI库支持动态创建,管理菜单项,即所有的菜单项不是被写在程序里定死的,可以通过调用函数的方式来更改

2,可拓展性:

        支持无限级的菜单与APP添加,内置APP的处理,只需要调用函数便可将自己的APP添加至GUI中(若APP中出现死循环,要在死循环中处理按键读取,显示屏刷屏以及主动退出等操作,主动退出仅支持2024.8.5之后的版本)。另外,库中提供了默认的菜单界面,用户也可以自行设计菜单的界面仅限v1.1及以上版本)。为了防止编写界面函数和APP函数时填写参数出错,我添加了  INTERFACE_PARAMETERS 和 APP_PARAMETERS 这两个宏定义,编写函数时只需要直接在括号中填入即可。

3,兼容性:

        使用Keil的 O3 等级优化,开启微库,该GUI库依然能够正常使用,没有任何影响,同时也支持在RTOS中作为独立的线程使用

4,动画:

        动画由 graphics_api 这个文件提供,使用的是PID动画页间的过渡采用虚化,在SXGUI_Main 函数中调用 Graphics_Bokeh 函数实现

二,程序设计思路:

1,数据结构及处理:

        为了方便管理,我采用了四向链表,形成了网络状结构(调用函数自动创建,不用手写),同时为了减少可能的逻辑错误,我加入了一个ROOT菜单项作为根,这样就由网状结构转变成了树状结构。

        如果你看过我的程序,你会发现链表结构体中都是指针,因为每一个结构体本身就是数据,就不需要再储存其他数据了(名称除外)。

        对于数据的处理,则全是指针的操作突击检查,指针不扎实的自觉复习),可以说该库的内核就是通过指针指向树状结构的不同节点,每个节点之间也通过指针链接,其数据处理的实质是对不同节点指针指向的操作。当然,作为使用者,大可以不用了解它是如何处理的只需要知道封装好的函数有什么功能,该怎么用,毕竟编写该库的初衷就是让GUI的开发简单化。

2, 跨平台的实现:

        正如预告中说的那样,我采用逻辑图形分离的方式,在不同的平台中只需要改动 graphics_api.c 这个文件的部分基础功能函数即可正常运行,我使用的是 0.96 OLED显示屏,目前还没对彩屏进行专门的优化适配。

3,显示屏驱动:

        采用我编写的 OLED驱动 v1.3MM的意思也就是精简版,只保留了最基础的图形绘制,如画点,显示字符,其余的图形绘制均在 graphics_api.c 中。

该版驱动支持:

        1,中英混合显示:字符中出现字库中含有的中文时,可以直接显示,无需专门用一个显示中文的函数像显示图片一样显示中文。

        2,二元光栅:该版本驱动库支持二元光栅的基本运算,可以胜任遮挡,层叠等关系的处理

        3,图形的批量绘制:调用任何绘图函数都只会在显存中运算,只有调用发送显存的函数时,才会一起发送给显示屏(可以理解为垂直同步),有效提高效率和帧率

4,调用方式:

        正如前面所说,我在开发时已经将各种功能封装成函数了,使用者只需要调用这些函数即可实现功能,完全不涉及任何的指针和变量操作,下面是一个示例:

  SXGUI_Init("Hub",SXGUI_Interface); //初始化GUI库
  
  SXGUI_MenuItem *Sub1 = SXGUI_CreateMenu("信息",SXGUI_Interface);
  SXGUI_MenuItem *Sub2 = SXGUI_CreateMenu("GUI信息",SXGUI_Interface);
  SXGUI_APPItem *App1 = SXGUI_CreateApp("Draw Line",Draw_Line);
  SXGUI_APPItem *App2 = SXGUI_CreateApp("Draw Round",Draw_Round);
  SXGUI_APPItem *App3 = SXGUI_CreateApp("Round Rect",Round_Rect);
  SXGUI_APPItem *App4 = SXGUI_CreateApp("内核版本",Kernel_Infor);
  SXGUI_APPItem *App5 = SXGUI_CreateApp("图形库版本",Graphics_Infor);
  SXGUI_APPItem *App6 = SXGUI_CreateApp("驱动信息",Driver_Infor);
  SXGUI_APPItem *App7 = SXGUI_CreateApp("作者信息",Writer_Infor);
  SXGUI_APPItem *App8 = SXGUI_CreateApp("PID Parameter",PID_Infor);
  //创建菜单项、APP项
  
  SXGUI_RootAddSubMenu(Sub1);
  SXGUI_AddSubMenu(Sub1,Sub2);
  
  SXGUI_RootAddApp(App1);
  SXGUI_RootAddApp(App2);
  SXGUI_RootAddApp(App3);
  
  SXGUI_AddApp(Sub2,App4);
  SXGUI_AddApp(Sub2,App5);
  SXGUI_AddApp(Sub2,App6);
  SXGUI_AddApp(Sub2,App7);
  SXGUI_AddApp(Sub2,App8);
  //添加菜单、APP(顺序随意)

 这样就完成了一个GUI界面的创建,后续还可进行实时更改。

三,结构体:

1,SXGUI_MenuItem:

        该结构体为菜单项的链表结构体;

typedef struct SXGUI_MenuItem{
  char *name;
  struct SXGUI_MenuItem *Pre;
  struct SXGUI_MenuItem *Next;
  struct SXGUI_MenuItem *Parent;
  struct SXGUI_MenuItem *Sub;
  struct SXGUI_APPItem *App;
  void (*Interface)(INTERFACE_PARAMETERS);  //界面绘制函数
  const uint8_t *Icon;    //图标的指针
} SXGUI_MenuItem;
参数描述
*name名称字符串指针
*Pre上个目录的指针
*Next下个目录的指针
*Parent父目录指针
*Sub子级首目录的指针
*Interface界面绘制函数的指针
*Icon目录图标的指针

2,SXGUI_APPItem:

        该结构体为应用项的结构体;

typedef struct SXGUI_APPItem{
  char *name;
  void (*Function)(APP_PARAMETERS);
  struct SXGUI_APPItem *Pre;
  struct SXGUI_APPItem *Next;
  struct SXGUI_MenuItem *Parent;
  const uint8_t *Icon;    //图标的指针
} SXGUI_APPItem;
参数描述
*name名称字符串指针
*FunctionAPP函数指针
*Pre上个应用的指针
*Next下个应用的指针
*Parent父目录指针
*Icon目录图标的指针

3,SXGUI_KeyItem:

         该结构体为按键的结构体;

typedef struct SXGUI_KeyItem{
  bool Back;
  bool Pre;
  bool Next;
  bool OK;
  int *MoreKey;     //更多按键
} SXGUI_KeyItem;
参数描述
Back回到上一级,布尔值,占用 1bit
Pre上一个,布尔值,占用 1bit
Next下一个,布尔值,占用 1bit
OK确定,布尔值,占用 1bit
*MoreKey更多扩展按键的指针,可直接用数组,int型值

 注意:该结构体需要自己定义,同时会传入APP函数内非阻塞型的APP函数可以直接通过该结构体读取按键。

四,主要函数:

1,SXGUI_Interface:

        该函数为提供的默认界面函数,不想自己写界面函数的可以直接调用;

void SXGUI_Interface(INTERFACE_PARAMETERS) {
  int List_x = Fontsize / 2,
      List_y = Fontsize + 1;

  Graphics_ListChoose(List_x, List_y, 128 - List_x - 1, 64 - Fontsize - 1,
                      Fontsize, Menu, MenuNum, AppNum, option, style, FontColor);

  Graphics_ShowString(0, 0, Menu->name, Fontsize, FontColor);
}

 函数参数 INTERFACE_PARAMETERS 是一个宏定义,具体如下:

#define INTERFACE_PARAMETERS    int Fontsize, struct SXGUI_MenuItem* Menu, int option,int MenuNum,\
int AppNum, uint32_t BackColor, uint32_t FontColor, int style   //界面参数的宏定义

该宏为界面绘制函数的参数,在自己编写界面绘制函数的时候为避免填错参数,直接填入该宏即可

2, SXGUI_CreateRoot:

        该函数为创建根目录的函数,在 SXGUI_Init 中已经调用,无需用户再次调用;

int SXGUI_CreateRoot(char* Name, void (*Interface)(INTERFACE_PARAMETERS)){

  if(ROOT != NULL) {
    return SXGUI_ERROR;     //如果已创建
  }
  ROOT = malloc(sizeof(SXGUI_MenuItem));
  ROOT->name = Name;
  ROOT->Interface = Interface;
  return SXGUI_OK;
}

其中的 ROOT 是全局指针变量,定义如下:

SXGUI_MenuItem* ROOT;

3,SXGUI_CreateMenu:

        该函数为创建菜单项的函数,返回值为 SXGUI_MenuItem 结构体指针;

SXGUI_MenuItem* SXGUI_CreateMenu(char* Name, void (*Interface)(INTERFACE_PARAMETERS)){
  SXGUI_MenuItem* Menu = malloc(sizeof(SXGUI_MenuItem));
  Menu->name = Name;
  Menu->Interface = Interface;
  return Menu;
}

4,SXGUI_CreateApp:

        该函数为创建APP的函数返回值为 SXGUI_APPItem 结构体指针;

SXGUI_APPItem* SXGUI_CreateApp(char* Name, void (*AppFunction)(APP_PARAMETERS)) {
  SXGUI_APPItem* APP = malloc(sizeof(SXGUI_APPItem));
  APP->name = Name;
  APP->Function = AppFunction;
  return APP;
}

5,删除项:

        有释放GUI,删除菜单项,删除APP项,这里不做过多讲解

6,添加项:

        分为在根目录下添加和在普通目录下添加,也分为添加菜单项和添加APP项

//在根目录下添加菜单项
int SXGUI_RootAddSubMenu(SXGUI_MenuItem* SubMenu) {
  if(SubMenu->Parent != NULL) { //如果已被添加
    return SXGUI_ERROR;
  }

  SubMenu->Parent = ROOT;
  SXGUI_MenuItem* Ptr = ROOT->Sub;

  if(Ptr != NULL) {
    for(; Ptr->Next != NULL; Ptr = Ptr->Next);
    Ptr->Next = SubMenu;
  } else {
    ROOT->Sub = SubMenu;
  }

  SubMenu->Pre = Ptr;

  return SXGUI_OK;
}

//根目录下添加APP项
int SXGUI_RootAddApp(SXGUI_APPItem* APP) {
  if(APP->Parent != NULL) {   //如果已被添加
    return SXGUI_ERROR;
  }
  APP->Parent = ROOT;

  SXGUI_APPItem* Ptr = ROOT->App;

  if(Ptr != NULL) {
    for(; Ptr->Next != NULL; Ptr = Ptr->Next);
    Ptr->Next = APP;
  } else {
    ROOT->App = APP;
  }

  APP->Pre = Ptr;

  return SXGUI_OK;
}

//菜单下添加子菜单
int SXGUI_AddSubMenu(SXGUI_MenuItem* ParentMenu, SXGUI_MenuItem* SubMenu) {
  if(SubMenu->Parent != NULL) {   //如果已被添加
    return SXGUI_ERROR;
  }
  SubMenu->Parent = ParentMenu;

  SXGUI_MenuItem* Ptr = ParentMenu->Sub;

  if(Ptr != NULL) {
    for(; Ptr->Next != NULL; Ptr = Ptr->Next);
    Ptr->Next = SubMenu;
  } else {
    ParentMenu->Sub = SubMenu;
  }

  SubMenu->Pre = Ptr;

  return SXGUI_OK;
}

//菜单下添加APP
int SXGUI_AddApp(SXGUI_MenuItem* ParentMenu, SXGUI_APPItem* APP) {
  if(APP->Parent != NULL) {   //如果已被添加
    return SXGUI_ERROR;
  }
  APP->Parent = ParentMenu;

  SXGUI_APPItem* Ptr = ParentMenu->App;

  if(Ptr != NULL) {
    for(; Ptr->Next != NULL; Ptr = Ptr->Next);
    Ptr->Next = APP;
  } else {
    ParentMenu->App = APP;
  }

  APP->Pre = Ptr;

  return SXGUI_OK;
}

 7,SXGUI_Init:

        该函数作用是初始化变量

void SXGUI_Init(char* HubName, void (*Interface)(INTERFACE_PARAMETERS)){
  SXGUI_CreateRoot(HubName,Interface);    //创建根目录
  NowMenu = ROOT;     //初始化指针变量
}

8,SXGUI_Main:

        该函数是GUI的主逻辑程序在主程序中循环执行,由于代码较长,这里不再贴出,只展示函数声明;

void SXGUI_Main(int Fontsize, uint32_t BackColor, uint32_t FontColor, int style, SXGUI_KeyItem* Key);

里面的参数也很好看懂,这里不解释了

五,常用图形库函数:

函数功能
Graphics_Init

初始化图形库

Graphics_Clear清空显存
Graphics_Display发送显存数据
Graphics_DrawPoint画点
Graphics_ShowBMP显示图片
Graphics_Bokeh背景虚化效果
Graphics_ShowString显示字符串,支持中英混合显示
Graphics_DrawLine画虚/实线
Graphics_DrawQuarterRound画四分之一圆
Graphics_DrawRound画整圆,填充/不填充
Graphics_DrawRect

画矩形,填充/不填充

Graphics_DrawRoundRect画圆角矩形,填充/不填充

六,结语: 

         该图形库会不定期更新,主要是根据应用中出现的不足和需求进行更新,各位有什么想法也可以留言或私信我,广泛的交流才能更好


开发不易,点个关注再走吧 (>▽<)

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值