How to add scrolling to a menu?

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
  // Comment out below lines once you set the date & time.
    // Following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  updateMenu();
}

void loop()
{
  static unsigned long
    timeButtonRead = 0;
  static byte
    lastupButton = 0xff,
    lastselButton = 0xff,
    lastdownButton = 0xff;
  byte
    currButton;
  unsigned long
    timeNow;

  //check buttons every 75mS
  timeNow = millis();
  if (timeNow - timeButtonRead < 75)
    return;
  timeButtonRead = timeNow;

  //read the button...
  currButton = digitalRead(downButton);
  //...if it's state is not the same as last...
  if (currButton != lastdownButton)
  {
    //...save the new state
    lastdownButton = currButton;
    //if it's low indicating it has been pressed...
    if (currButton == LOW)
    {
      //process action; in this case, if menu is greater than 1...
      if (menu > 1)
      {
        //...decrement it               
        menu--;
        //and update the menu
        updateMenu();

      }//if

    }//if

  }//if

  //same comments for downbutton apply for up and select
  currButton = digitalRead(upButton);
  if (currButton != lastupButton)
  {
    lastupButton = currButton;
    if (currButton == LOW)
    {
      if (menu < 4)
      {
        menu++;
        updateMenu();

      }//if

    }//if

  }//if

  currButton = digitalRead(selectButton);
  if (currButton != lastselButton)
  {
    lastselButton = currButton;
    if (currButton == LOW)
    {
      //call the function pointed to by menu in the Functions[] array
      Functions[menu - 2]();
      //when it returns, update the menu
      updateMenu();

    }//if

  }//if

  DateTime now = rtc.now(); //Attaches now to action1 scope
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.day(), DEC);
  lcd.print(" ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
}//loop

void updateMenu()
{
  lcd.clear();
  Serial.print("\n\n\n\n");
  for (int i = 1; i < 4; i++)
  {
    //if menu line is selected, print a '>', otherwise a space
    if (i == (menu - 1))
    {
      Serial.print(">");
      lcd.setCursor(0, i);
      lcd.print(">");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
    }
    else
    {
      Serial.print(" ");
      lcd.setCursor(0, i);
      lcd.print(" ");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);

    }//else

  }//for

}//updateMenu

bool action1()
{
  while(1){
  DateTime now = rtc.now(); //Attaches now to action1 scope
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Current Date & Time: ");
  lcd.setCursor(0, 1);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.day(), DEC);
  lcd.print(" ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
  Serial.println(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);

  if (digitalRead(downButton) == LOW) {
    delay(1000);
  }
  else {
    break;
  }
  }
}//action1

bool action2()
{
  while(1){
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");
    if (digitalRead(downButton) == LOW)
    {
      delay(1000);
    }
    else{
      return;
    }
  }
  }
//action2

bool action3()
{
  lcd.clear();
  lcd.print(">Executing #3");
  Serial.println(">Executing #3");
  delay(1500);
}//action3

bool action4()
{
  lcd.clear();
  lcd.print(">Executing #4");
  Serial.println(">Executing #4");
  delay(1500);
}//action4

How would I add scrolling to my menu so I can go through more then 4 menu items? Would you name a int of MenuPage to cut the menu items in sections so when MenuPage = 1 lcd.setCursor gets set to 0,1 and prints the following menu items that werent displayed at MenuPage = 0 in the updateMenu section?
Would like to use this for my sub menu's as well so can have multiple items in the sub menu's.
This came after deciding or believing i'd like the date & time displayed on the first line and the menu items below that with scrolling ability to go through more menu items.
I see Switches being used in a lot of menu's online but have little experience/understanding of switches yet, and wouldn't a if(MenuPage > 4) lcd.setcursor(0,1) lcd.print(pszMenuItems*) work? Where should it go?*

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();
bool action5();

typedef bool(*myFunc)();
myFunc Functions[5] =
{
  &action1,
  &action2,
  &action3,
  &action4,
  &action5
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 0;

void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
    // Comment out below lines once you set the date & time.
      // Following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  updateMenu();
}

void loop()
{
  static unsigned long
    timeButtonRead = 0;
  static byte
    lastupButton = 0xff,
    lastselButton = 0xff,
    lastdownButton = 0xff;
  byte
    currButton;
  unsigned long
    timeNow;

  //check buttons every 75mS
  timeNow = millis();
  if (timeNow - timeButtonRead < 75)
    return;
  timeButtonRead = timeNow;

  //read the button...
  currButton = digitalRead(downButton);
  //...if it's state is not the same as last...
  if (currButton != lastdownButton)
  {
    //...save the new state
    lastdownButton = currButton;
    //if it's low indicating it has been pressed...
    if (currButton == LOW)
    {
      //process action; in this case, if menu is greater than 1...
      if (menu > 1)
      {
        //...decrement it               
        menu--;
        //and update the menu
        updateMenu();

      }//if

    }//if

  }//if

  //same comments for downbutton apply for up and select
  currButton = digitalRead(upButton);
  if (currButton != lastupButton)
  {
    lastupButton = currButton;
    if (currButton == LOW)
    {
      if (menu < 4)
      {
        menu++;
        updateMenu();

      }//if

    }//if

  }//if

  currButton = digitalRead(selectButton);
  if (currButton != lastselButton)
  {
    lastselButton = currButton;
    if (currButton == LOW)
    {
      //call the function pointed to by menu in the Functions[] array
      Functions[menu - 2]();
      //when it returns, update the menu
      updateMenu();

    }//if

  }//if

  DateTime now = rtc.now(); //Attaches now to action1 scope
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.day(), DEC);
  lcd.print(" ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
}//loop

void updateMenu()
{
  lcd.clear();
  Serial.print("\n\n\n\n");
  for (int i = 0; i < 4; i++)
  {
    //if menu line is selected, print a '>', otherwise a space
    if (i == (menu - 1))
    {
      Serial.print(">");
      lcd.setCursor(0, i);
      lcd.print(">");
      lcd.print(pszMenuItems[i-1]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
    }
    else
    {
      Serial.print(" ");
      lcd.setCursor(0, i);
      lcd.print(" ");
      lcd.print(pszMenuItems[i-1]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);

    }//else
    

  }//for

}//updateMenu

bool action1()
{
  while (1) {
    DateTime now = rtc.now(); //Attaches now to action1 scope
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Current Date & Time: ");
    lcd.setCursor(0, 1);
    lcd.print(now.year(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.day(), DEC);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    lcd.print(now.second(), DEC);
    Serial.println(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);

    if (digitalRead(downButton) == LOW) {
      delay(1000);
    }
    else {
      break;
    }
  }
}//action1

bool action2()
{
  while (1) {
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");
    if (digitalRead(downButton) == LOW)
    {
      delay(1000);
    }
    else {
      return;
    }
  }
}
//action2

bool action3()
{
  lcd.clear();
  lcd.print(">Executing #3");
  Serial.println(">Executing #3");
  delay(1500);
}//action3

bool action4()
{
  lcd.clear();
  lcd.print(">Executing #4");
  Serial.println(">Executing #4");
  delay(1500);
}//action4

bool action5()
{
  lcd.clear();
  lcd.print(">Executing #4");
  Serial.println(">Executing #4");
  delay(1500);
}//action5

Got the initial menu to displayed and execute whats selected correctly, now scrolling just needs to be added so when I hit the downButton when MenuItem2 is selected the menu scolls down to MenuItem3 and so on.

There are already libraries for displaying menus on LCD: see here

lesept:
There are already libraries for displaying menus on LCD: see here

Would be nice to see a write up of how the libary is used to build a functioning menu through multiple inputs, but till then id like to just add scrolling which shouldnt be hard after I can figure out where and what to write.

https://forum.arduino.cc/index.php?topic=529299.0

this is completely untested but hopfully this point you in the right direction.

you should be able to simply add a couple lines to the top of your display function to do this.

here is the idea

int scroll;
void updateMenu()
{
  while(menu>scroll+4&&scroll<sizeof(pszMenuItems)-4){scroll++;}
  while(menu<scroll){scroll--;}
  lcd.clear();
  Serial.print("\n\n\n\n");
  int n = 0;
  for (int i = scroll; i < 4; i++)
  {
    //if menu line is selected, print a '>', otherwise a space
    if (i == (menu - 1)&&)
    {
      Serial.print(">");
      lcd.setCursor(0, n);
      lcd.print(">");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
    }
    else
    {
      Serial.print(" ");
      lcd.setCursor(0, n);
      lcd.print(" ");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);

    }//else

 n++; }//for

}//updateMenu

Im not sure why you're subtracting one from the menu variable in your loop, but i'm sure you can adjust accordingly with this example to make it work

The idea would be to keep an index into your *pszMenuItems[]; that index indicates the first menu element to display.

With the scroll buttons, you change the index and next display the 4 items starting at that index. Be aware that the high limit is either the number of lines to display or the number of elements remaining (e.g. if index equals 2 (3rd element), you can display lines 3, 4 and 5).

The above code by taterking has a bug as far as I can see; sizeof(somePointer) returns the number of bytes, not the number of elements. The below macro gives the number of elements in any array

#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
...
...
void setup()
{
  ...
  ...
  Serial.print("You have ");
  Serial.print(NUMELEMENTS(pszMenuItems));
  Serial.println(" menu items:);
  ...
  ...

void loop()
{
  ...
  ...
}

Not tested.

i have edited my last post in responce to sterretje. please excuse.... last time i used the function it was for a byte array!!! i just ran a test and see you are correct. anyways, his array is not dynamic so he is pry best off just typing a number in there anyhow!!!!

Hard coded numbers are difficult to maintain. Change the display to a two-liner and you have to replace all 4s by 2s :wink:

Thank you very much I appreciate your help and to learn off what you posted! I am going to try this out shortly, again thank you very much so far. I have been reading my code repeatedly, googling each thing I can to try to understand it better in case I am missing something.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
	Serial.begin(9600);
	lcd.init();
	lcd.backlight();
	pinMode(upButton, INPUT_PULLUP);
	pinMode(downButton, INPUT_PULLUP);
	pinMode(selectButton, INPUT_PULLUP);
	if (!rtc.begin()) {
		Serial.println("Couldn't find RTC");
		while (1);
	}
	if (!rtc.isrunning()) {
		Serial.println("RTC lost power, lets set the time!");
		// Comment out below lines once you set the date & time.
		  // Following line sets the RTC to the date & time this sketch was compiled
		rtc.adjust(DateTime(__DATE__, __TIME__));
	}
	updateMenu();
}

void loop()
{
	static unsigned long
		timeButtonRead = 0;
	static byte
		lastupButton = 0xff,
		lastselButton = 0xff,
		lastdownButton = 0xff;
	byte
		currButton;
	unsigned long
		timeNow;

	//check buttons every 75mS
	timeNow = millis();
	if (timeNow - timeButtonRead < 75)
		return;
	timeButtonRead = timeNow;

	//read the button...
	currButton = digitalRead(downButton);
	//...if it's state is not the same as last...
	if (currButton != lastdownButton)
	{
		//...save the new state
		lastdownButton = currButton;
		//if it's low indicating it has been pressed...
		if (currButton == LOW)
		{
			//process action; in this case, if menu is greater than 1...
			if (menu > 1)
			{
				//...decrement it               
				menu--;
				//and update the menu
				updateMenu();

			}//if

		}//if

	}//if

	//same comments for downbutton apply for up and select
	currButton = digitalRead(upButton);
	if (currButton != lastupButton)
	{
		lastupButton = currButton;
		if (currButton == LOW)
		{
			if (menu < 4)
			{
				menu++;
				updateMenu();

			}//if

		}//if

	}//if

	currButton = digitalRead(selectButton);
	if (currButton != lastselButton)
	{
		lastselButton = currButton;
		if (currButton == LOW)
		{
			//call the function pointed to by menu in the Functions[] array
			Functions[menu - 2]();
			//when it returns, update the menu
			updateMenu();

		}//if

	}//if

	DateTime now = rtc.now(); //Attaches now to action1 scope
	lcd.setCursor(0, 0);
	lcd.print(now.year(), DEC);
	lcd.print('/');
	lcd.print(now.month(), DEC);
	lcd.print('/');
	lcd.print(now.day(), DEC);
	lcd.print(" ");
	lcd.print(now.hour(), DEC);
	lcd.print(':');
	lcd.print(now.minute(), DEC);
	lcd.print(':');
	lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
	while (menu > scroll + 4 && scroll < sizeof(pszMenuItems) - 4) { scroll++; }
	while (menu < scroll) { scroll--; }
	lcd.clear();
	Serial.print("\n\n\n\n");
	int n = 0;
	for (int i = scroll; i < 4; i++)
	{
		//if menu line is selected, print a '>', otherwise a space
		if (i == (menu - 1) && )
		{
			Serial.print(">");
			lcd.setCursor(0, n);
			lcd.print(">");
			lcd.print(pszMenuItems[i]);
			//print the text of the line item
			Serial.println(pszMenuItems[i]);
		}
		else
		{
			Serial.print(" ");
			lcd.setCursor(0, n);
			lcd.print(" ");
			lcd.print(pszMenuItems[i]);
			//print the text of the line item
			Serial.println(pszMenuItems[i]);

		}//else

		n++;
	}//for

}//updateMenu


bool action1()
{
	while (1) {
		DateTime now = rtc.now(); //Attaches now to action1 scope
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Current Date & Time: ");
		lcd.setCursor(0, 1);
		lcd.print(now.year(), DEC);
		lcd.print('/');
		lcd.print(now.month(), DEC);
		lcd.print('/');
		lcd.print(now.day(), DEC);
		lcd.print(" ");
		lcd.print(now.hour(), DEC);
		lcd.print(':');
		lcd.print(now.minute(), DEC);
		lcd.print(':');
		lcd.print(now.second(), DEC);
		Serial.println(now.year(), DEC);
		Serial.print('/');
		Serial.print(now.month(), DEC);
		Serial.print('/');
		Serial.print(now.day(), DEC);
		Serial.print(" ");
		Serial.print(now.hour(), DEC);
		Serial.print(':');
		Serial.print(now.minute(), DEC);
		Serial.print(':');
		Serial.print(now.second(), DEC);

		if (digitalRead(downButton) == LOW) {
			delay(1000);
		}
		else {
			break;
		}
	}
}//action1

bool action2()
{
	while (1) {
		lcd.clear();
		lcd.print(">Executing #2");
		Serial.println(">Executing #2");
		if (digitalRead(downButton) == LOW)
		{
			delay(1000);
		}
		else {
			return;
		}
	}
}
//action2

bool action3()
{
	lcd.clear();
	lcd.print(">Executing #3");
	Serial.println(">Executing #3");
	delay(1500);
}//action3

bool action4()
{
	lcd.clear();
	lcd.print(">Executing #4");
	Serial.println(">Executing #4");
	delay(1500);
}//action4

I just need to upload to test now, but my question is... int scroll; I get that this is defined but what value is it given? I just would like to know since I thought a value had to be given?

I had the delete the && at the if block deciding where to draw the ">" due to no argument after the &&.
I did test this, it enters action1() off the start which is fine, hit a button to get to the menu, time is displayed at 0,0 menuItem1 at 0,1 menuItem2 at 0,2 and menuItem3 at 0,3.
No buttons scroll the display down to the next pszMenuItems, I am going to see if I can get this to work somehow though.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
    // Comment out below lines once you set the date & time.
      // Following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  updateMenu();
}

void loop()
{
  static unsigned long
    timeButtonRead = 0;
  static byte
    lastupButton = 0xff,
    lastselButton = 0xff,
    lastdownButton = 0xff;
  byte
    currButton;
  unsigned long
    timeNow;

  //check buttons every 75mS
  timeNow = millis();
  if (timeNow - timeButtonRead < 75)
    return;
  timeButtonRead = timeNow;

  //read the button...
  currButton = digitalRead(downButton);
  //...if it's state is not the same as last...
  if (currButton != lastdownButton)
  {
    //...save the new state
    lastdownButton = currButton;
    //if it's low indicating it has been pressed...
    if (currButton == LOW)
    {
      //process action; in this case, if menu is greater than 1...
      if (menu > 1)
      {
        //...decrement it               
        menu--;
        //and update the menu
        updateMenu();

      }//if

    }//if

  }//if

  //same comments for downbutton apply for up and select
  currButton = digitalRead(upButton);
  if (currButton != lastupButton)
  {
    lastupButton = currButton;
    if (currButton == LOW)
    {
      if (menu < 4)
      {
        menu++;
        updateMenu();

      }//if

    }//if

  }//if

  currButton = digitalRead(selectButton);
  if (currButton != lastselButton)
  {
    lastselButton = currButton;
    if (currButton == LOW)
    {
      //call the function pointed to by menu in the Functions[] array
      Functions[menu - 2]();
      //when it returns, update the menu
      updateMenu();

    }//if

  }//if

  DateTime now = rtc.now(); //Attaches now to action1 scope
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.day(), DEC);
  lcd.print(" ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
  while (menu > scroll + 4 && scroll < sizeof(pszMenuItems) - 4) { scroll++; }
  while (menu < scroll) { scroll--; }
  lcd.clear();
  Serial.print("\n\n\n\n");
  int n = 0;
  for (int i = scroll; i < 4; i++)
  {
    //if menu line is selected, print a '>', otherwise a space
    if (i == (menu - 1))
    {
      Serial.print(">");
      lcd.setCursor(0, n);
      lcd.print(">");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
      n++;
    }
    else
    {
      Serial.print(" ");
      lcd.setCursor(0, n);
      lcd.print(" ");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
      n++;

    }//else

  }//for

}//updateMenu


bool action1()
{
  while (1) {
    DateTime now = rtc.now(); //Attaches now to action1 scope
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Current Date & Time: ");
    lcd.setCursor(0, 1);
    lcd.print(now.year(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.day(), DEC);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    lcd.print(now.second(), DEC);
    Serial.println(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);

    if (digitalRead(downButton) == LOW) {
      delay(1000);
    }
    else {
      break;
    }
  }
}//action1

bool action2()
{
  while (1) {
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");
    if (digitalRead(downButton) == LOW)
    {
      delay(1000);
    }
    else {
      return;
    }
  }
}
//action2

bool action3()
{
  lcd.clear();
  lcd.print(">Executing #3");
  Serial.println(">Executing #3");
  delay(1500);
}//action3

bool action4()
{
  lcd.clear();
  lcd.print(">Executing #4");
  Serial.println(">Executing #4");
  delay(1500);
}//action4

That way I atleast know what line I am on, I tried adding scroll after the && which cause the cursor to not display.
psMenuitems in the updateMenu section has its argument set to i "", the for loop stops at 4 so I guess I understand why the display wouldn't go past menuItem3.

Sorry I thought you would have seen the comment below mine. i used sizeof(pszMenuItems) to represent the number of elements in your array. but this is not working. you need to replace it with the actual size of your menu array!

yeah sorry, i must have been in a hurry when i gave the example, you shouldnt need the &&

the scroll variable is a number that represents how many lines down the screen is scrolled.

in my example there is no seperate input to scroll the screen. it should "auto" scroll with some simple math.

if the menu index variable is larger the number of lines you can display then the scroll number goes up.
if the menu index variable is less than the scroll number then the scroll goes back down.

this code should only scroll down by itself when the menu selection variable is larger than how many lines your screen can show. I am assuming that your screen shows 4 lines.

when you get to your display loop you add the scroll number to "i".

for example if your scroll number is 2.... then your loop would page from 2 to 6. displaying items 2-6.

i added another "n" variable that always goes from 0 to 3 in the loop so you can use it to set the cursor as usual.

i don't have your screen or setup so i cant work out the bugs. I have to leave it up to you to do any tweaks.

taterking:
yeah sorry, i must have been in a hurry when i gave the example, you shouldnt need the &&

the scroll variable is a number that represents how many lines down the screen is scrolled.

in my example there is no seperate input to scroll the screen. it should "auto" scroll with some simple math.

if the menu index variable is larger the number of lines you can display then the scroll number goes up.
if the menu index variable is less than the scroll number then the scroll goes back down.

this code should only scroll down by itself when the menu selection variable is larger than how many lines your screen can show. I am assuming that your screen shows 4 lines.

when you get to your display loop you add the scroll number to "i".

for example if your scroll number is 2.... then your loop would page from 2 to 6. displaying items 2-6.

i added another "n" variable that always goes from 0 to 3 in the loop so you can use it to set the cursor as usual.

i don't have your screen or setup so i cant work out the bugs. I have to leave it up to you to do any tweaks.

Yes I have a RTC1307 LCD 20x4 and 3 buttons tied to input.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
    // Comment out below lines once you set the date & time.
      // Following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  updateMenu();
}

void loop()
{
  static unsigned long
    timeButtonRead = 0;
  static byte
    lastupButton = 0xff,
    lastselButton = 0xff,
    lastdownButton = 0xff;
  byte
    currButton;
  unsigned long
    timeNow;

  //check buttons every 75mS
  timeNow = millis();
  if (timeNow - timeButtonRead < 75)
    return;
  timeButtonRead = timeNow;

  //read the button...
  currButton = digitalRead(downButton);
  //...if it's state is not the same as last...
  if (currButton != lastdownButton)
  {
    //...save the new state
    lastdownButton = currButton;
    //if it's low indicating it has been pressed...
    if (currButton == LOW)
    {
      //process action; in this case, if menu is greater than 1...
      if (menu > 1)
      {
        //...decrement it               
        menu--;
        //and update the menu
        updateMenu();

      }//if

    }//if

  }//if

  //same comments for downbutton apply for up and select
  currButton = digitalRead(upButton);
  if (currButton != lastupButton)
  {
    lastupButton = currButton;
    if (currButton == LOW)
    {
      if (menu < 4)
      {
        menu++;
        updateMenu();

      }//if

    }//if

  }//if

  currButton = digitalRead(selectButton);
  if (currButton != lastselButton)
  {
    lastselButton = currButton;
    if (currButton == LOW)
    {
      //call the function pointed to by menu in the Functions[] array
      Functions[menu - 2]();
      //when it returns, update the menu
      updateMenu();

    }//if

  }//if

  DateTime now = rtc.now(); //Attaches now to action1 scope
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.day(), DEC);
  lcd.print(" ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
  while (menu > scroll + 4 && scroll < int(pszMenuItems[5]) - 4) {
    scroll++;
  }
  while (menu < scroll) {
    scroll--;
  }
      lcd.clear();
      Serial.print("\n\n\n\n");
      int n = 0;
      for (int i = scroll; i < 4; i++)
      {
        //if menu line is selected, print a '>', otherwise a space
        if (i == (menu - 1))
        {
          Serial.print(">");
          lcd.setCursor(0, i);
          lcd.print(">");
          lcd.print(pszMenuItems[n]);
          //print the text of the line item
          Serial.println(pszMenuItems[i]);
      if (i >= 4) { lcd.setCursor(0,i); }
        }
        else
        {
          Serial.print(" ");
          lcd.setCursor(0, i);
          lcd.print(" ");
          lcd.print(pszMenuItems[n]);
          //print the text of the line item
          Serial.println(pszMenuItems[i]);

        }//else
    n++;

      }//for
    
  

}//updateMenu


bool action1()
{
  while (1) {
    DateTime now = rtc.now(); //Attaches now to action1 scope
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Current Date & Time: ");
    lcd.setCursor(0, 1);
    lcd.print(now.year(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.day(), DEC);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    lcd.print(now.second(), DEC);
    Serial.println(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);

    if (digitalRead(downButton) == LOW) {
      delay(1000);
    }
    else {
      break;
    }
  }
}//action1

bool action2()
{
  while (1) {
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");
    if (digitalRead(downButton) == LOW)
    {
      delay(1000);
    }
    else {
      break;
    }
  }
}
//action2

bool action3()
{
  lcd.clear();
  lcd.print(">Executing #3");
  Serial.println(">Executing #3");
  delay(1500);
}//action3

bool action4()
{
  lcd.clear();
  lcd.print(">Executing #4");
  Serial.println(">Executing #4");
  delay(1500);
}//action4

That's what I currently have, which only lets me scroll down to line4(menuItem3) but still doesn't scroll. Going to go back to my old code and replace exactly what you say and see what happens.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
	Serial.begin(9600);
	lcd.init();
	lcd.backlight();
	pinMode(upButton, INPUT_PULLUP);
	pinMode(downButton, INPUT_PULLUP);
	pinMode(selectButton, INPUT_PULLUP);
	if (!rtc.begin()) {
		Serial.println("Couldn't find RTC");
		while (1);
	}
	if (!rtc.isrunning()) {
		Serial.println("RTC lost power, lets set the time!");
		// Comment out below lines once you set the date & time.
		  // Following line sets the RTC to the date & time this sketch was compiled
		rtc.adjust(DateTime(__DATE__, __TIME__));
	}
	updateMenu();
}

void loop()
{
	static unsigned long
		timeButtonRead = 0;
	static byte
		lastupButton = 0xff,
		lastselButton = 0xff,
		lastdownButton = 0xff;
	byte
		currButton;
	unsigned long
		timeNow;

	//check buttons every 75mS
	timeNow = millis();
	if (timeNow - timeButtonRead < 75)
		return;
	timeButtonRead = timeNow;

	//read the button...
	currButton = digitalRead(downButton);
	//...if it's state is not the same as last...
	if (currButton != lastdownButton)
	{
		//...save the new state
		lastdownButton = currButton;
		//if it's low indicating it has been pressed...
		if (currButton == LOW)
		{
			//process action; in this case, if menu is greater than 1...
			if (menu > 1)
			{
				//...decrement it               
				menu--;
				//and update the menu
				updateMenu();

			}//if

		}//if

	}//if

	//same comments for downbutton apply for up and select
	currButton = digitalRead(upButton);
	if (currButton != lastupButton)
	{
		lastupButton = currButton;
		if (currButton == LOW)
		{
			if (menu < 4)
			{
				menu++;
				updateMenu();

			}//if

		}//if

	}//if

	currButton = digitalRead(selectButton);
	if (currButton != lastselButton)
	{
		lastselButton = currButton;
		if (currButton == LOW)
		{
			//call the function pointed to by menu in the Functions[] array
			Functions[menu - 2]();
			//when it returns, update the menu
			updateMenu();

		}//if

	}//if

	DateTime now = rtc.now(); //Attaches now to action1 scope
	lcd.setCursor(0, 0);
	lcd.print(now.year(), DEC);
	lcd.print('/');
	lcd.print(now.month(), DEC);
	lcd.print('/');
	lcd.print(now.day(), DEC);
	lcd.print(" ");
	lcd.print(now.hour(), DEC);
	lcd.print(':');
	lcd.print(now.minute(), DEC);
	lcd.print(':');
	lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
	while (menu > scroll + 4 && scroll < pszMenuItems[5] - 4) { scroll++; }
	while (menu < scroll) { scroll--; }
	lcd.clear();
	Serial.print("\n\n\n\n");
	int n = 0;
	for (int i = scroll; i < 4; i++)
	{
		//if menu line is selected, print a '>', otherwise a space
		if (i == (menu - 1))
		{
			Serial.print(">");
			lcd.setCursor(0, n);
			lcd.print(">");
			lcd.print(pszMenuItems[i]);
			//print the text of the line item
			Serial.println(pszMenuItems[i]);
			n++;
		}
		else
		{
			Serial.print(" ");
			lcd.setCursor(0, n);
			lcd.print(" ");
			lcd.print(pszMenuItems[i]);
			//print the text of the line item
			Serial.println(pszMenuItems[i]);
			n++;

		}//else

	}//for

}//updateMenu


bool action1()
{
	while (1) {
		DateTime now = rtc.now(); //Attaches now to action1 scope
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Current Date & Time: ");
		lcd.setCursor(0, 1);
		lcd.print(now.year(), DEC);
		lcd.print('/');
		lcd.print(now.month(), DEC);
		lcd.print('/');
		lcd.print(now.day(), DEC);
		lcd.print(" ");
		lcd.print(now.hour(), DEC);
		lcd.print(':');
		lcd.print(now.minute(), DEC);
		lcd.print(':');
		lcd.print(now.second(), DEC);
		Serial.println(now.year(), DEC);
		Serial.print('/');
		Serial.print(now.month(), DEC);
		Serial.print('/');
		Serial.print(now.day(), DEC);
		Serial.print(" ");
		Serial.print(now.hour(), DEC);
		Serial.print(':');
		Serial.print(now.minute(), DEC);
		Serial.print(':');
		Serial.print(now.second(), DEC);

		if (digitalRead(downButton) == LOW) {
			delay(1000);
		}
		else {
			break;
		}
	}
}//action1

bool action2()
{
	while (1) {
		lcd.clear();
		lcd.print(">Executing #2");
		Serial.println(">Executing #2");
		if (digitalRead(downButton) == LOW)
		{
			delay(1000);
		}
		else {
			return;
		}
	}
}
//action2

bool action3()
{
	lcd.clear();
	lcd.print(">Executing #3");
	Serial.println(">Executing #3");
	delay(1500);
}//action3

bool action4()
{
	lcd.clear();
	lcd.print(">Executing #4");
	Serial.println(">Executing #4");
	delay(1500);
}//action4

Does the same, does not scroll down past MenuItem3.

[code]#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
 Serial.begin(9600);
 lcd.init();
 lcd.backlight();
 pinMode(upButton, INPUT_PULLUP);
 pinMode(downButton, INPUT_PULLUP);
 pinMode(selectButton, INPUT_PULLUP);
 if (!rtc.begin()) {
 Serial.println("Couldn't find RTC");
 while (1);
 }
 if (!rtc.isrunning()) {
 Serial.println("RTC lost power, lets set the time!");
 // Comment out below lines once you set the date & time.
  // Following line sets the RTC to the date & time this sketch was compiled
 rtc.adjust(DateTime(__DATE__, __TIME__));
 }
 updateMenu();
}

