Windows客戶端開發中,UI實作往往佔據 60% 以上工時。本文介紹自研 SonicUI 引擎核心技術,針對多格式圖片、富文本超連結、自繪按鈕、髒矩形區域刷新、異形視窗(含像素級Alpha)五大高頻痛點,提供零依賴、純GDI+、SSE2優化的輕量解決方案,實測繪圖效率較 CxImage 提升 4-10 倍。
引擎架構總覽
- 核心導出:單一
GetSonicUI() 工廠函數,返回 ISonicUI* 介面
- 組件模型:
ISonicImage、ISonicString、ISonicPaint、ISonicWndEffect 等介面
- 委托機制:類似 C# delegate,綁定全域函數/成員函數作為回調
- 髒矩形優化:所有組件內建區域追蹤,
Redraw() 僅重繪變更區域
- 無視窗繪製:按鈕、超連結等皆為無視窗組件,避免 HWND 開銷
核心功能模組實戰
1. 多格式圖片支援(含 Alpha 通道)
系統 LoadImage 僅支援 BMP/ICO。SonicUI 內建 CxImage 解碼,並將所有浮點運算(旋轉、HSL、灰階)轉為整數 + SSE2 指令優化。
// 三步完成 PNG 透明圖片繪製
ISonicImage* pImg = GetSonicUI()->CreateImage();
pImg->Load(L"C:\\ui\\button_hover.png"); // 支援:PNG/JPG/GIF/BMP/TIF/ICO...
pImg->Draw(hdc, 10, 10); // 自動 Alpha Blending
GetSonicUI()->DestroyObject(pImg);
- 資源載入:
pImg->LoadResource(IDR_PNG1, L"IMAGE") —— 資源類型必須命名為 IMAGE
- DC載入:
pImg->LoadFromDC(hdcSrc, rect)
- 色鍵透明:
pImg->SetColorKey(RGB(255,0,255)) —— 指定單一顏色為透明
2. 富文本與超連結(HTML-like 控制字元)
ISonicString 以控制字元實現字體、顏色、超連結、圖文混排,支援滑鼠互動(進入/點擊/離開)。
ISonicString* pStr = GetSonicUI()->CreateString();
// 格式化:/c=顏色, a=超連結URL, font, font_height=16/顯示文字
pStr->Format(L"/c=%x, a='https://hi.csdn.net/zskof', font, font_height=16/點我開啟連結",
RGB(0, 0, 255));
// WM_PAINT 中輸出
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
switch (msg) {
case WM_PAINT: {
PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps);
pStr->TextOut(hdc, 0, 0, hWnd); // 傳 hWnd 讓內部處理滑鼠訊息
EndPaint(hWnd, &ps);
break;
}
}
return DefWindowProc(hWnd, msg, wp, lp);
}
控制字元完整語法
| 字元 | 功能 | 範例 |
/c=RRGGBB | 文字顏色 | /c=FF0000/紅字 |
/font | 字體名稱 | /font=微軟正黑體/ |
/font_height=N | 字體高度 | /font_height=14/ |
/a=URL | 超連結 | /a='https://...'/點我 |
/u=1 | 底線 | /u=1/底線文字 |
/p=ImageID | 插入圖片 | /p=123/ |
/animation=MS | 狀態切換漸變動畫 | /animation=40/ |
圖文混排與圖片超連結
ISonicImage* pImg = GetSonicUI()->CreateImage();
pImg->Load(L"logo.png");
ISonicString* pStr = GetSonicUI()->CreateString();
// /p=ImageID 插入圖片,a=URL 為圖片加超連結
pStr->Format(L"/c=%x/你好,朋友/p=%d, a='https://example.com'/",
RGB(0,0,255), pImg->GetObjectId());
3. 自繪按鈕(三態 + 漸變動畫)
無視窗按鈕,透過 ISonicString 承載 Normal/Hover/Click 三態圖片,支援 QQ2009 風格漸變切換。
// 載入三態圖片(或單圖三態平鋪)
ISonicImage* pNormal = GetSonicUI()->CreateImage(); pNormal->Load(BMP_NORMAL); pNormal->SetColorKey(RGB(255,0,255));
ISonicImage* pHover = GetSonicUI()->CreateImage(); pHover->Load(BMP_HOVER); pHover->SetColorKey(RGB(255,0,255));
ISonicImage* pClick = GetSonicUI()->CreateImage(); pClick->Load(BMP_CLICK); pClick->SetColorKey(RGB(255,0,255));
ISonicString* pBtn = GetSonicUI()->CreateString();
// p=Normal, ph=Hover, pc=Click, linkt=提示文字
pBtn->Format(L"/a, p=%d, ph=%d, pc=%d, linkt='點我移動'/",
pNormal->GetObjectId(), pHover->GetObjectId(), pClick->GetObjectId());
// 加上漸變動畫:animation=速度(ms)
pBtn->Format(L"/a, p=%d, ph=%d, pc=%d, linkt='點我', animation=40/", ...);
// 委托點擊事件
void WINAPI OnBtnClick(ISonicString* pStr, LPVOID) {
g_pEffect->MoveGently(0, 0); // 觸發視窗移動特效
}
pBtn->Delegate(DELEGATE_EVENT_CLICK, NULL, NULL, OnBtnClick);
// WM_PAINT 中輸出
pBtn->TextOut(hdc, x, y, hWnd);

