CFrame窗体背景颜色
来源:互联网 发布:本地音乐播放器 知乎 编辑:程序博客网 时间:2024/05/22 11:51
如何修改frame窗口的背景颜色?
MDI窗口的客户区是由frame窗口拥有的另一个窗口覆盖的。为了改变frame窗口背景的颜色,只需要这个客户区的背景颜色就可以了。你必须自己处理WM_ERASEBKND消息。下面是工作步骤:
创建一个从CWnd类继承的类,就叫它CMDIClient吧;
在CMDIFrameWnd中加入CMDIClient变量;(具体情况看下面的代码)
class CMainFrame : public CMDIFrameWnd
{
...
protected:
CMDIClient m_wndMDIClient;
}
重载CMDIFrameWnd::OnCreateClient,下面是这段代码,请注意其中的SubclassWindow();
{
if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )
{
m_wndMDIClient.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
else
return FALSE;
}
最后要在CMDIClient中加入处理WM_ERASEBKGND的函数。
如何改变view的背景颜色?
若要改变CView,CFrameWnd或CWnd对象的背景颜色需要处理WM_ERASEBKGND消息,下面就是一个范例代码:
BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
//设置brush为希望的背景颜色
CBrush backBrush(#ff8080);
//保存旧的brush
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect);
//画需要的区域
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
若要改变CFromView继承类的背景颜色
下面是一个范例代码:
HBRUSH CMyFormView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINTnCtlColor)
{
switch (nCtlColor)
{
case CTLCOLOR_BTN:
case CTLCOLOR_STATIC:
{
pDC->SetBkMode(TRANSPARENT);
//不加任何处理或设置背景为透明
}
case CTLCOLOR_DLG:
{
CBrush* back_brush;
COLORREF color;
color = (COLORREF) GetSysColor(COLOR_BTNFACE);
back_brush = new CBrush(color);
return (HBRUSH) (back_brush->m_hObject);
}
}
return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}
如何修改frame窗口的背景颜色?
MDI窗口的客户区是由frame窗口拥有的另一个窗口覆盖的。为了改变frame窗口背景的颜色,只需要这个客户区的背景颜色就可以了。你必须自己处理WM_ERASEBKND消息。下面是工作步骤:
创建一个从CWnd类继承的类,就叫它CMDIClient吧;
在CMDIFrameWnd中加入CMDIClient变量;(具体情况看下面的代码)
class CMainFrame : public CMDIFrameWnd
{
...
protected:
CMDIClient m_wndMDIClient;
}
重载CMDIFrameWnd::OnCreateClient,下面是这段代码,请注意其中的SubclassWindow();
{
if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )
{
m_wndMDIClient.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
else
return FALSE;
}
最后要在CMDIClient中加入处理WM_ERASEBKGND的函数。
如何改变view的背景颜色?
若要改变CView,CFrameWnd或CWnd对象的背景颜色需要处理WM_ERASEBKGND消息,下面就是一个范例代码:
BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
//设置brush为希望的背景颜色
CBrush backBrush(#ff8080);
//保存旧的brush
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect);
//画需要的区域
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
若要改变CFromView继承类的背景颜色
下面是一个范例代码:
HBRUSH CMyFormView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINTnCtlColor)
{
switch (nCtlColor)
{
case CTLCOLOR_BTN:
case CTLCOLOR_STATIC:
{
pDC->SetBkMode(TRANSPARENT);
//不加任何处理或设置背景为透明
}
case CTLCOLOR_DLG:
{
CBrush* back_brush;
COLORREF color;
color = (COLORREF) GetSysColor(COLOR_BTNFACE);
back_brush = new CBrush(color);
return (HBRUSH) (back_brush->m_hObject);
}
}
return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}
BOOLCMainWindow::OnEraseBkgnd(CDC* pDC)
{
}
HBRUSHCMainWindow::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
}
先载入一张图片,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* UINTpDC, CWnd* pWnd, 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 BOOLOnInitDialog();返回值指定对话框是否对它的一个控件设置输入焦点。如果OnInitDialog返回非零值,Windows将输入焦点设在对话框的第一个控件上,只有在对话框明确将输入焦点设在某控件上,应用返回0。
CBitmap:类CBitmap封装了Windows图形设备接口(GDI)中的位图,并且提供操纵位图的成员函数。
LoadBitmap ( ):CBitmap类的一个成员函数,从应用的可执行文件中加载一个命名的位图资源来初始化位图对象。
用法:
BOOL LoadBitmap( LPCTSTR lpszRecourceName );BOOL LoadBitmap( UINTnIDResource);返回值调用成功时返回非零值,否则为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的WindowsGDI对象,释放与此对象相关的系统存储空间。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以及设备描述表devicecontext。实际上,句柄是一个标识符,用来表示对象或者项目,是一个32位的正整数。应用程序几乎总是通过调用一个Windows函数来获得一个句柄,之后其他的Windows函数就可以使用这个句柄,以引用相应的对象。
WM_CTLCOLOR消息:WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notificationmessage)。利用向导映射该消息产生函数:
HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINTnCtlColor);
参数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);
- }
- }
一、在一个MFC应用程序中,要改变控件的背景色可通过重载OnCtlColor()函数来实现。方法是在该函数中设置所需颜色后再返回一个画刷句柄便可重绘控件背景色。OnCtlColor()函数对于控件背景色的处理是通过捕捉相应的控件消息来实现的。常用的此类消息有: