首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Visual C++ 程式設計技巧:視圖背景色與對話框標題的正確設定時機

     編輯:關於VC++

前言

MFC 文檔/視圖架構複雜,初學者常在「程式碼放哪裡」上踩坑。本文透過兩個經典案例——設定視圖背景色、動態修改對話框標題——揭示 MFC 訊息迴路與視窗生命週期的關鍵時機差異。

案例一:視圖背景色設定

錯誤嘗試 1:系統色彩 SetSysColors

修改 COLOR_WINDOW 會影響**全系統**所有視窗,造成視覺混亂,不可取。

錯誤嘗試 2:在 OnDraw 中繪製背景

void CTestView::OnDraw(CDC* pDC)
{
    CRect rectClient; GetClientRect(rectClient);
    CBrush brush; brush.CreateSolidBrush(RGB(255,0,0));
    pDC->DPtoLP(rectClient);
    pDC->FillRect(rectClient, &brush);
    // ... 其他繪圖
}

後果:OnDraw 因視窗縮放、資料更新(Invalidate)頻繁被呼叫。每次先由系統用 WM_ERASEBKGND 以預設白色擦除,再由 OnDraw 重疊紅色,**必然產生閃爍**。

正確解法:攔截 WM_ERASEBKGND

在 OnDraw 之前,Windows 會發送 WM_ERASEBKGND 要求擦除背景。預設由視窗類別的 hbrBackground 畫刷處理(通常是 COLOR_WINDOW)。我們應在此訊息中完成背景填充,並回傳 TRUE 告知系統「已處理」,避免預設擦除動作。

實作步驟

  1. **文檔類別**新增成員 COLORREF m_viewBkColor 及存取函式,支援序列化(開啟文檔自動還原背景色)。
  2. **視圖類別**用 ClassWizard 為 WM_ERASEBKGND 新增 OnEraseBkgnd:
    BOOL CTestView::OnEraseBkgnd(CDC* pDC)
    {
        CRect rect; pDC->GetClipBox(&rect); // 僅取得需重繪區域
        CBrush brush; brush.CreateSolidBrush(GetDocument()->GetViewBkColor());
        pDC->FillRect(&rect, &brush);
        return TRUE; // 關鍵:阻止預設擦除
    }
  3. **選單命令**修改顏色:
    void CTestView::OnChangeViewBkcolor()
    {
        CColorDialog dlg;
        if (dlg.DoModal() == IDOK) {
            GetDocument()->SetViewBkColor(dlg.GetColor());
            InvalidateRect(NULL); // 觸發 WM_ERASEBKGND → OnEraseBkgnd
        }
    }

優勢:無閃爍、僅重繪裁剪區域、背景色隨文檔持久化。

案例二:動態設定對話框標題

錯誤嘗試:DoModal 前呼叫 SetWindowText

CTestDialog dlg;
dlg.SetWindowText(_T("標題-1")); // 無效!
dlg.DoModal();

原因:MFC 對話框為**動態建立**。CTestDialog dlg 僅構造 C++ 物件,真正的視窗控制代碼(HWND)在 DoModal() 內部呼叫 CreateDialogIndirect 時才建立。視窗未建立前呼叫 SetWindowText 無效;DoModal 返回後視窗已銷毀,同樣無效。

正確解法:在 OnInitDialog 中設定

  1. 對話框類別新增 public: CString m_strCaption;
  2. 呼叫端設定成員變數:
    CTestDialog dlg;
    dlg.m_strCaption = _T("標題-1");
    dlg.DoModal();
  3. 覆寫 OnInitDialog:
    BOOL CTestDialog::OnInitDialog()
    {
        CDialog::OnInitDialog(); // 必須呼叫基類
        SetWindowText(m_strCaption); // 此時 HWND 已存在
        return TRUE;
    }

原理:DoModal 內部流程:建立視窗 → 發送 WM_INITDIALOG → MFC 對映至 OnInitDialog → 顯示視窗 → 進入訊息迴圈。此時設定標題剛好在視窗可見前完成。

核心心得

兩個技巧的共同點:**相同的程式碼,放在正確的訊息/生命週期節點,效果截然不同**。掌握 MFC 訊息對映順序、視窗建立/銷毀時機、Invalidate/WM_PAINT/WM_ERASEBKGND 互動關係,是寫出高效、無閃爍、行為正確 VC++ 程式的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved