8x8 Matrix / MAX7219 Help

I am building a kids busy board and one of its features is a 8x8 matrix and two toggle switches, when switch up and arrow up displays on the matrix, when its down an arrow down appears etc...

The switches are also hooked up to a mp3 sound fx board so when the switch is up the matrix displays up and you also hear the spoken word "up".
The sound side is a second circuit so there is no coding for it here.

Now everything is working but i would like to clear the display after a couple of seconds, i can't use the normal delay(2000); as this blocks the switches from being used.

can anyone think of a way i can clear the screen after a couple of seconds?

I have heard about using mills but every time i try, i just can't get it to work.
to be honest i am new to all this and i have worked out delay and editing most code but mills is way over my head.

I'm using an Arduino nano ooard with a MAX7219 8x8 matrix on a shield.

Thank you in advance for any help and advice.

Here is my code

#include <LedControl.h>
#include <ezButton.h>

ezButton button1(2);  // create ezButton object that attach to pin 2;
ezButton button2(4);  // create ezButton object that attach to pin 4;
ezButton button3(6);  // create ezButton object that attach to pin 6;
ezButton button4(8);  // create ezButton object that attach to pin 8;

const int DIN_PIN = 12;
const int CS_PIN = 11;
const int CLK_PIN = 10;

//////
const byte CLEAR[][8] = {
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000
};
const int IMAGES_C = sizeof(CLEAR) / 8;
//////


byte LEFT[][8] = {
  B00000000,
  B00001000,
  B00011000,
  B00111111,
  B01111111,
  B00111111,
  B00011000,
  B00001000
};

int IMAGES_L = sizeof(LEFT) / 8;

byte RIGHT[][8] = {
  B00000000,
  B00010000,
  B00011000,
  B11111100,
  B11111110,
  B11111100,
  B00011000,
  B00010000
};

int IMAGES_R = sizeof(RIGHT) / 8;

byte UP[][8] = {
  B00000000,
  B00001000,
  B00011100,
  B00111110,
  B01111111,
  B00011100,
  B00011100,
  B00011100
};

int IMAGES_U = sizeof(UP) / 8;

byte DOWN[][8] = {
  B00011100,
  B00011100,
  B00011100,
  B01111111,
  B00111110,
  B00011100,
  B00001000,
  B00000000
};

int IMAGES_D = sizeof(DOWN) / 8;


LedControl display = LedControl(DIN_PIN, CLK_PIN, CS_PIN);


void setup() {

  display.clearDisplay(0);
  display.shutdown(0, false);
  display.setIntensity(0, 10);
  button1.setDebounceTime(200); // set debounce time to 50 milliseconds
  button2.setDebounceTime(200); // set debounce time to 50 milliseconds
  button3.setDebounceTime(200); // set debounce time to 50 milliseconds
  button4.setDebounceTime(200); // set debounce time to 50 milliseconds
}

void displayImage(const byte* image) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      display.setLed(0, i, j, bitRead(image[i], 7 - j));
    }
  }
}

int i = 0;

void loop() {

  button1.loop(); // MUST call the loop() function first
  button2.loop(); // MUST call the loop() function first
  button3.loop(); // MUST call the loop() function first
  button4.loop(); // MUST call the loop() function first

  int btn1State = button1.getState();
  int btn2State = button2.getState();
  int btn3State = button3.getState();
  int btn4State = button4.getState();

  if (button1.isPressed())
    displayImage(UP[i]);
  if (++i >= IMAGES_U ) {
    i = 0;
  }

  if (button2.isPressed())
    displayImage(DOWN[i]);
  if (++i >= IMAGES_D ) {
    i = 0;
  }

  if (button3.isPressed())
    displayImage(LEFT[i]);
  if (++i >= IMAGES_L ) {
    i = 0;
  }

  if (button4.isPressed())
    displayImage(RIGHT[i]);
  if (++i >= IMAGES_R ) {
    i = 0;
  }

}