void loop()
{
 static unsigned long
 timeButtonRead = 0;
 static byte
 lastupButton = 0xff,
 lastselButton = 0xff,
 lastdownButton = 0xff;
 byte
 currButton;
 unsigned long
 timeNow;

 //check buttons every 75mS
 timeNow = millis();
 if (timeNow - timeButtonRead < 75)
 return;
 timeButtonRead = timeNow;

 //read the button...
 currButton = digitalRead(downButton);
 //...if it's state is not the same as last...
 if (currButton != lastdownButton)
 {
 //...save the new state
 lastdownButton = currButton;
 //if it's low indicating it has been pressed...
 if (currButton == LOW)
 {
 //process action; in this case, if menu is greater than 1...
 if (menu > 1)
 {
 //...decrement it               
 menu--;
 //and update the menu
 updateMenu();

 }//if

 }//if

 }//if

 //same comments for downbutton apply for up and select
 currButton = digitalRead(upButton);
 if (currButton != lastupButton)
 {
 lastupButton = currButton;
 if (currButton == LOW)
 {
 if (menu < 4)
 {
 menu++;
 updateMenu();

 }//if

 }//if

 }//if

 currButton = digitalRead(selectButton);
 if (currButton != lastselButton)
 {
 lastselButton = currButton;
 if (currButton == LOW)
 {
 //call the function pointed to by menu in the Functions[] array
 Functions[menu - 2]();
 //when it returns, update the menu
 updateMenu();

 }//if

 }//if

 DateTime now = rtc.now(); //Attaches now to action1 scope
 lcd.setCursor(0, 0);
 lcd.print(now.year(), DEC);
 lcd.print('/');
 lcd.print(now.month(), DEC);
 lcd.print('/');
 lcd.print(now.day(), DEC);
 lcd.print(" ");
 lcd.print(now.hour(), DEC);
 lcd.print(':');
 lcd.print(now.minute(), DEC);
 lcd.print(':');
 lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
 while (menu > scroll - 4 && scroll < pszMenuItems[5] + 4) { scroll++; }
 while (menu < scroll and pszMenuItems[5] + 4) { scroll--; }
 lcd.clear();
 Serial.print("\n\n\n\n");
 int n = 0;
 for (int i = scroll; i < 4; i++)
 {
 //if menu line is selected, print a '>', otherwise a space
 if (i == (menu - 1))
 {
 Serial.print(">");
 lcd.setCursor(0, n);
 lcd.print(">");
 lcd.print(pszMenuItems[i]);
 //print the text of the line item
 Serial.println(pszMenuItems[i]);
 n++;
 }
 else
 {
 Serial.print(" ");
 lcd.setCursor(0, n);
 lcd.print(" ");
 lcd.print(pszMenuItems[i]);
 //print the text of the line item
 Serial.println(pszMenuItems[i]);
 n++;

 }//else

 }//for

}//updateMenu


