单色OLED屏可移植多级菜单式GUI(3)-使用
在上篇文章中已经讲了源码实现,这篇文章将教会你怎么使用和移植到自己的项目中去,以此系列第一篇文章的效果视频为例,通过实例的方式展现其用法,快速上手。
还是先贴上代码:
#ifndef __M_GUI_TEST_H
#define __M_GUI_TEST_H
#define BUILD_TITLE(X,Y) \
{ \
if(!((*(X)).pszTitle)) \
{ \
for(uint32_t i = 0;i < COUNTOF(X);i++) \
{ \
(X)[i].pszTitle = (tTitle)&(Y)[i]; \
} \
} \
}
#endif/*__M_GUI_TEST_H*/
#include "./m_gui/m_gui.h"
#include "./m_gui/m_gui_test.h"
#include "./key_board/key_board.h"
#include "./oled.h"
static M_U32 key_up(void);
static M_U32 key_down(void);
static M_U32 key_left(void);
static M_U32 key_right(void);
static M_U32 key_enter(void);
static M_U32 key_exit(void);
MENU_GUI gui;
opsTypeDef ops = {
.pset = (void (*)(M_U16, M_U16, M_U8))OLED_DrawPoint,
.pclear = (void (*)(void))OLED_clcScreen,
.pputString = (void (*)(M_U16, M_U16, M_U8, void *))OLED_INT_CharDisp,
};
keyTypeDef key = {
.up = key_up,
.down = key_down,
.left = key_left,
.right = key_right,
.enter = key_enter,
.exit = key_exit,
};
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
static void page_item1_S_f(void);
static const struct sTitle page_item1_o_t[] = {
{"speed-10",40,16},
{"speed-20",40,96},
{"speed-30",40,176},
};
static const struct sItem page_item1_o[] = {
{(tTitle)&page_item1_o_t[0],NULL},
{(tTitle)&page_item1_o_t[1],NULL},
{(tTitle)&page_item1_o_t[2],NULL},
};
static const struct sTitle page_item1_t[] = {"速度选择",0,0};
static struct sMenu page_item1[] = {(tTitle)page_item1_t,(tItem)page_item1_o,COUNTOF(page_item1_o),0,1,3,(thmi)hmi_def,page_item1_S_f};
static void page_item1_S_f(void)
{
gui_put_string(10, OLED_Y_COR_CENTER(strlen(gui.active->pszTitle->str)), 0, gui.active->pszTitle->str);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
static void page_item2_S_f(void);
static const struct sTitle page_item2_o_t[] = {
{"选项1",29,40},
};
static struct sItem page_item2_o[] = {
{NULL,page_item1},
};
static const struct sTitle page_item2_t[] = {"菜单3",0,0};
static struct sMenu page_item2[] = {(tTitle)page_item2_t,(tItem)page_item2_o,COUNTOF(page_item2_o),0,1,3,(thmi)hmi_def,page_item2_S_f};
static void page_item2_S_f(void)
{
BUILD_TITLE(page_item2_o,page_item2_o_t)
gui_put_string(10, OLED_Y_COR_CENTER(strlen(gui.active->pszTitle->str)), 0, gui.active->pszTitle->str);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
static void page_item3_S_f(void);
static struct sMenu page_item3[] = {(tTitle)NULL,(tItem)NULL,0,0,0,0,(thmi)hmi_def,page_item3_S_f};
static void page_item3_S_f(void)
{
char tmpStr[32] = {0};
sprintf(tmpStr,"%s","测试test");
gui_put_string(10, OLED_Y_COR_CENTER(strlen(tmpStr)), 0, tmpStr);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
static void page_item4_S_f(void);
static const struct sTitle page_item4_o_t[] = {
{"选项1",29,40},
{"选项2",29,152},
{"选项3",48,40},
};
static struct sItem page_item4_o[] = {
{NULL,page_item1},
{NULL,page_item2},
{NULL,page_item3},
};
static const struct sTitle page_item4_t[] = {"菜单2",0,0};
static struct sMenu page_item4[] = {(tTitle)page_item4_t,(tItem)page_item4_o,COUNTOF(page_item4_o),0,1,3,(thmi)hmi_def,page_item4_S_f};
static void page_item4_S_f(void)
{
BUILD_TITLE(page_item4_o,page_item4_o_t)
gui_put_string(10, OLED_Y_COR_CENTER(strlen(gui.active->pszTitle->str)), 0, gui.active->pszTitle->str);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
static void page_item5_S_f(void);
static const struct sTitle page_item5_o_t[] = {
{"speed-10",40,16},
{"speed-20",40,96},
{"speed-30",40,176},
};
static const struct sItem page_item5_o[] = {
{(tTitle)&page_item5_o_t[0],NULL},
{(tTitle)&page_item5_o_t[1],NULL},
{(tTitle)&page_item5_o_t[2],NULL},
};
static const struct sTitle page_item5_t[] = {"速度选择",0,0};
static struct sMenu page_item5[] = {(tTitle)page_item5_t,(tItem)page_item5_o,COUNTOF(page_item5_o),0,1,3,(thmi)hmi_def,page_item5_S_f};
static void page_item5_S_f(void)
{
gui_put_string(10, OLED_Y_COR_CENTER(strlen(gui.active->pszTitle->str)), 0, gui.active->pszTitle->str);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
static void pageS_f(void);//主界面
static const struct sTitle page_o_t[] = {
{"选项1",29,40},
{"选项2",29,152},
{"选项3",48,40},
{"选项4",48,152},
{"选项5",29,40},
};
static struct sItem page_o[] = {
{NULL,page_item1},
{NULL,page_item2},
{NULL,page_item3},
{NULL,page_item4},
{NULL,page_item5},
};
static const struct sTitle page_t[] = {"菜单1",0,0};
static struct sMenu page[] = {(tTitle)page_t,(tItem)page_o,COUNTOF(page_o),0,2,2,(thmi)hmi_def,pageS_f};
static void pageS_f(void)
{
BUILD_TITLE(page_o,page_o_t)
gui_put_string(10, OLED_Y_COR_CENTER(strlen(gui.active->pszTitle->str)), 0, gui.active->pszTitle->str);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
void gui_test(void)
{
gui_init(&gui,&ops,&key);
gui_select(&gui);
gui_set_active(page);
gui_send_sig(gui.active);
}
M_U32 key_up(void)
{
return (KeyGetState(KEY_UP) == KEY_RELEASE);
}
M_U32 key_down(void)
{
return (KeyGetState(KEY_DOWN) == KEY_RELEASE);
}
M_U32 key_left(void)
{
return (KeyGetState(KEY_LEFT) == KEY_RELEASE);
}
M_U32 key_right(void)
{
return (KeyGetState(KEY_RIGHT) == KEY_RELEASE);
}
M_U32 key_enter(void)
{
return (KeyGetState(KEY_ENTER) == KEY_RELEASE);
}
M_U32 key_exit(void)
{
return (KeyGetState(KEY_EXIT) == KEY_RELEASE);
}
/*
使用示例(一个任务或者定时器)
void gui_task(void)
{
M_U32 tmpCnt = 0; gui_test();//初始化
for(;;)
{
//按键每10ms扫描一次
if(0 == (tmpCnt++ % 10))
{
//你的键盘扫描
do something
//响应按键后的具体操作
gui_key_scan();
}
//有事件时更新
gui_flush();
//1ms调度
vTaskDelay(1);
}
}
//目前键盘仅实现了菜单项的选择,菜单的切换功能,如果想实现数值修改等其它功能,只需要新增相应的键盘操作即可,可参考hmi_def的实现
*/
通过以上代码就实现了此系列第一篇文章的效果,可以看到,每一个菜单都是一个小部分,可以随意的增删改,而不会影响其它的菜单,更不用改了一个菜单后还需要重新构建菜单层级关系,使用和维护都是非常方便的。
总结:这个小项目虽然简单,但是在合适的场景其发挥的作用可以说是举足轻重的 ,从最开始的上千行代码,到现在的几百行代码就能完成的功能,对我来说也是一种进步,经过好几版的改进,重构,才有了现在的效果,我不能说这已经是最好的,但可以说是目前更好的,希望我的思路能给你带来启发。





