透過串口接收資料 (每秒 1 點),在 MFC 對話框/視圖繪製軌跡圖 (圓形軌跡)。需解決繪圖效能、執行緒安全、UI 回應問題。
// Worker Thread 執行緒函數
UINT SerialReadThread(LPVOID pParam) {
CMyView* pView = (CMyView*)pParam;
BYTE buf[256];
while (!pView->m_bStopThread) {
DWORD dwRead;
if (ReadFile(pView->m_hComm, buf, sizeof(buf), &dwRead, NULL) && dwRead > 0) {
// 解析座標 (假設協定固定)
int x = buf[0]; int y = buf[1];
// 關鍵:PostMessage 送至 UI 執行緒,不可直接呼叫 UI 方法!
pView->PostMessage(WM_USER_NEW_POINT, (WPARAM)x, (LPARAM)y);
}
Sleep(10); // 避免佔滿 CPU
}
return 0;
}
// UI 執行緒訊息處理
#define WM_USER_NEW_POINT (WM_USER + 1)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_MESSAGE(WM_USER_NEW_POINT, OnNewPoint)
END_MESSAGE_MAP()
LRESULT CMyView::OnNewPoint(WPARAM wParam, LPARAM lParam) {
int x = (int)wParam;
int y = (int)lParam;
m_points.Add(CPoint(x, y)); // 儲存歷史點 (CArray/CList)
// 觸發重繪 (僅無效化最小區域)
CRect rect(x-3, y-3, x+3, y+3);
InvalidateRect(rect, FALSE);
return 0;
}
void CMyView::OnDraw(CDC* pDC) {
// 雙緩衝防閃爍
CMemDC memDC(pDC, &rectClip); // 自定義雙緩衝類或用 CMemoryDC
// 繪製所有歷史點
CPen pen(PS_SOLID, 1, RGB(255,0,0));
CPen* pOldPen = memDC.SelectObject(&pen);
for (CPoint pt : m_points) {
memDC.Ellipse(pt.x-2, pt.y-2, pt.x+2, pt.y+2);
}
memDC.SelectObject(pOldPen);
}
MFC 繪圖雙緩衝完整範例:MFC 雙緩衝繪圖實戰
MFC 即時繪圖核心是 **「工作執行緒收資料 → PostMessage → UI 執行緒儲存點 → InvalidateRect → OnDraw 雙緩衝繪製」**。`SetPixel`/`Ellipse` 效能足夠應付每秒幾十點;若上千點需優化,改用 `PolyLine` 批次繪製 + 虛擬清單只畫可視區域。