bool action1()
{
 while (1) {
 DateTime now = rtc.now(); //Attaches now to action1 scope
 lcd.clear();
 lcd.setCursor(0, 0);
 lcd.print("Current Date & Time: ");
 lcd.setCursor(0, 1);
 lcd.print(now.year(), DEC);
 lcd.print('/');
 lcd.print(now.month(), DEC);
 lcd.print('/');
 lcd.print(now.day(), DEC);
 lcd.print(" ");
 lcd.print(now.hour(), DEC);
 lcd.print(':');
 lcd.print(now.minute(), DEC);
 lcd.print(':');
 lcd.print(now.second(), DEC);
 Serial.println(now.year(), DEC);
 Serial.print('/');
 Serial.print(now.month(), DEC);
 Serial.print('/');
 Serial.print(now.day(), DEC);
 Serial.print(" ");
 Serial.print(now.hour(), DEC);
 Serial.print(':');
 Serial.print(now.minute(), DEC);
 Serial.print(':');
 Serial.print(now.second(), DEC);

 if (digitalRead(downButton) == LOW) {
 delay(1000);
 }
 else {
 break;
 }
 }
}//action1

bool action2()
{
 while (1) {
 lcd.clear();
 lcd.print(">Executing #2");
 Serial.println(">Executing #2");
 if (digitalRead(downButton) == LOW)
 {
 delay(1000);
 }
 else {
 return;
 }
 }
}
//action2

