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函數中填充其他顏色,這正是產生屏幕閃爍的根本原 因。

解決問題

通過上述分析,我們應將視圖背景顏色填充移到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);

}

}

自己嘗試過重寫onpaint()函數的方法,可以實現效果,我是用了一個pictrue control控件,顯示一張圖片,可以用GetDlgItem(IDC_VIDEO_WINDOW)->GetWindowRect(&rect) 或者 m_VideoWindow(這個是控件的變量).GetWindowRect(&rect) ,這樣就實現了對某個特定控件的控制。
 

 

自己代碼: CRect    rect;  

 GetDlgItem(IDC_VIDEO_WINDOW)->GetWindowRect(&rect);
 ScreenToClient(rect); //把位置設爲用戶的相對位置

 CDC    *pDC=GetDC();  

 CDC    memdc;  

 memdc.CreateCompatibleDC(pDC);  

 CBitmap    bitmap;  

 //從資源中載入位圖  

 bitmap.LoadBitmap(IDB_BITMAP_BKGROUND);  

 memdc.SelectObject(bitmap);  

 pDC->BitBlt(10,11,rect.Width(),rect.Height(),&memdc,0,0,SRCCOPY);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章