MiterV
MiterV

Reputation: 65

How to reduce the complexity of a GUI program

There is a problem confused me a lot.
I use C language to display GUI in the Embedded device.Just like the following example.

  title  
1.xxxx 2.xxxx  
3.xxxx 4.xxxx  
5.xxxx 6.xxxx      

I use the keypad to choose which item i need.but the item often has is's sub-item and I have to draw the menu and set the function again.Just like the follwing shows.

  title             title             title  
1.xxxx 2.xxxx  press 1  1.xxxx 2.xxxx press 2   1.xxxx 2.xxxx  
3.xxxx 4.xxxx --------------> 3.xxxx 4.xxxx  --------------> 3.xxxx 4.xxxx  
5.xxxx 6.xxxx       5.xxxx 6.xxxx       5.xxxx 6.xxxx    

Now I use the following code temple to set the function i need.

GrawAndGetKeyCode( "0.xxxx||1.xxxx||2.xxxx||3.xxxx||4.xxxx", "title", &nSelect);
switch(nSelect)
{
    case 0:
        fuction();
        break;
    case 1:
        fuction();
        break;
    case 2:
        fuction();
        break;
    case 3:
        fuction();
        break;
    case 4:
        fuction();
        break;
    default:
        break;
}

I wonder if there is some way i can use the menu1.item1.subitem2() to figure out the function i need?

Thanks a lot!!!

Upvotes: 0

Views: 137

Answers (2)

You may have a structure for menu items, each structure contains a label to be shown and a function pointer to be invoked. Then, your DrawMenuAndExecute function may take an array of menu_items and draw them, take the input and execute the corresponding function. Here is a working example:

#include <stdio.h>
#include <stdlib.h>

typedef void (* MENUFUNCPTR)();

struct menu_item {
  const char *menu_item;
  MENUFUNCPTR func;
};

void DrawMenuAndExecute(struct menu_item *items, size_t n) {
  size_t i;
  int opt;
  int cont = 1;
  // draw the menu
  for (i = 0; i < n; ++i) {
    printf("%3d: %s\n", (int)(i+1), items[i].menu_item);
  }
  printf("Your selection: ");
  while (cont) {
    scanf("%d", &opt);
    if (opt > 0 && opt <= n) {
      cont = 0;
    }
    else {
      printf("Wrong selection, your selection again: ");
    }
  }
  opt--;
  if (items[opt].func != NULL) {
    (*(items[opt].func))();
  }
}

void main_menu();
void item1_item1();
void item1_item2();
void item1();
void item2();
void item3();
void item4();

void main_menu() {
  struct menu_item items [] = {
    { "Item 1 (has submenu)", &item1 },
    { "Item 2 (count to ten)", &item2 },
    { "Item 3 (write something)", &item3 },
    { "Exit", &item4 }
  };
  DrawMenuAndExecute(items, 4);
}

void item1_item1() {
  printf("Hello, how're you? (since I don't care, I won't let you type.)\n");
  item1();
}

void item1_item2() {
  main_menu();
}

void item1() {
  // item1 has a sub menu
  struct menu_item items [] = {
    { "Write something", &item1_item1 },
    { "Previous Menu", &item1_item2 }
  };
  DrawMenuAndExecute(items, 2);
}

void item2() {
  int i = 1;
  for (; i <= 10; ++i) {
    printf("%d ", i);
  }
  printf("\n");
  main_menu();
}

void item3() {
  printf("Something.\n");
  main_menu();
}

void item4() {
  exit(0);
}

int main(int argc, char **argv) {
  main_menu();
}

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409356

A simple menu system like that could be implemented using a simple state-machine.

Maybe something like this (warning: pseudo-ish code):

typedef void (*handler_t)(void);  // Menu handler function type

handler_t * current_handlers;
char *current_menu;

// The top-level menu
handler_t top_menu_handlers[] = {
    top_menu_1,
    top_menu_2,
    top_menu_3
};

char *top_menu = "..."; // Menu text for the top menu

// One sub-menu
handler_t sub_menu_1_handlers[] = {
    sub_menu_1_1,
    sub_menu_1_2,
    sub_menu_1_3
};

char *sub_menu_1 = "...";

// Another sub-menu
handler_t sub_menu_2_handlers[] = {
    sub_menu_2_1,
    sub_menu_2_2,
    sub_menu_2_3
};

char *sub_menu_2 = "...";

// ...

// Initialization
current_handlers = top_menu_handlers;
current_menu = top_menu;

// The state machine
for (;;)  // Infinite loop
{
    clear_screen();
    print_menu(current_menu);

    int selection = get_input();

    current_handlers[selection]();  // Call menu function
}

// ...

void top_menu_1(void)
{
    // When user selects `1` in the top menu, go to first sub-menu
    current_handlers = sub_menu_1_handlers;
    current_menu = sub_menu_1;
}

// ...
void sub_menu_1_3(void)
{
    // When the user select `3` in the first sub-menu, go back to top menu
    current_handlers = top_menu_handlers;
    current_menu = top_menu;
}

It's a lot of work to set up initially, but then it makes the code more general, and it's easier to add new alternatives or menus. And most importantly, it can be much more automated (by e.g. making the menu tree into an actual tree structure, and making the state-machine code handle the menu changing instead of having handler functions change it).

Upvotes: 1

Related Questions