bool action3()
{
 lcd.clear();
 lcd.print(">Executing #3");
 Serial.println(">Executing #3");
 delay(1500);
}//action3

bool action4()
{
 lcd.clear();
 lcd.print(">Executing #4");
 Serial.println(">Executing #4");
 delay(1500);
}//action4

[/code]

That provides scrolling but line2 is MenuItem2, line3 is MenuItem3, line4 is blank, and if the button is pressed I can scroll till everything below the clock is blank.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
	Serial.begin(9600);
	lcd.init();
	lcd.backlight();
	pinMode(upButton, INPUT_PULLUP);
	pinMode(downButton, INPUT_PULLUP);
	pinMode(selectButton, INPUT_PULLUP);
	if (!rtc.begin()) {
		Serial.println("Couldn't find RTC");
		while (1);
	}
	if (!rtc.isrunning()) {
		Serial.println("RTC lost power, lets set the time!");
		// Comment out below lines once you set the date & time.
		  // Following line sets the RTC to the date & time this sketch was compiled
		rtc.adjust(DateTime(__DATE__, __TIME__));
	}
	updateMenu();
}

void loop()
{
	static unsigned long
		timeButtonRead = 0;
	static byte
		lastupButton = 0xff,
		lastselButton = 0xff,
		lastdownButton = 0xff;
	byte
		currButton;
	unsigned long
		timeNow;

	//check buttons every 75mS
	timeNow = millis();
	if (timeNow - timeButtonRead < 75)
		return;
	timeButtonRead = timeNow;

	//read the button...
	currButton = digitalRead(downButton);
	//...if it's state is not the same as last...
	if (currButton != lastdownButton)
	{
		//...save the new state
		lastdownButton = currButton;
		//if it's low indicating it has been pressed...
		if (currButton == LOW)
		{
			//process action; in this case, if menu is greater than 1...
			if (menu > 1)
			{
				//...decrement it               
				menu--;
				//and update the menu
				updateMenu();

			}//if

		}//if

	}//if

	//same comments for downbutton apply for up and select
	currButton = digitalRead(upButton);
	if (currButton != lastupButton)
	{
		lastupButton = currButton;
		if (currButton == LOW)
		{
			if (menu < 4)
			{
				menu++;
				updateMenu();

			}//if

		}//if

	}//if

	currButton = digitalRead(selectButton);
	if (currButton != lastselButton)
	{
		lastselButton = currButton;
		if (currButton == LOW)
		{
			//call the function pointed to by menu in the Functions[] array
			Functions[menu - 2]();
			//when it returns, update the menu
			updateMenu();

		}//if

	}//if

	DateTime now = rtc.now(); //Attaches now to action1 scope
	lcd.setCursor(0, 0);
	lcd.print(now.year(), DEC);
	lcd.print('/');
	lcd.print(now.month(), DEC);
	lcd.print('/');
	lcd.print(now.day(), DEC);
	lcd.print(" ");
	lcd.print(now.hour(), DEC);
	lcd.print(':');
	lcd.print(now.minute(), DEC);
	lcd.print(':');
	lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
	while (menu > scroll- 4&& scroll < pszMenuItems[5]+4) { scroll++; }
	while (menu < scroll) { scroll--; }
	lcd.clear();
	Serial.print("\n\n\n\n");
	int n = 0;
	for (int i = scroll; i < 5; i++)
	{
		//if menu line is selected, print a '>', otherwise a space
		if (i == (menu - 1))
		{
			Serial.print(">");
			lcd.setCursor(0, n);
			lcd.print(">");
			lcd.print(pszMenuItems[i]);
			//print the text of the line item
			Serial.println(pszMenuItems[i]);
			//n++;
		}
		else
		{
			Serial.print(" ");
			lcd.setCursor(0, n);
			lcd.print(" ");
			lcd.print(pszMenuItems[i]);
			//print the text of the line item
			Serial.println(pszMenuItems[i]);
			//#n++;

		}//else
   n++;

	}//for

}//updateMenu


