kmzuaz 发表于 2025-3-27 21:00

嵌入式应用软件人机界面开发的菜单框架编写

https://ask.qcloudimg.com/http-save/yehe-5745070/in43cfgz01.jpeg


    一般来说我们的产品都有按键,按键用来操作相应的界面,那就会有相应的界面处理方法,以下有两种结构的编写:
A类编写



1//针对左键的处理函数,传入的参数为当前页面
2void left_key_process(int current_page)
3{
4    switch(current_page)
5    {
6      case MAIN_PAGE:
7            //针对main_page的左键处理
8             main_page_left_key_process();
9            break ;
10      case SETTING_PAGE:
11            //针对setting_page的左键处理
12            setting_page_left_key_process();
13             break ;
14      case LOG_PAGE:
15            //针对log_page的左键处理
16            log_page_left_key_process();
17            break ;
18      case LANGUAGE_PAGE:
19            //针对language_page的左键处理
20            language_page_left_key_process();
21            break ;
22             ....
23    }
24}
25
26//针对右键的处理函数,传入的参数为当前页面
27void right_key_process(int current_page)
28{
29    //....
30}
31//针对确认键的处理函数,传入的参数为当前页面
32void enter_key_process(int current_page)
33{
34    //....
35}
36//UI页面处理函数,传入的参数为当前的键值
37void UI_Page_Process(int KeyValue)
38{
39    switch(KeyValue)
40    {
41      case LEFT_KEY :
42             left_key_process(KeyValue);
43             break ;
44
45      case RIGHT_KEY:
46             right_key_process(KeyValue);
47             break ;
48      case ENTER_KEY:
49             enter_key_process(KeyValue);
50             break ;
51      ...
52    }
53}


   A类编写,我可以起个名字叫直男式编写,逻辑没有错,也能正常操作相应的页面,没有问题,可它就是一条线,直! 首先拿到键值,然后操作界面,和我们正常人的思维差不多。但如果代码量剧增,页面众多,每个页面有不同的处理按键,相信A类的编写给后面的人来维护或者增加处理方法人一定会非常抱怨,为啥找个界面处理这么痛苦?    我们再来看看B类,我可以起个名字叫人机接口式编写。首先我们要操作界面,界面就是人机接口,每个不同的界面由对应的按键操作方法,这样看起来,是不是更好维护了?以后,我要往界面添加、删除等相关按键的处理方法,那是不是就更好找了?B类编写




1//主页面处理
2void main_page_process(int KeyValue)
3{
4    switch(KeyValue)
5    {
6      case LEFT_KEY:
7             //针对main_page的左键处理
8             break ;
9      case RIGHT_KEY:
10             //针对main_page的右键处理
11             break ;
12      case ENTER_KEY:
13             //针对main_page的Enter键处理
14             break ;
15      case BACK_KEY:
16             //针对main_page的back键处理
17             break ;
18      ...
19    }
20}
21//设置页面处理
22void setting_page_process(int KeyValue)
23{
24    switch(KeyValue)
25    {
26      case LEFT_KEY:
27             ...
28             break ;
29      case RIGHT_KEY:
30             ...
31             break ;
32      case ENTER_KEY:
33             ...
34             break ;
35      case BACK_KEY:
36             ...
37             break ;
38      ...
39    }
40}
41//记录页面处理
42void Log_page_process(int KeyValue)
43{
44    switch(KeyValue)
45    {
46      case LEFT_KEY:
47             ...
48             break ;
49      case RIGHT_KEY:
50             ...
51             break ;
52      case ENTER_KEY:
53             ...
54             break ;
55      case BACK_KEY:
56             ...
57             break ;
58      ...
59    }
60}
61//UI主页面处理 ,传入键值
62void UI_Page_Process(int KeyValue)
63{
64
65    switch(current_page)
66    {
67      case MAIN_PAGE:
68             main_page_process(KeyValue);
69             break ;
70      case SETTING_PAGE:
71             setting_page_process(KeyValue);
72             break ;
73      case LOG_PAGE:
74             Log_page_process(KeyValue);
75             break ;
76      ....
77    }
78}

    虽然说B类看起来更加的易维护,但仍然存在缺陷,那就是一旦菜单项数变多以后,就存在效率低下的问题了,我们有一种更好的解决方法函数跳转表,我们将B类的方式改一下,引入C类编写。
