使重繪時不做清除底圖的動作,減少閃爍的情況,
但並不是所有的情況都可以不清除底圖直接繪上新圖,
例如若要在花色背景上打字,為了不讓字產生底色,我們會將DC的屬性設為透明,
dc.SetBkMode(TRANSPARENT);
例如先前已經印上 99%,不清除背景的狀況上更新為 100%,
在透明字體的情況下就會發生字體重疊的囧況,
為免這種情況發生我們只好重新再把花色背景畫上去一次,
如此就可以在不清除背景的情況下讓字不會重疊,
但是重畫背景是粍時的工作,顯示卡在螢幕上畫出每一條線也可能造成閃爍,
如此我們就要想辦法不要一直在螢幕上畫圖,使用 Memory DC 是個好方法。
原本使用 CWnd 的 dc.DrawText(); dc.LineTo(); 等等這些動作,
其實每條指令都會佔用顯示卡請它將資訊輸出至螢幕,相當粍時,
現在我們改成在記憶體中的一塊 dc 上作畫,
將佔用顯示卡的頻率降至將 memory dc 貼到 CWnd dc 上這麼一次就好,
貼的動作是使用記憶體複製,遠比一條一條指令請顯示卡畫快多了,
使用Memory DC的範例如下
// Dlg.h
class CDlg : CDialog
{
private:
CDC m_dcMem; // 宣告一塊畫布
CBitmap m_bmp; // 宣告一張點陣圖
CFont m_fontSet; // 宣告一個字型
};
// Dlg.cpp
BOOL CDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // 設定大圖示
SetIcon(m_hIcon, FALSE); // 設定小圖示
CDC* pDC = GetDC(); // 取得目前視窗的DC
m_dcMem.CreateCompatibleDC(NULL); // 初始化MemDC
// 也可以指定和 CWnd DC 一樣的格式 m_dcMem.CreateCompatibleDC(pDc);
// 將m_bmp初始化為C_MAXWIDTH、C_MAXHEIGHT大小,並指定和pDC相同格式
m_bmp.CreateCompatibleBitmap(pDC, C_MAXWIDTH, C_MAXHEIGHT);
m_dcMem.SelectObject(&m_bmp); // Mem DC選擇一張點陣圖
m_dcMem.SetBkMode(TRANSPARENT); // 視需求設為透明底圖
ReleaseDC(pDC); // 釋放CWnd DC
// 當然 Memory DC 也可以設定字型、筆刷等條件
m_dcMem.SelectObject(m_fontSet);
return TRUE;
}
這時我們可以在任意時間利用 dcMem.DrawText() 等方式畫上資訊,
當然畫面都不會有任何改變,因為我們畫的是記憶體中的畫布,
在 OnPaint() 時我們再將 dcMem 貼到 CWnd 的 DC 上,
void ChundredSingerDlg::OnPaint()
{
CPaintDC dc(this);
dc.BitBlt(0, 0,
m_rcClient.Width(),
m_rcClient.Height(), /* 以上4個參數指定貼到CWnd DC的哪裡 */
&m_dcMem, /* 來源 */
0, 0, /* 從來源的哪個座標開始貼 */
SRCCOPY /* 使用複製的方式貼上 */);
}
如此不論我們對 Memory DC 做多複雜的指令,畫面也不會閃爍,
要更新資訊時,只需要使用非常快速的記憶體複製貼上 Memory DC 即可。
Memory DC 不一定要宣告為類別成員物件,
做為 OnPaint() 裡面的 local variable 再一次畫好貼上也可以,
但如此就必須每次 OnPaint 時都做一次 Mem DC 的初始化動作,
所以我習慣將 Memory DC 與 Bitmap 宣告為類別成員省去常常初始化的時間。
沒有留言:
張貼留言