bool action1()
{
	while (1) {
		DateTime now = rtc.now(); //Attaches now to action1 scope
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Current Date & Time: ");
		lcd.setCursor(0, 1);
		lcd.print(now.year(), DEC);
		lcd.print('/');
		lcd.print(now.month(), DEC);
		lcd.print('/');
		lcd.print(now.day(), DEC);
		lcd.print(" ");
		lcd.print(now.hour(), DEC);
		lcd.print(':');
		lcd.print(now.minute(), DEC);
		lcd.print(':');
		lcd.print(now.second(), DEC);
		Serial.println(now.year(), DEC);
		Serial.print('/');
		Serial.print(now.month(), DEC);
		Serial.print('/');
		Serial.print(now.day(), DEC);
		Serial.print(" ");
		Serial.print(now.hour(), DEC);
		Serial.print(':');
		Serial.print(now.minute(), DEC);
		Serial.print(':');
		Serial.print(now.second(), DEC);

		if (digitalRead(downButton) == LOW) {
			delay(1000);
		}
		else {
			break;
		}
	}
}//action1

bool action2()
{
	while (1) {
		lcd.clear();
		lcd.print(">Executing #2");
		Serial.println(">Executing #2");
		if (digitalRead(downButton) == LOW)
		{
			delay(1000);
		}
		else {
			return;
		}
	}
}
//action2

