在螢幕右下角 (系統托盤區) 顯示非模態提示視窗,支援兩種動畫:
AnimateWindow + AW_BLEND)
#define ID_TIMER_POP_WINDOW 1 // 滑入
#define ID_TIMER_DISPLAY_DELAY 2 // 停留
#define ID_TIMER_CLOSE_WINDOW 3 // 滑出
class CMsgWnd : public CWnd {
int m_nHeight = 0;
const int WIN_WIDTH = 300, WIN_HEIGHT = 150;
void OnTimer(UINT nIDEvent) {
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
RECT rcWork; SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
int x = rcWork.right - WIN_WIDTH;
int y = rcWork.bottom;
switch (nIDEvent) {
case ID_TIMER_POP_WINDOW: // 滑入
if (m_nHeight <= WIN_HEIGHT) {
++m_nHeight;
MoveWindow(x, y - m_nHeight, WIN_WIDTH, WIN_HEIGHT);
Invalidate(FALSE);
} else {
KillTimer(ID_TIMER_POP_WINDOW);
SetTimer(ID_TIMER_DISPLAY_DELAY, 5000, NULL); // 停留 5 秒
}
break;
case ID_TIMER_DISPLAY_DELAY: // 停留結束
KillTimer(ID_TIMER_DISPLAY_DELAY);
SetTimer(ID_TIMER_CLOSE_WINDOW, 20, NULL);
break;
case ID_TIMER_CLOSE_WINDOW: // 滑出
if (m_nHeight >= 0) {
--m_nHeight;
MoveWindow(x, y - m_nHeight, WIN_WIDTH, m_nHeight);
} else {
KillTimer(ID_TIMER_CLOSE_WINDOW);
SendMessage(WM_CLOSE);
}
break;
}
CWnd::OnTimer(nIDEvent);
}
// 建立時啟動
int OnCreate(LPCREATESTRUCT lpCS) {
if (CWnd::OnCreate(lpCS) == -1) return -1;
SetTimer(ID_TIMER_POP_WINDOW, 20, NULL); // 20ms/幀 ≈ 50 FPS
return 0;
}
};
// 顯示時
AnimateWindow(GetSafeHwnd(), 1000, AW_CENTER | AW_BLEND | AW_ACTIVATE);
// 關閉時
AnimateWindow(GetSafeHwnd(), 1000, AW_HIDE | AW_CENTER | AW_BLEND);
關鍵旗標:
| 旗標 | 效果 |
|---|---|
AW_BLEND | 淡入/淡出 (僅限最上層視窗) |
AW_CENTER | 從中心展開/收縮 |
AW_SLIDE | 滑動 (需搭配 AW_HOR_POSITIVE 等方向旗標) |
AW_ACTIVATE | 顯示後啟動視窗 |
AW_HIDE | 執行隱藏動畫 |
void CMsgWnd::OnEraseBkgnd(CDC* pDC) {
// 不呼叫預設擦除,由 OnPaint 統一繪製背景+內容
return TRUE;
}
void CMsgWnd::OnPaint() {
CPaintDC dc(this);
CRect rc; GetClientRect(&rc);
// 雙緩衝
CMemDC memDC(&dc, &rc);
memDC.FillSolidRect(&rc, RGB(255, 255, 200)); // 淡黃背景
memDC.DrawText(m_strMsg, &rc, DT_CENTER|DT_VCENTER|DT_WORDBREAK);
}
CMemDC 為 Keith Rule 經典雙緩衝類別,專案中已包含。
void CMainFrame::ShowNotification(LPCTSTR pszMsg) {
CMsgWnd* pWnd = new CMsgWnd();
pWnd->CreateEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
AfxRegisterWndClass(CS_SAVEBITS, LoadCursor(NULL, IDC_ARROW),
(HBRUSH)GetStockObject(WHITE_BRUSH)),
_T("MsgTip"), WS_POPUP, 0, 0, 300, 150, NULL, NULL);
pWnd->SetMessage(pszMsg);
// 視窗會自動動畫顯示並自我銷毀
}
WS_EX_TRANSPARENT (需配合 WS_EX_LAYERED)GetDpiForWindow 縮放尺寸與字體CImage) 實現圓角、陰影MSN 風格以 MoveWindow + 定時器實現像素級控制,適合需精確軌跡的場景;QQ 風格以系統級 AnimateWindow 一行搞定,適合快速集成。兩者均在 VC6.0+Win2000 驗證通過。