2013-01-07 82 views
3

我想創建一個最大10行窗口的菜單,並在窗口中顯示xml文件中的所有項目(包含超過10個項目),通過在窗口中向上/向下滾動查看文件的全部內容。滾動菜單(c代碼)

問題:如何實現這一點在我的API(如在ncurses的滾動菜單):

「如果一個窗口給出的子窗口是不是足夠大,以顯示所有的項目,然後將菜單將滾動。當你在當前列表中的最後一項時,如果你發送REQ_DOWN_ITEM,它將被轉換爲REQ_SCR_DLINE,並且菜單會滾動一個項目,你可以手動給REQ_SCR_操作做滾動,讓我們看看它是如何完成的。我的這個特徵代碼

部分:

static void menu(commands_t *cmd) 
{ 
    /* this display only first 10 line */ 
    int i; 
    char string[ 128 ]; 
    for(i = 0; i < 10; i++) { 
     snprintf(string, sizeof (string), "%s", list_get_name(cmd->listmgr, i)); 
     menu_list_set_text(cmd->menu, i, string); 
    } 
} 

目前,該功能只能顯示從列表中的第10個項目。

     A 
         B 
         C 
         D 
         E 
       ----------------- 
Line 01   |  F  | 
Line 02   |  G  | 
Line 03   |  H  | 
Line 04   |  I  | 
Line 05   |  J  |  
Line 06   |  K  | 
Line 07   |  L  | 
Line 08   |  M  | 
Line 09   |  N  | 
Line 10   |  O  | 
       ----------------- 
         P 
         Q 
         R 
         S 
         T 
        ....... 
         Z 

爲此,我試圖創建一個能夠設置在從列表菜單行文本API,在菜單向上/向下移動光標,但我現在該怎麼做出向上或向下移動線沒有。

typedef struct list_info_s list_info_t; 
struct list_info_s 
{ 
    int position; 
    char name[ 50 ]; 

    list_info_t *next; 
    list_info_t *prev; 
}; 

const list_info_t *list_get_list(list_mgr_t *mgr, int pos) 
{ 
    const list_info_t *tmp = mgr->first; 
    int i; 
    for (i = 0; tmp && i < pos; i++) 
     tmp = tmp->next; 
    return tmp; 
} 

const char *list_get_name(list_mgr_t *mgr, int position) 
{ 
    const list_info_t *list = list_get_list(mgr, position); 
    if((list) && (*list->name)) { 
     return list->name; 
    } else { 
     return 0; 
    } 
} 

TO MOVE UP/DOWN: 

void commands_handle(commands_t *cmd, int prog_cmd) 
{ 
    switch(prog_cmd) { 
    case MENU_UP: 
     cmd->menu_position = (cmd->menu_position + cmd->menu_size - 1) % (cmd->menu_size); 
     menu(cmd); 
     break; 
    case MENU_DOWN: 
     cmd->menu_position = (cmd->menu_position + 1) % (cmd->menu_size); 
     menu(cmd); 
     break; 
    return; 
    } 
} 


MENU: 


static void menu(commands_t *cmd) 
{ 
    /* this display only first 10 line */ 
    int i; 
    char string[ 128 ]; 
    for(i = 0; i < 10; i++) { 
     snprintf(string, sizeof (string), "%s", list_get_name(cmd->listmgr, i)); 
     menu_list_set_text(cmd->menu, i, string); 
    } 
} 

由於xml可能包含大量項目,因此菜單的窗口最多可用於10個項目行。 什麼編程選項必須通過向上/向下按鈕來顯示文件中的所有行以在菜單上可見?

這是菜單實際API:

#define MENU_MAX 10 

struct menu_s 
{ 
    char *name; 
    char text[ MENU_MAX ][ 128 ]; 
    char arguments[ MENU_MAX ][ 128 ]; 
    int commands[ MENU_MAX ]; 
    char back_argument[ 128 ]; 
    int back_command; 
    int numlines; 
    int cursor; 
    int defaultcursor; 
}; 

menu_t *menu_new(const char *name) 
{ 
    menu_t *menu = malloc(sizeof(menu_t)); 
    if(!menu) { 
    return 0; 
    } 

    menu->numlines = 0; 
    menu->cursor = 0; 
    menu->defaultcursor = 0; 
    menu->name = strdup(name); 
    if(!menu->name) { 
     free(menu); 
     return 0; 
    } 

    return menu; 
} 

void menu_delete(menu_t *menu) 
{ 
    free(menu->name); 
    free(menu); 
} 

void menu_reset_num_lines(menu_t *menu) 
{ 
    menu->numlines = 0; 
} 

void menu_set_text(menu_t *menu, int line, const char *text) 
{ 
    snprintf(menu->text[ line ], sizeof(menu->text[ 0 ]), "%s", text); 
    if(line >= menu->numlines) menu->numlines = line + 1; 
} 