bool action3()
{
	lcd.clear();
	lcd.print(">Executing #3");
	Serial.println(">Executing #3");
	delay(1500);
}//action3

bool action4()
{
	lcd.clear();
	lcd.print(">Executing #4");
	Serial.println(">Executing #4");
	delay(1500);
}//action4

Line2 is MenuItem2 to line4 being MenuItem4, I can execute action3() now. Scrolling down still produces blank lines from lines2-4

try changing the line that increments scroll to this:

while (menu >= scroll + 4&& scroll < pszMenuItems[5]+4) { scroll++; }

I looked it over and i think this is where the bug is and why its not adding to the scroll.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
  "clock",
  "MenuItem1",
  "MenuItem2",
  "MenuItem3",
  "MenuItem4"
};

bool action1();
bool action2();
bool action3();
bool action4();

typedef bool(*myFunc)();
myFunc Functions[4] =
{
  &action1,
  &action2,
  &action3,
  &action4
};

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (!rtc.isrunning()) {
    Serial.println("RTC lost power, lets set the time!");
    // Comment out below lines once you set the date & time.
      // Following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  updateMenu();
}

void loop()
{
  static unsigned long
    timeButtonRead = 0;
  static byte
    lastupButton = 0xff,
    lastselButton = 0xff,
    lastdownButton = 0xff;
  byte
    currButton;
  unsigned long
    timeNow;

  //check buttons every 75mS
  timeNow = millis();
  if (timeNow - timeButtonRead < 75)
    return;
  timeButtonRead = timeNow;

  //read the button...
  currButton = digitalRead(downButton);
  //...if it's state is not the same as last...
  if (currButton != lastdownButton)
  {
    //...save the new state
    lastdownButton = currButton;
    //if it's low indicating it has been pressed...
    if (currButton == LOW)
    {
      //process action; in this case, if menu is greater than 1...
      if (menu > 1)
      {
        //...decrement it               
        menu--;
        //and update the menu
        updateMenu();

      }//if

    }//if

  }//if

  //same comments for downbutton apply for up and select
  currButton = digitalRead(upButton);
  if (currButton != lastupButton)
  {
    lastupButton = currButton;
    if (currButton == LOW)
    {
      if (menu < 4)
      {
        menu++;
        updateMenu();

      }//if

    }//if

  }//if

  currButton = digitalRead(selectButton);
  if (currButton != lastselButton)
  {
    lastselButton = currButton;
    if (currButton == LOW)
    {
      //call the function pointed to by menu in the Functions[] array
      Functions[menu - 1]();
      //when it returns, update the menu
      updateMenu();

    }//if

  }//if

  DateTime now = rtc.now(); //Attaches now to action1 scope
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.day(), DEC);
  lcd.print(" ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
}//loop