C类编写



1#include <iostream>
2#include <conio.h>
3using namespace std ;
4#define NR(x) (sizeof(x)/sizeof(x))
5
6int main_page_process();
7int detect_page_process();
8int log_page_process();
9int setting_page_process();
10
11//菜单枚举
12typedef enum
13{
14    MAIN_PAGE = 0,
15    DETECT_PAGE,
16    LOG_PAGE,
17    SETTING_PAGE
18}MENU_INDEX;
19
20typedef int(*OPERATE_FUNC)();
21
22class MENU
23{
24    public:
25    MENU_INDEX index ;   //菜单索引
26    OPERATE_FUNC op_func ; //菜单对应的函数
27};
28
29//构造函数跳转表
30static MENU OP_MENU_STRUCT[] =
31{
32    {MAIN_PAGE   ,main_page_process},
33    {DETECT_PAGE ,detect_page_process},
34    {LOG_PAGE    ,log_page_process},
35    {SETTING_PAGE,setting_page_process},
36};
37
38int Goto_execute(int op)
39{
40    if(op >= NR(OP_MENU_STRUCT) || op < 0)
41      return -1 ;
42    //根据索引值op,调用相应的函数
43    return OP_MENU_STRUCT.op_func();
44}
45
46int main(int argc , char **argv)
47{
48    char ch ;
49    int menu_index = 0;
50    while(1)
51    {
52      ch = getch();
53      if(ch == 'a')   //左键
54         menu_index > 0 ? menu_index-- : menu_index = 0 ;
55      else if(ch == 'd')//右键
56         menu_index < NR(OP_MENU_STRUCT) ? menu_index++ : menu_index = NR(OP_MENU_STRUCT);
57      //执行菜单操作
58      Goto_execute(menu_index);
59    }
60    return 0 ;
61}
62
63int main_page_process()
64{
65    cout << "主页面" << endl ;
66}
67
68int detect_page_process()
69{
70    cout << "检测页面" << endl ;
71}
72
73int log_page_process()
74{
75    cout << "记录页面" << endl ;
76}
77
78int setting_page_process()
79{
80    cout << "设置页面" << endl ;
81}



heisexingqisi 发表于 2025-3-28 14:43

菜单如何做比较合适呢。那些流畅的菜单都是如何实现的

heisexingqisi 发表于 2025-3-28 14:44

要讨论采用什么样的结构来实现。

bartonalfred 发表于 2025-4-6 07:14

使用静态数组或预分配内存池,防止内存碎片和分配失败。

51xlf 发表于 2025-4-8 11:37

避免过于复杂的嵌套和过多的选项。

louliana 发表于 2025-4-8 13:08

合理利用嵌入式设备的内存、存储和处理器资源。

macpherson 发表于 2025-4-8 16:16

限制菜单递归深度,避免任务栈耗尽。

chenci2013 发表于 2025-4-9 21:39

仅在菜单状态变化时更新屏幕,避免频繁刷新。

weifeng90 发表于 2025-4-9 22:08

把按键当做是一个事件,用事件来驱动操作。

yeates333 发表于 2025-4-10 00:49

通过宏或配置文件定义菜单项数量、布局等,便于修改。

jackcat 发表于 2025-4-13 21:50

菜单框架的代码和数据结构应该紧凑高效。

Wxy8030 发表于 2025-4-13 22:56

没看懂C类,键值怎么导入的?与A、B类比的优势在哪里?

mmbs 发表于 2025-4-14 19:46

选择轻量级图形库            
页: [1]
查看完整版本: 嵌入式应用软件人机界面开发的菜单框架编写