A Menu Class for LCDs

For a simple LCD menu for the Arduino , as I understand it, you only need a display, a push button and the definition of the menu texts with the associated menu actions. Everything else should not have to bother the user. So a menu entry should look like this:

				
  typedef struct { const char *txt; void (&action)(); } MenuItem;
		
and the menu itself like this:
					
  MenuItem menu[] =           
   {
     { "menuText1 ", action1 },
     { ...                   },
   };
  
  // Calculate the number of menuitems
  const uint8_t nbrMenuItems = sizeof(menu) / sizeof(menu[0]);
		
The push button allows to navigate through the menu and select the associated action. Of course, the pushbutton should be debounced and able to trigger the functions:
				
  onClick() 
  onDoubleClick()
  onLongClick()
		

We realize the debouncing of the push button in the class ButtonDebounced. The button doesn't know yet how we want to use the three functions mentioned above. Therefore we declare them as virtual. In the loop method of the class we decide which of the functions should be called.

In the class LcdMenuControlButton derived from ButtonDebounced we implement the virtual functions. A LcdMenuControlButton needs to know which pin the button is connected to and which menu it should serve. Therefore we pass the pin and a pointer to the menu to its constructor.

The class LcdMenu implements the whole functionality of the menu system, i.e. displaying the text, navigating forward and backward and triggering the menu actions. Therefore we pass in to the constructor a reference to the display, a pointer to the menu, the number of menu items and the number of menu lines to display.

So in our main program we only need the array of MenuItems and one instance each of the classes

				
  LiquidCrystal_I2C    lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);     // the LCD
  LcdMenu              lcdMenu(lcd, menu, nbrMenuItems, LCD_ROWS);  // the menu
  LcdMenuControlButton menuButton(PIN_BTN_MENU, lcdMenu);           // the menu button
		
and the actions to be executed. The main loop consists of a single line.
					
  void action1()
  {
    lcd.clear();
    doSomething();
    lcd.print("print results...")
  }

  void loop() 
  {
    menuButton.loop(); // handle button clicks
  }					
		

Interested? Please download the entire program code. The zip-file contains the complete PlatformIO project.

My programming environment is not the native Arduino™ IDE but PlatformIO™ on top of Microsoft's Visual Studio Code™. This combination offers many advantages and allows a much better structuring of the code into several modules especially when we adopt The Object Oriented way.