很久之前,写过一个简易的多级菜单,如今回头看,我都不敢承认那玩意是自己写的,于是打算重新写过一个,并且做成一个简易的GUI。原来用的OLED,现在改成了TFT(ST7789驱动)。但是答题的思路还是不变的。
先说说思路,由于选择的是一个没有触摸的屏幕,于是就要加上物理按键。这样才能操作屏幕嘛。 按照面向对象的思想,我将整个GUI结构分为三类:按键,显示,动作。
- 按键用来控制屏幕,进行上滑下滑切入切出菜单;
- 显示则作为每一级菜单的背景,并且将菜单设置为静态显示(即每次切换只显示一次);
- 动作则用来链接各种显示功能。例如一级菜单切入二级菜单这么个动作;
- 除此之外就是各种动态效果,这部分暂时还未开工。
接下来看看menu.c文件的内容
#include <stdio.h>
#include "string.h"
#include "lcd_init.h"
#include "lcd.h"
#include "main.h"
#include "menu.h"
#define Menu_Select 3
char buf[100];
uint8_t List_Number = 1;
static uint8_t Menu_Change = 0;
static uint8_t Menu_Refresh_Flag = 0;
static uint8_t UD_Action_Flag = 0;
extern unsigned char BMP_1[];
extern unsigned char BMP_2[];
extern unsigned char BMP_3[];
extern unsigned char BMP_4[];
extern unsigned char BMP_5[];
extern unsigned char BMP_6[];
extern unsigned char BMP_7[];
extern unsigned char BMP_8[];
extern unsigned char BMP_9[];
void Draw_Line(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{
u16 i = 0;
if (x1 == x2)
{
for (i = y1; i <= y2; i++)
{
LCD_DrawPoint(x1, i, color);
}
}
if (y1 == y2)
{
for (i = x1; i <= x2; i++)
{
LCD_DrawPoint(i, y1, color);
}
}
}
void Draw_Rectangle(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{
Draw_Line(x1, y1, x2, y1, color);
Draw_Line(x1, y1, x1, y2, color);
Draw_Line(x1, y2, x2, y2, color);
Draw_Line(x2, y1, x2, y2, color);
}
void Draw_Box(u16 x1, u16 y1, u16 x2, u16 y2, u16 color, u16 index)
{
u16 i = 0;
for (i = 0; i < index; i++)
{
Draw_Rectangle(x1 + i, y1 + i, x2 - i, y2 - i, color);
}
}
void Draw_Windows(void)
{
Draw_Box(0, 0, 240, 240, LBBLUE, 5);
Draw_Box(0, 36, 240, 41, LBBLUE, 5);
sprintf(buf, " WINDOWS1 ");
LCD_ShowString(5, 5, (uint8_t*)buf, WHITE, LBBLUE, 32, 0);
}
void Draw_Circal_Box(u16 x0, u16 y0, u8 r, u16 color, u8 length)
{
int a, b;
a = 0;
b = r;
while (a <= b)
{
LCD_DrawPoint(x0 - b, y0 - a, color);
LCD_DrawPoint(x0 - b, y0 + a, color);
LCD_DrawPoint(x0 - a, y0 + b, color);
LCD_DrawPoint(x0 - a, y0 - b, color);
LCD_DrawPoint(x0 + b + length, y0 - a, color);
LCD_DrawPoint(x0 + b + length, y0 + a, color);
LCD_DrawPoint(x0 + a + length, y0 - b, color);
LCD_DrawPoint(x0 + a + length, y0 + b, color);
a++;
if ((a * a + b * b) > (r * r))
{
b--;
}
}
LCD_DrawLine(x0, y0 - r, x0 + length, y0 - r, color);
LCD_DrawLine(x0, y0 + r, x0 + length, y0 + r, color);
}
void Draw_Circal_Solid(u16 x0, u16 y0, u8 r, u16 color)
{
int a, b, c;
a = 0;
b = r;
for (c = r; c > 0; c--)
{
Draw_Circle(x0, y0, c - 1, color);
}
}
void Display_Initial_Menu(u16 x,u16 y,u16 fc,u16 bc,u8 sizey,u8 mode,u8 Box_Height)
{
sprintf(buf,"DISPLAY");
LCD_ShowString(x, y + ( Box_Height * 0 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"VOICE");
LCD_ShowString(x, y + ( Box_Height * 1 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"NOTICE");
LCD_ShowString(x, y + ( Box_Height * 2 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"BATTERY");
LCD_ShowString(x, y + ( Box_Height * 3 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"MEMORY");
LCD_ShowString(x, y + ( Box_Height * 4 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"ABOUT");
LCD_ShowString(x, y + ( Box_Height * 5 ), (uint8_t *)buf, fc, bc, sizey, mode);
}
void Display_Second_Menu(u16 x,u16 y,u16 fc,u16 bc,u8 sizey,u8 mode,u8 Box_Height)
{
sprintf(buf,"DISPLAY");
LCD_ShowString(x, y + ( Box_Height * 0 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"VOICE");
LCD_ShowString(x, y + ( Box_Height * 1 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"NOTICE");
LCD_ShowString(x, y + ( Box_Height * 2 ), (uint8_t *)buf, fc, bc, sizey, mode);
sprintf(buf,"BATTERY");
LCD_ShowString(x, y + ( Box_Height * 3 ), (uint8_t *)buf, fc, bc, sizey, mode);
}
void Display_Third_Menu(void)
{
LCD_ShowPicture( 25, 15, 50, 50, BMP_1);
LCD_ShowPicture( 95, 15, 50, 50, BMP_2);
LCD_ShowPicture(175, 15, 50, 50, BMP_3);
LCD_ShowPicture( 15, 95, 50, 50, BMP_4);
LCD_ShowPicture( 95, 95, 50, 50, BMP_5);
LCD_ShowPicture(175, 95, 50, 50, BMP_6);
LCD_ShowPicture( 15, 175, 50, 50, BMP_7);
LCD_ShowPicture( 95, 175, 50, 50, BMP_8);
LCD_ShowPicture(175, 175, 50, 50, BMP_9);
}
void Button_Up_Click(uint8_t Menu_List)
{
if (Button_Click_Event_1)
{
if (List_Number > 1)
List_Number = List_Number - 1;
else if (List_Number == 1)
List_Number = Menu_List;
else
List_Number = List_Number;
UD_Action_Flag = 2;
LCD_ShowIntNum(220, 220, List_Number, 1, WHITE, BLACK, 16);
}
}
void Button_Down_Click(uint8_t Menu_List)
{
if (Button_Click_Event_2)
{
if (List_Number < Menu_List)
List_Number = List_Number + 1;
else if (List_Number == Menu_List)
List_Number = 1;
else
List_Number = List_Number;
UD_Action_Flag = 1;
LCD_ShowIntNum(220, 220, List_Number, 1, WHITE, BLACK, 16);
}
}
void Button_Menu_Enter(u8 Desk_Num)
{
LCD_ShowIntNum(200,220,Menu_Change,1,WHITE,BLACK,16);
if(Button_Click_Event_3)
{
Action_Menu_Change(0);
Menu_Refresh_Flag = 1;
if (Menu_Change < Desk_Num - 1)
Menu_Change = Menu_Change + 1;
else if (Menu_Change == Desk_Num - 1)
Menu_Change = Desk_Num - 1;
LCD_ShowIntNum(220, 220, List_Number, 1, WHITE, BLACK, 16);
}
}
void Button_Menu_Exit(u8 Desk_Num)
{
LCD_ShowIntNum(200, 220, Menu_Change, 1, WHITE, BLACK, 16);
if (Button_Click_Event_4)
{
Action_Menu_Change(1);
Menu_Refresh_Flag = 1;
if (Menu_Change > 0)
Menu_Change = Menu_Change - 1;
if (Menu_Change < Desk_Num - 2)
Menu_Change = 0;
LCD_ShowIntNum(220, 220, List_Number, 1, WHITE, BLACK, 16);
}
}
u8 List = 0,List2 = 0;
void Action_Menu_Change(u8 select)
{
switch (select)
{
case 0:
switch (Menu_Change)
{
case 0:
List = List_Number;
List_Number = 1;
LCD_Fill(0, 0, LCD_W, LCD_H, BLACK);
break;
case 1:
List2 = List_Number;
List_Number = 1;
LCD_Fill(0, 0, LCD_W, LCD_H, BLACK);
break;
}
break;
case 1:
switch (Menu_Change)
{
case 1:
List_Number = List;
LCD_Fill(0, 0, LCD_W, LCD_H, BLACK);
break;
case 2:
List_Number = List2;
LCD_Fill(0, 0, LCD_W, LCD_H, BLACK);
break;
}
default:
break;
}
}
void Action_Box_Up(u16 x1,u16 y1,u16 x2,u16 y2,uint8_t Menu_List, uint8_t Box_Height)
{
if(UD_Action_Flag == 2)
{
UD_Action_Flag = 0;
if(List_Number >= 1 && List_Number < Menu_List)
{
LCD_DrawLine(x1, y2+Box_Height*(List_Number), x2, y2+Box_Height*(List_Number), BLACK);
LCD_DrawLine(x1, y1+Box_Height*(List_Number), x1, y2+Box_Height*(List_Number), BLACK);
LCD_DrawLine(x2, y1+Box_Height*(List_Number), x2, y2+Box_Height*(List_Number), BLACK);
printf("%d",List_Number);
}
if(List_Number == Menu_List)
{
LCD_DrawRectangle(x1, y1 + Box_Height*(0), x2, y2+Box_Height*(0), BLACK);
}
}
}
void Action_Box_Down(u16 x1, u16 y1, u16 x2, u16 y2, uint8_t Menu_List, uint8_t Box_Height)
{
if (UD_Action_Flag == 1)
{
UD_Action_Flag = 0;
if (List_Number > 1 && List_Number <= Menu_List)
{
LCD_DrawLine(x1, y1 + Box_Height * (List_Number - 2), x2, y1 + Box_Height * (List_Number - 2), BLACK);
LCD_DrawLine(x1, y1 + Box_Height * (List_Number - 2), x1, y2 + Box_Height * (List_Number - 2), BLACK);
LCD_DrawLine(x2, y1 + Box_Height * (List_Number - 2), x2, y2 + Box_Height * (List_Number - 2), BLACK);
printf("%d", List_Number);
}
if (List_Number == 1)
{
LCD_DrawRectangle(x1, y1 + Box_Height * (Menu_List - 1), x2, y2 + Box_Height * (Menu_List - 1), BLACK);
}
}
}
void Draw_Option_Box(u16 x1, u16 y1, u16 x2, u16 y2, uint8_t Menu_List, uint8_t Box_Height)
{
LCD_DrawRectangle(x1, y1 + Box_Height * (List_Number - 1), x2, y2 + Box_Height * (List_Number - 1), BLUE);
}
void Menu_Display_Control(void)
{
Button_Menu_Enter(Menu_Select);
Button_Menu_Exit(Menu_Select);
switch (Menu_Change)
{
case 0:
if (Menu_Refresh_Flag == 1)
{
Display_Initial_Menu(10, 3, WHITE, BLACK, 24, 0, 30);
Menu_Refresh_Flag = 0;
}
Draw_Option_Box(3, 0, 200, 30, 6, 30);
Action_Box_Up(3, 0, 200, 30, 6, 30);
Action_Box_Down(3, 0, 200, 30, 6, 30);
Button_Down_Click(6);
Button_Up_Click(6);
break;
case 1:
if (Menu_Refresh_Flag == 1)
{
Display_Second_Menu(10, 3, RED, BLACK, 32, 0, 59);
Menu_Refresh_Flag = 0;
}
Draw_Option_Box(3, 0, 150, 59, 4, 59);
Action_Box_Up(3, 0, 150, 59, 4, 59);
Action_Box_Down(3, 0, 150, 59, 4, 59);
Button_Down_Click(4);
Button_Up_Click(4);
break;
case 2:
if (Menu_Refresh_Flag == 1)
{
Display_Third_Menu();
Menu_Refresh_Flag = 0;
}
Draw_Option_Box(0, 0, 80, 79, 3, 79);
Action_Box_Up(0, 0, 80,79, 3, 79);
Action_Box_Down(0, 0, 80, 79, 3, 79);
Button_Down_Click(3);
Button_Up_Click(3);
break;
default:
Menu_Refresh_Flag = 0;
break;
}
}
重点:如何创建菜单
如果使用其中自带的选项框,那么只需要修改两处即可 一是 Action_Menu_Change(u8 select) 函数,在其中添加 List_Number 变量的继承; 二是Menu_Display_Control(void) 函数中注册新的菜单。 重点在第二个函数
- 首先要确定菜单级数
- 然后申请一个或多个新的菜单,并且在Menu_Refresh_Flag == 1的情况下申请,不然会不断刷新屏幕
- 然后注册选项框,注册选项框的动作,动作可以自行修改
- 最后注册按键
接下来是menu.h文件内容
#ifndef __menu_H_
#define __menu_H_
#include <stdio.h>
#include "string.h"
#include "stdint.h"
#include "main.h"
#define Button_Click_Event_1 HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET
#define Button_Click_Event_2 HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET
#define Button_Click_Event_3 HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == GPIO_PIN_RESET
#define Button_Click_Event_4 HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == GPIO_PIN_RESET
void Display_Initial_Menu(u16 x,u16 y,u16 fc,u16 bc,u8 sizey,u8 mode,u8 Box_Height);
void Display_Second_Menu(u16 x,u16 y,u16 fc,u16 bc,u8 sizey,u8 mode,u8 Box_Height);
void Display_Third_Menu(void);
void Draw_Box(u16 x1, u16 y1, u16 x2, u16 y2, u16 color, u16 index);
void Draw_Line(u16 x1, u16 y1, u16 x2, u16 y2, u16 color);
void Draw_Rectangle(u16 x1, u16 y1, u16 x2, u16 y2, u16 color);
void Draw_Option_Box(u16 x1, u16 y1, u16 x2, u16 y2, uint8_t Menu_List, uint8_t Box_Height);
void Draw_Windows(void);
void Draw_Circal_Box(u16 x0,u16 y0,u8 r,u16 color, u8 length);
void Draw_Circal_Solid(u16 x0, u16 y0, u8 r, u16 color);
void Button_Down_Click(uint8_t Menu_List);
void Button_Up_Click(uint8_t Menu_List);
void Button_Menu_Enter(u8 Desk_Num);
void Button_Menu_Exit(u8 Desk_Num);
void Action_Box_Up(u16 x1, u16 y1, u16 x2, u16 y2, uint8_t Menu_List, uint8_t Box_Height);
void Action_Box_Down(u16 x1, u16 y1, u16 x2, u16 y2, uint8_t Menu_List, uint8_t Box_Height);
void Action_Menu_Change(u8 select);
void Menu_Display_Control(void);
#endif
最后是main.c的内容
在while循环里添加 Menu_Display_Control(); 即可,菜单的其他配置都在menu.c中配置完成。
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
LCD_Init();
LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
Display_Initial_Menu(10, 3, WHITE, BLACK, 24, 0, 30);
LCD_ShowIntNum(220, 220, List_Number, 1, WHITE, BLACK, 16);
while (1)
{
Menu_Display_Control();
}
}
显示效果
B站视频效果
|