打開vc+的mfc工程,先載入一張圖片,ID爲IDB_BITMAP2
TestDlg.h中:
CBrush m_brBk;//在public中定義
TestDlg.cpp中:
在初始化函數OnInitDialog()中加入:
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP2);
m_brBk.CreatePatternBrush(&bmp);
bmp.DeleteObject();
return TRUE; // return TRUE unless you set the focus to a control
}
再打開類嚮導,找到WM_CTLCOLOR消息,重載得對應函數OnCtlColor(),
添加以下:
HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd == this)
{
return m_brBk;
}
return hbr;
}
按照上面的方法一路COPY下來運行,OK!而且因爲圖片是作爲背景顯示的,因此再添的按鈕都能很好的顯示出來,很是方便。
總結一下其中出現的變量和函數。
CBrush:類CBrush封裝了Windows圖形設備接口(GDI)中的畫刷,畫刷也就是採起什麼方案填充圖形的背景的工具。
OnInitDialog ( ):用於對對話框類的變量的初始化(注意:是在產生對話框以前就初始化),是WM_INITDIALOG消息產生的消
息處理函數,覆蓋該函數可改變對話框初始設置。
用法:
virtual BOOL OnInitDialog();返回值指定對話框是否對它的一個控件設置輸入焦點。若是OnInitDialog返回非零
值,Windows 將輸入焦點設在對話框的第一個控件上,只有在對話框明確將輸入焦點設在某控件上,應用返回0。
CBitmap:類CBitmap封裝了Windows圖形設備接口(GDI)中的位圖,而且提供操縱位圖的成員函數。
LoadBitmap ( ):CBitmap類的一個成員函數,從應用的可執行文件中加載一個命名的位圖資源來初始化位圖對象。
用法:
BOOL LoadBitmap( LPCTSTR lpszRecourceName );BOOL LoadBitmap( UINT nIDResource );返回值調用成功時返回非零值,
不然爲0。參數lpszResourceName指向一個包含了位圖資源名字的字符串(該字符串以null結尾)。NIDResource指定位圖資源
中資源的ID號。本函數從應用的可執行文件中加載由lpszResourceName指定名字或者由nIDResource指定的ID號標誌的位圖資
源。加載的位圖被附在Cbitmap對象上。若是由lpszResourceName指定名字的對象不存在,或者沒有足夠的內存加載位圖,函
數將返回0。能夠調用函數CgdiObject::DeleteObject刪除由LoadBitmap加載的位圖,不然Cbitmap的析構函數將刪除該位圖對象。
CreatePatternBrush ( ):CBrush類的一個成員函數,用位圖指定的模式初始化畫刷。
用法:
BOOL CreatePatternBrush( CBitmap* pBitmap );返回值調用成功時返回非零值,不然爲0。參數pBitmap指定一個位圖。本
函數用位圖指定的模式初始化畫刷。此畫刷隨後就可用於任何支持光柵操做的設備上下文。由bBitmap指定的位圖通常用如下
的函數初始化:CBitmap:: CreateBitmap、CBitmap::CreateBitmapIndirect、CBitmap::LoadBitmap或Cbitmap::
CreateCompatibleBitmap。
DeleteObject ( ):CgdiObject類的一個成員函數,從內存中刪除附加給CGdiObject的Windows GDI對象,釋放與此對象相關
的系統存儲空間。GdiObject類爲各類Windows圖形設備接口(GDI)對象,如位圖、區域、畫刷、畫筆、調色板、字體等提供
了一些基本類。咱們不會直接構造一個CGdiObject對象,而是使用某一個派生類如CPen或CBrush建立。
用法:
BOOL DeleteObject( );若是GDI對象被成功刪除,則返回非零值,不然爲0。經過釋放附加的GDI對象佔有的系統存儲來刪除它
們。與CGdiObject對象有關的存儲不受此調用的影響。若是CGdiObject對象正被選入設備上下文中,則應用不可對此對象調用
DeleteObject,。當一個模式畫刷被刪除時,與之相關聯的位圖不被刪除。位圖必須被獨立刪除。
HBRUSH:數據類型,用於定義畫刷句柄。在Windows環境中,句柄是用來標識項目的,這些項目包括:module, task,
instance, file ,block of memory, menu, control, font, resource, icon, cursor, string, GDI object等,包括
bitmap, brush, metafile, palette, pen, region以及設備描述表device context。實際上,句柄是一個標識符,用來表示
對象或者項目,是一個32位的正整數。應用程序幾乎老是經過調用一個Windows函數來得到一個句柄,以後其餘的Windows函數
就可使用這個句柄,以引用相應的對象。
WM_CTLCOLOR消息:WM_CTLCOLOR是一個由控制(Control)發送給它父窗口的通知消息(Notification message)。利用嚮導映射
該消息產生函數:HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);參數pDC是TestDlg的設備上下
文,pWnd是TestDlg中發送該消息的control指針,nCtlColor是Control的類型編碼。WM_CTLCOLOR是系統在繪製控件的時候自
動發送的,若是須要自定義,就截取這個消息並重載它的響應函數,用classWizard添加WM_CTLCOLOR消息而後編輯其
OnCtlColor函數。這樣Windows嚮應用程序發送消息WM_CTLCOLOR,應用程序處理WM_CTLCOLOR消息並返回一個用來繪畫窗體背
景的刷子句柄
====================================
//放在OnPaint()裏
{//設置背景圖片
CRect rect;
GetClientRect(&rect);
CDC *pDC=GetDC();
CDC memdc;
memdc.CreateCompatibleDC(pDC);
CBitmap bitmap;
//從資源中載入位圖
bitmap.LoadBitmap(IDB_BITMAP1);
memdc.SelectObject(bitmap);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memdc,0,0,SRCCOPY);
}
==========================================
對於VC++文檔、視結構中的視圖,從用戶的角度來看,只是能夠改變大小、位置的普通窗口,同其餘基於Windows應用程序的窗口是同樣的;從程序員的 角度來看,視圖並非普通的窗口,而是從MFC庫中CView類派生的類對象。像任何VC++對象同樣,視圖對象的行爲由類的成員函數(數據成員)決定, 包括派生類中應用程序定義的函數和從基類繼承來的函數。 程序員
提出問題
視圖的背景通常來講是白色的,在缺省狀況下,它和系統定義的顏色COLOR_WINDOW是一致的。設計者通常會但願本身的 程序可讓用戶輕鬆地改變窗口背景顏色,或是用漂亮的圖片來充填背景。咱們能夠用Windows函數SetSysColors來從新指定 COLOR_WINDOW所對應的實際顏色,來達到改變視圖背景顏色的目的。但這樣會同時改變其餘應用程序的視圖窗口背景,使得整個Windows系統的 顏色設置產生混亂。另外,咱們可能會用如下方法來設置視圖的背景顏色,即在CView的OnDraw函數中添寫以下一段程序代碼:
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rectClient;
CBrush brushBkColor;
GetClientRect(rectClient);
brushBkColor.CreateSolidBrush(RGB(255,0,0));
pDC->DPtoLP(rectClient);
pDC->FillRect(rectClient,&brushBkColor);
…
}
這樣能夠達到改變當前應用程序的視圖背景的目的,但同時也產生了一些不良影響,使得程序運行效果不盡如人意。 框架
分析問題
咱們知道,在VC++的文檔、視結構中,CView的OnDraw函數用於實現絕大部分圖形繪製的工做。若是用戶改變窗口尺寸, 或者顯示隱藏的區域,OnDraw函數都將被調用來重畫窗口。而且,當程序文檔中的數據發生改變時,通常必須經過調用視圖的Invalidate(或 InvalidateRect)成員函數來通知Windows所發生的改變,對Invalidate的調用也會觸發對OnDraw函數的調用。正由於 OnDraw函數被頻繁調用,因此在其執行時,每次都刷新填充一次視圖客戶區域,便會使屏幕不穩定,產生閃爍現象。
筆者經過對VC++應用程 序框架結構和Windows消息映射系統的仔細研究,找到另一種改變視圖背景的方法,其執行效果比上述兩種方法都好。其實在程序調用OnDraw函數之 前,會觸發一個Windows消息:WM_ERASEBKGND,以擦除視圖刷新區域。在缺省狀況下,Windows系統使用視圖窗口註冊時窗口類中的成 員hbrBackground所描述的畫刷來擦除屏幕,這通常會將屏幕刷新成COLOR_WINDOW所對應的顏色。所以,在OnDraw函數中設置背景 顏色的執行過程是這樣的:先將屏幕刷新成COLOR_WINDOW所對應的顏色,接着又在OnDraw函數中填充其餘顏色,這正是產生屏幕閃爍的根本原 因。 less
解決問題
經過上述分析,咱們應將視圖背景顏色填充移到Windows消息:WM_ERASEBKGND所對應的消息映射函數中,而不是在 OnDraw函數中。咱們能夠經過下列步驟實現這一過程:在文檔類中增長一成員變量m_viewBkColor保存當前背景顏色,同時增長兩個成員函數 GetViewBkColor和SetViewBkColor對其進行讀寫操做。這樣作的好處是能夠對m_viewBkColor成員進行序列化,將其和 文檔聯繫在一塊兒,打開某一文檔時,其背景將和上一次程序操做該文檔時的背景保持一致。在視圖類中爲視圖的Windows消息WM_ERASEBKGND增 加消息映射函數OnEraseBkgnd,代碼以下:
BOOL CTestView::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
CBrush brush;
brush.CreateSolidBrush(GetDocument()->GetViewBkColor());
pDC->GetClipBox(rect);
pDC->FillRect(rect,&brush);
return true;
}
在該函數中不須要對客戶區域矩形進行設備座標到邏輯座標的轉換,而且Windows在調用該函數時會自動進行裁剪區域的計算,使得須要刷新的屏幕面積達到最小。這樣咱們能夠在程序中經過設計下列菜單函數輕鬆地改變視圖背景的顏色,並且運行效果至關使人滿意。
void CTestView::OnChangeViewBkcolor()
{
CColorDialog cdlg;
if(cdlg.DoModal()==IDOK)
{
GetDocument()->SetViewBkColor
(cdlg.GetColor());
InvalidateRect(NULL);
}
} 函數