首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言實現類 Windows 可配置菜單系統:基於 curses 與外部參數文件

     編輯:關於C語言

專案背景

在 Unix/Linux 字符終端環境下開發具有圖形化界面(TUI)的應用程序,curses/ncurses 庫是標準選擇。本專案實現一個高度可配置、無需重新編譯即可擴展功能的下拉菜單系統,靈感來源於 Windows 應用程序的菜單欄。核心設計:菜單結構與顯示參數完全外部化到文本配置文件,實現「數據驅動界面」。

系統架構:兩大配置文件

1. menu.def — 菜單項定義

格式:!菜單代號!項順序號!菜單項名稱!外掛程序名稱!下級菜單代號!


!0!1!文件操作!0!10!      // 主菜單項1,有子菜單10
!0!2!系統設置!0!20!      // 主菜單項2,有子菜單20
!0!3!格式化磁盤!format /dev/rfd0135ds18!0!  // 主菜單項3,執行外部命令,無子菜單
!10!1!讀取文件!read_file!0! // 子菜單10 項1,內部函數
!10!2!寫入文件!write_file!0!
  • 菜單代號=0 表示主菜單。
  • 外掛程序=0 表示調用內部函數或進入子菜單。
  • 下級菜單=0 表示無子菜單(葉子節點)。
  • 項順序號 兼作熱鍵(如數字鍵 1-9)。

2. menu.conf — 菜單顯示參數

格式:!菜單代號!上級代號!邊框標志!寬度!行數!列數!起始X!起始Y!


!0!-1!1!30!10!1!5!5!   // 主菜單:有框,寬30,10行1列,位置(5,5)
!10!0!1!25!5!1!10!10!  // 子菜單10:父0,有框,寬25,5行1列,位置(10,10)
  • 修改此文件即可調整菜單位置、大小、邊框、佈局,無需改代碼。

核心數據結構


// 雙向鏈表節點:菜單項
struct menu {
    short menu_code;      // 所屬菜單代號
    short item_order;     // 項順序/熱鍵
    char item[20];        // 顯示名稱
    char prog[80];        // 外掛程序/內部命令
    short submenu_code;   // 子菜單代號
    struct menu *next, *prev; // 雙向鏈表指針
};

// 菜單顯示配置
struct menuconf {
    short menu_code, last_code;
    short bord_flag;      // 0無框 1有框
    short m_wight, m_lengh, m_col; // 寬、高(行)、列數
    short m_bx, m_by;     // 起始座標
};

// 窗口管理 (curses WINDOW*)
WINDOW *menuwin, *boxwin, *curw, *lastw[MAX_M], *workwin;

關鍵模塊解析

1. 初始化與配置讀取

  • initial():initscr()、cbreak()、noecho()、keypad() 標準 curses 初始化。
  • getmenuconf(code):解析 menu.conf 指定行,填充 m_conf 全局結構。解析器按 ! 分隔字段,atoi/strcpy 賦值。
  • getitem():讀取 menu.def,篩選屬於當前 menu_no 的項,構建雙向鏈表 head,並創建 curses 窗口 menuwin、邊框窗口 boxwin。

2. 菜單事件循環 domenu()

核心狀態機:

  • scrpos:當前高亮項指針。
  • curpos:當前項在頁內的線性索引 (0-based)。
  • wgetch(curw) 獲取按鍵:

3. 顯示輔助函數

  • disponepage():按行列佈局 (m_lengh 行, m_col 列) 繪製當前頁菜單項。
  • revcurpos()/nomlastpos():利用 wattrset(A_STANDOUT/A_NORMAL) 實現高亮切換。
  • dispnextline()/dispprevline():處理鍵盤導航觸發的視窗捲動,更新 begin/last 頁邊界指針。

4. 外部程序執行 execprog()


void execprog() {
    system("clear");                    // 清屏
    fprintf(stderr, "%s:\n", scrpos->item); // 顯示菜單名
    system(scrpos->prog);               // 執行外部命令
    keycont();                          // 等待按鍵
    initial();                          // 重新初始化 curses
    touchwin(boxwin); touchwin(curw);   // 標記窗口需重繪
    wrefresh(boxwin); wrefresh(curw);
}

編譯與運行


cc -o menu menu.c -lcurses   // SCO OpenServer 5.05 驗證通過
// 現代 Linux: gcc -o menu menu.c -lncurses

運行前需準備 menu.def、menu.conf 於當前目錄。

設計亮點與現代化啟發

  1. 配置驅動:菜單結構、外觀、綁定命令完全數據化,符合「開閉原則」(對擴展開放,對修改關閉)。
  2. 狀態棧管理子菜單:lastw[MAX_M] 等數組模擬棧,支援多級嵌套菜單無縫切換與返回。
  3. curses 窗口管理:邊框窗口 boxwin 與內容窗口 curw 分離,捲動時操作內容窗口不破壞邊框。
  4. 可移植性:標準 curses/ncurses API,跨 Unix/Linux/Windows (PDCurses) 直接編譯。

現代開發可將此思想移植至:

  • ncurses + JSON/TOML 配置 替代自定義文本格式。
  • TUI 框架 (如 ratatui Rust, Textual Python, ftxui C++) 實現更豐富組件。
  • 插件系統:prog 欄位指向動態庫 .so 入口函數,而非 system() 調用,實現進程內擴展,性能與安全性更優。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
按鍵動作
Enter若有子菜單 → 遞歸進入 domenu() (保存父菜單狀態到棧 lastw, lastscr, lastmenucur);若為外部命令 → endwin() 恢復終端執行 system();若為內部函數 → 調用對應處理。
Esc/q/Q/0返回上級菜單 (恢復父窗口、高亮位置、配置);若無父菜單 (last_code=-1) → 退出程序。
方向鍵更新 scrpos、curpos,處理換頁/捲動 (wdeleteln/winsertln + dispnextline/dispprevline),調用 nomlastpos() 恢復舊項正常顏色,revcurpos() 高亮新項 (A_STANDOUT 屬性)。
R/刷新鍵wrefresh(curscr) 重繪全屏。