Save the value of millis() when the start action occurs and set a boolean to true to indicate that timing is taking place.
Each time through loop(), if the boolean is true then test whether the required period has elapsed by subtracting the start value from the current value of millis(). If so, act accordingly.
If the start action is cancelled/negated/no longer valid before the period elapses then set the boolean to false

Thank you for your quick reply.

I have spent a few days on this and could find nothing to help me.

This worked a treat thank you.

Could you show the new sketch ?

My examples "Fun with millis" show such a single shot timer in "millis_single_delay.ino"

Did you know that there are libraries with fonts ?
I think the Parola library has a font, and this project has its own font in the file "Font7Seg.h". If you look at that file, you see that it is put in Flash memory with "PROGMEM", so it does not use any SRAM.

If you add things to your project, then you might use too much SRAM someday and you have to move the data to PROGMEM.

Here is the code i am using

#include <LedControl.h>
#include <ezButton.h>

ezButton button1(2);  // create ezButton object that attach to pin 2;
ezButton button2(4);  // create ezButton object that attach to pin 4;
ezButton button3(6);  // create ezButton object that attach to pin 6;
ezButton button4(8);  // create ezButton object that attach to pin 8;

const int DIN_PIN = 12;
const int CS_PIN = 11;
const int CLK_PIN = 10;

//////
const byte CLEAR[][8] = {
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000
};
const int IMAGES_C = sizeof(CLEAR) / 8;
//////


byte LEFT[][8] = {
  B00000000,
  B00001000,
  B00011000,
  B00111111,
  B01111111,
  B00111111,
  B00011000,
  B00001000
};

int IMAGES_L = sizeof(LEFT) / 8;

byte RIGHT[][8] = {
  B00000000,
  B00010000,
  B00011000,
  B11111100,
  B11111110,
  B11111100,
  B00011000,
  B00010000
};

int IMAGES_R = sizeof(RIGHT) / 8;

byte UP[][8] = {
  B00000000,
  B00001000,
  B00011100,
  B00111110,
  B01111111,
  B00011100,
  B00011100,
  B00011100
};

int IMAGES_U = sizeof(UP) / 8;

byte DOWN[][8] = {
  B00011100,
  B00011100,
  B00011100,
  B01111111,
  B00111110,
  B00011100,
  B00001000,
  B00000000
};

int IMAGES_D = sizeof(DOWN) / 8;


LedControl display = LedControl(DIN_PIN, CLK_PIN, CS_PIN);


void setup() {

  display.clearDisplay(0);
  display.shutdown(0, false);
  display.setIntensity(0, 10);
  button1.setDebounceTime(200); // set debounce time to 50 milliseconds
  button2.setDebounceTime(200); // set debounce time to 50 milliseconds
  button3.setDebounceTime(200); // set debounce time to 50 milliseconds
  button4.setDebounceTime(200); // set debounce time to 50 milliseconds
}

void displayImage(const byte* image) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      display.setLed(0, i, j, bitRead(image[i], 7 - j));
    }
  }
}

int i = 0;

//////
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod )
  {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

unsigned long MyTimer;
////

void loop() {

  button1.loop(); // MUST call the loop() function first
  button2.loop(); // MUST call the loop() function first
  button3.loop(); // MUST call the loop() function first
  button4.loop(); // MUST call the loop() function first

  int btn1State = button1.getState();
  int btn2State = button2.getState();
  int btn3State = button3.getState();
  int btn4State = button4.getState();

  if (button1.isPressed())
    displayImage(UP[i]);
  if (++i >= IMAGES_U ) {
    i = 0;
  if (TimePeriodIsOver(MyTimer,2000)){
    displayImage(CLEAR[i]);
  }
  }

  if (button2.isPressed())
    displayImage(DOWN[i]);
  if (++i >= IMAGES_D ) {
    i = 0;
  }

  if (button3.isPressed())
    displayImage(LEFT[i]);
  if (++i >= IMAGES_L ) {
    i = 0;
  }

  if (button4.isPressed())
    displayImage(RIGHT[i]);
  if (++i >= IMAGES_R ) {
    i = 0;
  }
}