C語言本身**無內置GUI庫**,所有圖形界面均依賴第三方庫。選型取決於目標平台、授權要求、性能需求、開發效率與團隊技術棧。
| 類別 | 代表庫 | 授權 | 平台 | 特點 | 學習曲線 |
|---|---|---|---|---|---|
| 跨平台成熟 | GTK | LGPL | Linux/Win/macOS | GNOME基石、控件豐富、C原生 | 中等 |
| 跨平台現代 | Qt (C++但有C綁定) | GPL/LGPL/商業 | 全平台+嵌入式 | 功能最全、QML聲明式、工具鏈完善 | 較陡峭 |
| 跨平台輕量 | IUP | MIT | Win/Linux/macOS | Lua綁定佳、原生外觀、API簡潔 | 平緩 |
| 跨平台極簡 | Nuklear, Dear ImGui | MIT/公共域 | 全平台 | 即時模式、單頭文件、適合工具/調試界面 | 極低 |
| Windows原生 | Win32 API | 專有 | 僅Windows | 零依賴、底層控制、代碼冗長 | 極陡峭 |
| 嵌入式專用 | LVGL, µGFX, emWin | MIT/商業 | 裸機/RTOS | 無OS運行、內存極省、硬件加速 | 中等 |
| 教學/復古 | graphics.h (Turbo C) | 專有 | DOS/模擬器 | 教學入門、無現代應用價值 | 平緩 |
| Web技術 | Electron/Tauri + C後端 | MIT | 全平台 | 前端生態豐富、C做核心邏輯 | 前端高 |
// GTK 4 最小示例
#include <gtk/gtk.h>
static void on_activate(GtkApplication *app) {
GtkWidget *win = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(win), "Hello GTK");
gtk_window_set_default_size(GTK_WINDOW(win), 400, 300);
GtkWidget *btn = gtk_button_new_with_label("Click Me");
g_signal_connect(btn, "clicked", G_CALLBACK(gtk_window_close), win);
gtk_window_set_child(GTK_WINDOW(win), btn);
gtk_widget_show(win);
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("com.example", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
編譯:gcc main.c -o main `pkg-config --cflags --libs gtk4`
// IUP 示例
#include <iup.h>
int main() {
IupOpen(NULL, NULL);
Ihandle *dlg = IupDialog(IupVbox(
IupLabel("Hello IUP"),
IupButton("Exit", "ACTION=IUP_CLOSE"),
NULL));
IupShowXY(dlg, IUP_CENTER, IUP_CENTER);
IupMainLoop();
IupClose();
return 0;
}
// Nuklear 單頭文件風格
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_IMPLEMENTATION
#include "nuklear.h"
// 渲染後端需自行實現 (OpenGL/SDL/Vulkan/Metal/DirectX/軟件渲染)
// 核心循環:
struct nk_context *ctx = nk_init_default(alloc, NULL);
while (running) {
nk_input_begin(ctx);
// 處理事件 -> nk_input_xxx(ctx, ...)
nk_input_end(ctx);
if (nk_begin(ctx, "Demo", nk_rect(50,50,200,200), NK_WINDOW_BORDER)) {
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "Button")) { /* action */ }
}
nk_end(ctx);
// 渲染: nk_convert + 後端繪製
}
nk_free(ctx);
// 最小 Win32 窗口 (約 70 行)
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY: PostQuitMessage(0); return 0;
case WM_PAINT: {
PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 50, 50, L"Hello Win32", 11);
EndPaint(hwnd, &ps); return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, PWSTR, int) {
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.lpszClassName = L"MinWin32";
RegisterClass(&wc);
HWND hwnd = CreateWindow(wc.lpszClassName, L"Win32 Demo", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInst, NULL);
ShowWindow(hwnd, SW_SHOW);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); DispatchMessage(&msg);
}
return 0;
}
| 階段 | 推薦庫 | 核心收穫 |
|---|---|---|
| 入門理解GUI原理 | Win32 API / SDL2 | 消息循環、事件驅動、繪製管線、資源管理 |
| 跨平台桌面開發 | GTK 4 / IUP | 控件佈局、信號槽、CSS樣式、國際化、打包分發 |
| 嵌入式GUI開發 | LVGL (PC模擬器起步) | 內存優化、幀緩衝、輸入設備抽象、無OS移植 |
| 現代聲明式UI | Qt QML / Flutter (Dart) | 聲明式編程、狀態管理、動態UI、熱重載 |
graphics.h / Turbo C 做實際項目