增強經典 CStaticLink 類別,新增完整鍵盤無障礙支援:Tab 鍵切換焦點、焦點矩形視覺提示、空白鍵啟動連結(符合對話框慣例)、解決 /clr 混合模式下 ShellExecute 失效問題,附 LinkTest 範例驗證。
Tabstop = True(或手動加 WS_TABSTOP),使控件進入 Tab 順序。WM_SETFOCUS/WM_KILLFOCUS 呼叫 DrawFocusRect():
void CStaticLink::DrawFocusRect() {
CWnd* pParent = GetParent(); CRect rc;
if (GetStyle() & (SS_BITMAP|SS_ICON|SS_ENHMETAFILE|SS_OWNERDRAW)) {
GetWindowRect(&rc); // 圖片用視窗矩形
} else {
CClientDC dc(this); CString s; GetWindowText(s);
CFont* pOld = dc.SelectObject(GetFont());
rc.SetRectEmpty(); dc.DrawText(s, &rc, DT_CALCRECT); // 精確文字外接矩形
dc.SelectObject(pOld); ClientToScreen(&rc);
}
rc.InflateRect(1,1); pParent->ScreenToClient(&rc);
CClientDC dcParent(pParent); dcParent.DrawFocusRect(&rc); // 父視窗 DC 繪製 XOR 矩形
}
關鍵:文字項目用 DT_CALCRECT 計算緊貼矩形,避免寬大靜態控件產生巨大焦點框;繪製於父視窗 DC 以超出控件邊界。WM_CHAR 攔截 VK_SPACE 呼叫 Navigate(),前置 WM_GETDLGCODE 回傳 DLGC_WANTCHARS 讓對話框轉發字元訊息。原因:/clr 強制多執行緒單元(MTA),ShellExecute 依賴 IShellExecuteHook(單執行緒單元 STA 專用),導致存取被拒(錯誤碼 5)。
方案一:CSTAThread 強制 STA(推薦):
class CSTAThread { public: CSTAThread() { CoInitialize(NULL); } ~CSTAThread() { CoUninitialize(); } };
// 應用程式模組 (如 MyApp.cpp) 靜態實例:
CSTAThread forceSTAThread; // 建構早於 MFC 內部 CoInitializeEx(COINIT_MULTITHREADED)
方案二:rundll32.exe 間接啟動(相容 MTA):
CString args; args.Format(_T("url.dll,FileProtocolHandler %s"), url);
ShellExecute(NULL, _T("open"), _T("rundll32.exe"), args);
缺點:無法取得錯誤回傳碼。
方案三:.NET Process.Start + [STAThread]:純 .NET 適用,MFC 難以注入屬性。
CStaticLink 內建 CSTAThread,自動適應原生與 /clr 專案。LinkTest 範例包含托管測試對話框,驗證混合模式下超連結正常啟動瀏覽器。
超連結宜置於 Tab 順序末尾,避免對話框啟動焦點落於商標連結、或編輯框間跳躍穿插超連結,符合使用者預期流程。