void menu_set_enter_command(menu_t *menu, int line, int command, 
         const char *argument) 
{ 
    menu->commands[ line ] = command; 
    snprintf(menu->argum#define MENU_MAX 10 

struct menu_s 
{ 
    char *name; 
    char text[ MENU_MAX ][ 128 ]; 
    char arguments[ MENU_MAX ][ 128 ]; 
    int commands[ MENU_MAX ]; 
    char back_argument[ 128 ]; 
    int back_command; 
    int numlines; 
    int cursor; 
    int defaultcursor; 
}; 

menu_t *menu_new(const char *name) 
{ 
    menu_t *menu = malloc(sizeof(menu_t)); 
    if(!menu) { 
    return 0; 
    } 

    menu->numlines = 0; 
    menu->cursor = 0; 
    menu->defaultcursor = 0; 
    menu->name = strdup(name); 
    if(!menu->name) { 
     free(menu); 
     return 0; 
    } 

    return menu; 
} 

void menu_delete(menu_t *menu) 
{ 
    free(menu->name); 
    free(menu); 
} 

void menu_reset_num_lines(menu_t *menu) 
{ 
    menu->numlines = 0; 
} 

void menu_set_text(menu_t *menu, int line, const char *text) 
{ 
    snprintf(menu->text[ line ], sizeof(menu->text[ 0 ]), "%s", text); 
    if(line >= menu->numlines) menu->numlines = line + 1; 
} 

void menu_set_enter_command(menu_t *menu, int line, int command, 
         const char *argument) 
{ 
    menu->commands[ line ] = command; 
    snprintf(menu->arguments[ line ], sizeof(menu->arguments[ 0 ]), 
      "%s", argument); 
} 

void menu_set_back_command(menu_t *menu, int command, 
         const char *argument) 
{ 
    menu->back_command = command; 
    snprintf(menu->back_argument, sizeof(menu->back_argument), 
      "%s", argument); 
} 

void menu_set_cursor(menu_t *menu, int cursor) 
{ 
    menu->cursor = cursor; 
} 

const char *menu_get_name(menu_t *menu) 
{ 
    return menu->name; 
} 

int menu_get_num_lines(menu_t *menu) 
{ 
    return menu->numlines; 
} 

const char *menu_get_text(menu_t *menu, int line) 
{ 
    return menu->text[ line ]; 
} 

int menu_get_enter_command(menu_t *menu, int line) 
{ 
    return menu->commands[ line ]; 
} 

const char *menu_get_enter_argument(menu_t *menu, int line) 
{ 
    return menu->arguments[ line ]; 
} 

int menu_get_back_command(menu_t *menu) 
{ 
    return menu->back_command; 
} 

const char *menu_get_back_argument(menu_t *menu) 
{ 
    return menu->back_argument; 
} 

int menu_get_cursor(menu_t *menu) 
{ 
    return menu->cursor; 
} 

int menu_get_default_cursor(menu_t *menu) 
{ 
    return menu->defaultcursor; 
} 

我嘗試了醜陋的解決方案:

static void menu(commands_t *cmd) 
{ 
    int i; 
    for(i = 0; i < 10; i++) { 
     char string[ 128 ]; 
     snprintf(string, sizeof (string), "%s", list_get_name(cmd->listmgr, i) 
     menu_list_set_text(cmd->menu, i, string); 
     int scroll; 
     for(scroll = 0; scroll < list_size; scroll++) { 
      if(cmd->curmenupos == 10 + scroll) { 
       snprintf(string, sizeof (string), "%s", list_get_name(cmd->listmgr, i + scroll + 1) 
       menu_list_set_text(cmd->menu, i, string); 
      } 
     } 
     } 
    } 

其中 「CMD-> curmenupos」 是命令來獲取菜單線位置和 「list_size」是來自xml的項目數量

+4

你的問題是什麼? – OldProgrammer

+4

難道你不能只使用[ncurses](http://en.wikipedia.org/wiki/Ncurses)?請參閱[滾動菜單示例](http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/menus.html#SCROLLMENUS)。 – jweyrich

+0

這是OSD菜單 – user1840007

回答

0

您可以通過使用基於陣列的ring buffer實現來簡化您的解決方案,然後僅打印您的菜單從左上角的頭部/尾部。然後滾動只是推進頭部/尾部,並覆蓋與新的消失的線。無論如何,使用基於數組的實現應該沒問題,因爲你的行號是恆定的。

根據IO的速度有多慢,軟件可能會使用較少的IO資源,從而通過簡單地緩存舊線路來提高性能。 Keep in mind not to prematurely optimize這可以通過讓環形緩衝區有比屏幕上的行更多的條目來完成,然後只有在滾動經過某個點時纔會覆蓋。