int scroll;
void updateMenu()
{
  while (menu > scroll- 4&& scroll < pszMenuItems[5]+4) { scroll++; }
  while (menu < scroll) { scroll--; }
  lcd.clear();
  Serial.print("\n\n\n\n");
  int n = 1;
  for (int i = scroll; i < 5; i++)
  {
    //if menu line is selected, print a '>', otherwise a space
    if (i == menu)
    {
      Serial.print(">");
      lcd.setCursor(0, n);
      lcd.print(">");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
      n++;
    }
    else
    {
      Serial.print(" ");
      lcd.setCursor(0, n);
      lcd.print(" ");
      lcd.print(pszMenuItems[i]);
      //print the text of the line item
      Serial.println(pszMenuItems[i]);
      n++;

    }//else

  }//for

}//updateMenu


bool action1()
{
  while (1) {
    DateTime now = rtc.now(); //Attaches now to action1 scope
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Current Date & Time: ");
    lcd.setCursor(0, 1);
    lcd.print(now.year(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.day(), DEC);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    lcd.print(now.second(), DEC);
    Serial.println(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);

    if (digitalRead(downButton) == LOW) {
      delay(1000);
    }
    else {
      break;
    }
  }
}//action1

bool action2()
{
  while (1) {
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");
    if (digitalRead(downButton) == LOW)
    {
      delay(1000);
    }
    else {
      return;
    }
  }
}
//action2

bool action3()
{
  lcd.clear();
  lcd.print(">Executing #3");
  Serial.println(">Executing #3");
  delay(1500);
}//action3

bool action4()
{
  lcd.clear();
  lcd.print(">Executing #4");
  Serial.println(">Executing #4");
  delay(1500);
}//action4

That seems to work...

I saw that int n = 0; when the time is displayed at 0 I reassigned int n =1, the cursor stays at line 1 which is ok, and if I hit the down button once it moves menuItem1 up and off the screen and displays menuItem4 at the 4th line.

Couldn't see myself recoding my menu using a library when I figured scrolling could be added with the addition of a few extra lines, but I do wonder how much work it'd be to adapt LiquidMenu or even TCmenu. Could I still write in the sub menu's the exact code I want? I am using this for a environment controller so will have a relayed power strip connected to control water, lights, and maybe fans according to time and or temp/humidity.

glad you got it working. sorry for the bug

everything with your selections should work the same. the scrolling affect is just a visual display.

if you want to add sub-menus the proper way would be to put all your menu stuff into a custom class and then create an array of menus.

but if your menus are somewhat simple, you could keep things how you have them and just add all the submenu items and actions to your current arrays. then limit the menu variable to a set range depending on what submenu the user is currently on.

so you would code everything like you have it in one big menu, but it would look like seperate menus to the user.

for example if your pszMenuItems was 15 long. you could have indexes 0 to 4 represent menu 1, and 5 to 9 would represent your second menu. and 10 to 14 to represent a third menu.

if your user is on menu 1 you would prevent them from moving the menu index past 4.

if the user is on menu 2 you would force the menu index to stay between 5 and ten.

... and so on

with this approach you could add submenu capability with what you have plus a few more lines of code!!!

taterking:
glad you got it working. sorry for the bug

everything with your selections should work the same. the scrolling affect is just a visual display.

if you want to add sub-menus the proper way would be to put all your menu stuff into a custom class and then create an array of menus.

but if your menus are somewhat simple, you could keep things how you have them and just add all the submenu items and actions to your current arrays. then limit the menu variable to a set range depending on what submenu the user is currently on.

so you would code everything like you have it in one big menu, but it would look like seperate menus to the user.

for example if your pszMenuItems was 15 long. you could have indexes 0 to 4 represent menu 1, and 5 to 9 would represent your second menu. and 10 to 14 to represent a third menu.

if your user is on menu 1 you would prevent them from moving the menu index past 4.

if the user is on menu 2 you would force the menu index to stay between 5 and ten.

... and so on

with this approach you could add submenu capability with what you have plus a few more lines of code!!!

Yea I saw the concept your talking about in another menu's code for a 16x2 display where if menupage = 1,2,3,etc. it'd display the menuitems that fit the display according to the menupage variable, which I appreciate and may end up going that route if more submenus are added.
I'm going to have to read about classes because I would like my submenu's to have the ability to adjust what time a relay is turned on and off, for another submenu have the ability to adjust the humidity level's for a relay to come on, and another submenu to adjust for when a relay should be activated at what given temp.
I'd also like to display sensor values in those submenu's so having a scrolling ability allows me to feel comfortable writing what I feel is sufficient. I would like to add datalogging as a submenu to save time and dates relays are turned on and sensor values.