圖1:三態按鈕 + 漸變動畫效果
4. 髒矩形區域刷新系統
GDI 繪圖效率低,InvalidateRect(hwnd, NULL, TRUE) 全域重繪極其浪費。SonicUI 提供 ISonicPaint 畫布物件,內建髒區域追蹤與自動區域合併。
// 建立畫布(可選擇是否擁有獨立 MemDC)
ISonicPaint* pPaint = GetSonicUI()->CreatePaint();
pPaint->Create(FALSE, width, height); // FALSE=無獨立MemDC,共用目標DC
// 委托自定義繪製邏輯
class CRenderer {
public:
void OnPaint(ISonicPaint* pPaint, LPVOID) {
if (!pPaint->GetCurrentPaint()) return;
HDC hdc = pPaint->GetCurrentPaint()->hdc;
int x = pPaint->GetCurrentPaint()->x;
int y = pPaint->GetCurrentPaint()->y;
// 在此繪製...
}
};
CRenderer renderer;
pPaint->Delegate(DELEGATE_EVENT_PAINT, NULL, &renderer, &CRenderer::OnPaint);
// 需要重繪時,僅呼叫
pPaint->Redraw(); // 內部自動計算髒區域、合併、僅重繪變更區域
畫布支援直接添加子組件
pPaint->AddObject(pImage); // 添加圖片
pPaint->AddObject(pString); // 添加文字
pPaint->AddObject(pSubPaint); // 添加子畫布(巢狀)
// 所有子組件自動享有髒區域優化
5. 異形視窗(含像素級 Alpha 透明)
兩種實現模式,視需求選擇:
模式 A:區域裁剪(SetWindowRgn)
// 根據圖片非透明區域建立 HRGN
HRGN hRgn = pImg->CreateRgn(); // 內部掃描 Alpha > 0 的像素
SetWindowRgn(hWnd, hRgn, TRUE);
- 優點:相容性好、無層疊視窗限制
- 缺點:邊緣鋸齒、拖動殘影、不支援半透明
模式 B:分層視窗(WS_EX_LAYERED + UpdateLayeredWindow)——推薦
ISonicWndEffect* pEffect = GetSonicUI()->CreateWndEffect();
// TRUE = 像素級 Alpha 模式(UpdateLayeredWindow)
pEffect->Attach(hWnd, TRUE);
// 依圖片 Alpha 通道自動裁剪視窗形狀
pEffect->SetShapeByImage(pImg);
- 優點:完美半透明、邊緣平滑、拖動無殘影、支援淡入淡出
- 缺點:不支援 WS_CHILD 視窗、需 Win2000+、效能略高
分層視窗文字繪製難題解決
GDI TextOut 不支援 Alpha,直接繪製會出現方塊邊緣。SonicUI 內建字體 Alpha 通道合成:
// ISonicString 內部實現:
// 1. 建立 32-bit DIBSection
// 2. GDI 繪製文字到 DIB
// 3. 像素級合成 Alpha 通道
// 4. UpdateLayeredWindow 送顯
// 使用者無感知,直接 pStr->TextOut(hdc, x, y, hWnd) 即可

圖2:像素級 Alpha 異形視窗 + 文字正確合成
效能基準測試(CPU: T2330 1.6GHz)
| 操作 | CxImage (浮點) | SonicUI (整數+SSE2) | 提升倍數 |
| 圖片旋轉 90° | 12.4 ms | 1.8 ms | 6.9x |
| HSL 色調調整 | 8.7 ms | 1.2 ms | 7.3x |
| 灰階轉換 | 5.3 ms | 0.9 ms | 5.9x |
| Alpha Blending | 3.1 ms | 0.7 ms | 4.4x |
其他內建組件(篇幅限制略過詳述)
ISonicMarquee:跑馬燈/滾動字幕,支援暫停/續播/速度控制
ISonicAnimation:關鍵幀動畫,支援缓動函數、循環/反向/彈跳
ISonicTooltip:智慧工具提示,自動避開螢幕邊緣
ISonicScrollBar:自繪捲軸,支援觸控慣性滾動
設計原則與擴充建議
- 輕便:核心 DLL < 500KB,無 MFC/ATL/WTL 依賴,純 Win32 + GDI+
- 高效:SSE2 優化、髒矩形、無視窗組件、延遲繪製
- 易用:HTML-like 控制字元、委托回調、工廠模式統一建構
- 開放:歡迎提交 Issue/PR,共同完善(聯繫作者獲取原始碼合作)
SonicUI 目前為公司內部專案資產,完整源碼暫不公開,但核心技術細節(SSE2 優化策略、髒區域算法、分層視窗文字合成)歡迎技術交流探討。
- 上一篇文章: 將Lua腳本引擎嵌入C/C++應用程式完整實戰指南
- 下一篇文章: 任意數學表達式解析計算引擎設計與實現:支援函數嵌套、多變量、遞歸下降解析
Copyright ©
程式碼之家 All Rights Reserved