SDK问题?消息WM_ERASEBKGND的处理,能解释一下背景的处理吗?问题在下面,谢谢!

leemuxiang 2001-07-20 10:19:59
// 程序使用MFC头文件,须MFC支持!
#include "afxwin.h"
#include "resource.h"// 资源
//#include "sysmets.h"
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iShowCmd)
{
static TCHAR szAppName[]=TEXT("Sys");
HWND hWnd;
MSG msg;
WNDCLASS wc;
wc.style =CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc =WndProc;
wc.cbClsExtra =0;
wc.cbWndExtra =0;
wc.hInstance =hInstance;
wc.hIcon =LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor =LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
// 《==如果参数定义为NULL,将导致背景不会被擦除!!!
wc.lpszMenuName ="menu";
wc.lpszClassName =szAppName;

if(!RegisterClass(&wc))
{
MessageBox(NULL,
TEXT("This program requires Windows NT!"),szAppName,MB_ICONERROR);
return 0;
}

hWnd=CreateWindow(szAppName,
TEXT("Get System Metrics No.1"),
WS_OVERLAPPEDWINDOW,
0x80000000,
0x80000000,
0x80000000,
0x80000000,
NULL,
NULL,
hInstance,
NULL);

ShowWindow(hWnd,iShowCmd);
UpdateWindow(hWnd);

while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam ;
}



LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
static int cxChar,cxCaps,cyChar;
HDC hdc;
int i;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm;
RECT rect;
// ps解释
// 不定义参数wc.hbrBackground,将导致客户区背景不会被擦除,
// 参数的定义将导致ps.fErease=0;
// 如果要在窗口中自己定义一个背景的擦除,可以处理处理WM_ERASEBKEND消息
// ps.rcPaint:导致无效的客户区大小
// ps.fRestore:windows内部使用
// ps.IncUpdate:windows内部使用
// ps.rgbReserved:windows使用,缺省值为:6683512?

switch(message)
{
case WM_CREATE:
hdc=GetDC(hWnd);

GetTextMetrics(hdc,&tm);
cxChar=tm.tmAveCharWidth ;
cxCaps=(tm.tmPitchAndFamily &1?3:2)*cxChar/2;
cyChar=tm.tmHeight +tm.tmExternalLeading ;

ReleaseDC(hWnd,hdc);
return 0;
// WM_ERASEBKGND消息处理但没有指定刷子,将导致背景擦除无效!
// **************************************************************
// 问题一:如果我要把背景设置为一个渐变色,该如何做?或者设置为红色背景
// ***************************************************************
/* case WM_ERASEBKGND:
// 怎么做?
return 0;
*/
// ***************************************************************

case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
// 下面是ps结构的值显示
TextOut(hdc,0,0,szBuffer,wsprintf(szBuffer,TEXT("%5d"),hdc));
TextOut(hdc,0,10+cxChar*2,
szBuffer,wsprintf(szBuffer,TEXT("%5d"),ps.hdc ));
TextOut(hdc,0,20+cxChar*3,
szBuffer,wsprintf(szBuffer,TEXT("%5d"),ps.fErase ));
TextOut(hdc,0,30+cxChar*4,
szBuffer,wsprintf(szBuffer,TEXT("%5d %5d %5d %5d"),ps.rcPaint .left,
ps.rcPaint .right ,ps.rcPaint .top ,ps.rcPaint .bottom ));
TextOut(hdc,0,40+cxChar*5,szBuffer,wsprintf(szBuffer,TEXT("%5d"),ps.fRestore ));
TextOut(hdc,0,50+cxChar*6,szBuffer,wsprintf(szBuffer,TEXT("%5d"),ps.fIncUpdate ));
TextOut(hdc,0,60+cxChar*7,szBuffer,wsprintf(szBuffer,TEXT("%5d"),ps.rgbReserved ));


/* for(i=0;i<NUMLINES;i++)
{
TextOut(hdc,0,cyChar*(i+8),sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));

TextOut(hdc,cxCaps*22,cyChar*(i+8),sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));

SetTextAlign(hdc,TA_RIGHT|TA_TOP);

TextOut(hdc,22*cxCaps+40*cxChar,cyChar*(i+8),szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].iIndex)));

SetTextAlign(hdc,TA_LEFT|TA_TOP);

}*/

EndPaint(hWnd,&ps);
return 0;

case WM_COMMAND:

GetClientRect(hWnd,&rect);
rect.top =rect.top;
rect.left =rect.left;
rect.right =(rect.right-rect.left ) /2;
rect.bottom =(rect.bottom -rect.top )/2;
{
switch(LOWORD(wParam))
{
case ID_TEST:
InvalidateRect(hWnd,&rect,TRUE);
// 第四个参数为TRUE!!!
break;
case ID_QUIT:
DestroyWindow(hWnd);
break;
default:
return (DefWindowProc(hWnd,message,wParam,lParam));
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,message,wParam,lParam);
}


...全文
377 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
tiongkohlang 2001-07-27
  • 打赏
  • 举报
回复
第一个问题的现象可以理解。
第二个问题我不明白,可以用spy++或者别的东西看一看。
leemuxiang 2001-07-25
  • 打赏
  • 举报
回复
to all thanks.!
leemuxiang 2001-07-23
  • 打赏
  • 举报
回复
再问几个问题?
问题一:下面是WM_PAINT的处理程序
hdc=BeginPaint(hWnd,&ps);
hdc1=GetWindowDC(hWnd);
GetClientRect(hWnd,&rect);// ==>rect声明为:static RECT rect;
SetTextColor (hdc,RGB(255,0,0));
SetBkColor(hdc,RGB(128,128,128));
TextOut(hdc1,0,0,szBuffer,wsprintf(szBuffer,TEXT("hdc:%5d"),hdc));
TextOut(hdc1,cxChar*20,0,szBuffer,wsprintf(szBuffer,TEXT("hWnd:%5d"),hWnd));
// 在标题处显示hdc & hWnd.
ReleaseDC(hWnd,hdc1);
EndPaint(hWnd,&ps);
return 0;
在一个菜单的处理程序中调用:InvalidateRect(hWnd,&rect,TRUE);
可以观察到hdc在变化,应该变化吗?为什么?(我的疑问来自hWnd一直没变?)

问题二:在窗口改变大小后,窗体客户区,及背景均重绘,
WM_PAINT在WM_ERASEBKGND之前执行?
不好意思:能从一个HDC知道其属主窗口(能这么说吗?)的HWND吗?

to all 谢谢!
leemuxiang 2001-07-23
  • 打赏
  • 举报
回复
谢谢!
原来返回非零值,试试!
tiongkohlang 2001-07-21
  • 打赏
  • 举报
回复
“需要在处理程序中建立一个刷子吗?就象MFC中一样?”

不用不用,你干什么都行。你贴一张位图也行,你画一个渐变地背景也行,怎么都行。只要你返回一个非零值就可以。那个WNDCLASSEX的hbrBackground是DefWindowProc用来刷背景的。

以下是msdn的解释。

WM_ERASEBKGND
The WM_ERASEBKGND message is sent when the window background must be erased (for example, when a window is resized). The message is sent to prepare an invalidated portion of a window for painting.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_ERASEBKGND
WPARAM wParam, // handle to device context (HDC)
LPARAM lParam // not used
);
Parameters
wParam
Handle to the device context.
lParam
This parameter is not used.
Return Values
An application should return nonzero if it erases the background; otherwise, it should return zero.

Remarks
The DefWindowProc function erases the background by using the class background brush specified by the hbrBackground member of the WNDCLASS structure. If hbrBackground is NULL, the application should process the WM_ERASEBKGND message and erase the background.

An application should return nonzero in response to WM_ERASEBKGND if it processes the message and erases the background; this indicates that no further erasing is required. If the application returns zero, the window will remain marked for erasing. (Typically, this indicates that the fErase member of the PAINTSTRUCT structure will be TRUE.)
MSVCer 2001-07-21
  • 打赏
  • 举报
回复
WM_ERASEBKGND信息的参数wParam传递的是一个设备上下文句柄,有了句柄,怎么画就随你便了
leemuxiang 2001-07-21
  • 打赏
  • 举报
回复
to MSVCer:您好:我需要在处理程序中建立一个刷子吗?就象MFC中一样?
不明白怎么去做!例如我要画渐变色的背景?
另外,能给一个处理此消息的例程吗?很需要清楚到底在窗口改变后,
此消息的响应如何工作?
谢谢
标准Windows应用程序窗口一般为带有标题栏的浅灰色矩形外观,因而“异形”对话框/窗口也主要是颜色与外形上动手脚。改变背景颜色 改变对话框(窗口)的背景颜色是最简单的改变Windows应用程序外观的方法,根据Windows创建与管理机理,一般有两种方法。一种是处理WM_CTLCOLOR消息,首先创建所选背景颜色的刷子,然后调用SetBkColor()或SetDialogBkColor()以所创建的刷子来绘制窗口或对话框的背景。需要重画窗口或对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR,应用程序处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的刷子句柄。另外一种是响应Windows的WM_ERASEBKGND消息,Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用VC++的ClassWizard重载该消息的缺省处理程序来擦除背景(实际是用刷子画),并返回TRUE以防止Windows擦除窗口。2.改变窗口外形通过使用新的SDK函数SetWindowRgn(),可以将绘画和鼠标消息限定在窗口的一个指定的区域,因此实际上是使窗口成为指定的不规则形状(区域形状)。“区域”是Windows GDI中一种强有力的机制,区域是设备上的一块空间,可以是任意形状,复杂的区域可以由各个小区域组合而成。Windows内含的区域创建函数有CreateRectRgn()、CreatePolyRgn()、CreatePolygonRgn()、CreateRoundRectRgn()和CreateEllipticRgn(),再通过CombineRgn()来组合区域,即可得到复杂形状的区域,获得复杂形状的窗口外形。通过上面的方法虽然可以得到“异形”窗口,但感觉颜色单调,外形也不够“COOL”,能否获得更酷的“异形”对话框/窗口呢?回答是肯定的。下面就介绍利用位图和蒙板创建“异形”对话框/窗口的方法。3.利用位图创建异形对话框窗口利用位图创建异形对话框原理是根据象素的颜色来进行“扣像”处理,对所有非指定颜色象素区域进行区域组合。利用这一技术,实际上就是实现对话框/窗口的位图背景,并且对指定的颜色区域进行透明处理下面就以透明位图为背景的对话框为例来说明:首先用绘图软件如PhotoShop绘制编辑一幅拟做对话框背景用的图片,用BMP格式保存,假设存为Back.Bmp。需要说明的是,虽然Visual C++集成开发环境的资源编辑器只能编辑不超过16色的位图,但完全我们可以以真彩色方式存储,不必理会Visual C++的警告。下一步是用Visual C++的AppWizard创建一个基于对话框的应用程序假定命名为Trans。用资源编辑器引入背景图片Back.Bmp,如果是高彩色,不必理会出现的警告信息,点击OK确认即可。为了明确,修改默认的资源ID标识IDB_BITMAP1为IDB_BACKBMP。然后修改对话框的Style为Popup,Border为None,如图1 。图1向CTransDlg类添加区域处理功能模块void CTransDlg::SetupRegion(CDC *pDC /*对话框窗口DC*/, UINT BackBitmapID /*背景位图资源ID*/, UINT MaskBitmapID /*区域处理位图资源ID*/, COLORREF TransColor = 0x00000000 /*透明颜色值,默认为黑色*/)。到目前为止,我们暂时认为MaskBitmapID等同于BackBitmapID。其核心工作是根据MaskBitmapID指示位图的象素颜色进行区域组合。完整的代码如下:void CTransDlg::SetupRegion(CDC *pDC /*对话框窗口DC*/, UINT BackBitmapID /*背景位图资源ID*/,UINT MaskBitmapID /*区域处理位图资源ID*/,COLORREF TransColor /*透明颜色值*/){CDC memDC;CBitmap cBitmap;CBitmap* pOldMemBmp = NULL;COLORREF cl;CRect cRect;UINT x, y;CRgn wndRgn, rgnTemp;//取得窗口大小GetWindowRect(&cRect);//背景位图资源IDm_BackBitmapID = BackBitmapID//装载位图cBitmap.LoadBitmap(MaskBitmapID);memDC.CreateCompatibleDC(pDC);pOldMemBmp = memDC.SelectObject(&cBitmap);//首先创建默认的完整区域为完整的窗口区域wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height());//下面的两层循环为检查背景位图象素颜色,进行透明区域处理;//当象素颜色为指定的透明值时,即将该点从区域中剪裁掉。//其中用到的几个成员变量m_MaskLeftOff、m_MaskTopOff、//m_MaskRightOff、m_MaskBottomOff、m_FrameWidth//和m_CaptionHeight,其作用后面再作说明,此时可全部当作0来处理。for(x= m_FrameWidth+m_MaskLeftOff;x<=cRect.Width() - m_FrameWidth-m_MaskRightOff; x++){for(y = m_CaptionHeight+m_MaskTopOff; yBitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRC/DownloadFiles\a\2001-10-12\COPY);if (pOldMemBmp) memDC.SelectObject( pOldMemBmp );//删除系统却省的OnEraseBkgnd功能//return CDialog::OnEraseBkgnd(pDC);return TRUE;}接下来是在WM_PAINT的消息处理函数OnPaint()中添加代码。由于当背景位图比较大时,进行区域处理比较耗时,所以只在启动时进行一次处理。一种方法是OnInitDialog()处理,但这样会在从启动程序到窗口出现有相当的延迟,易引起程序尚未启动的误解。再一种方法就是在OnPaint()处理,但为了避免重复处理,可以加上一个判断标志。以下是OnPaint()的代码,正体为AppWizard生成,粗体为自己添加内容。void CTransDlg::OnPaint() {if (IsIconic()){……}else{if(m_nFirstRun){ //首次运行标志//修改鼠标光标为等待方式BeginWaitCursor();//设置背景区域SetupRegion(GetWindowDC(), 计算机教程用VC++实现异形窗口.来自www.itwen.comIT WEN计算机教程网 IDB_BACKBMP, IDB_BACKBMP, 0x00FFFFFF /*白色*/);//恢复鼠标光标为正常模式EndWaitCursor();m_nFirstRun = 0;}CDialog::OnPaint();}}剩下的工作就是根据背景位图的大小来设置对话框窗口的大小和位置,这可以在OnInitDialog()中通过调用MoveWindow()来实现。再添加一些变量的声名和初始化,即可编译运行。图2为运行结果示例:图24.进一步的讨论前面实现了单一模式的异形对话框,但有些情况下又需要不同的样式,如有标题栏、边框等,或者只作局部的处理,这就是前面两个成员变量m_FrameWidth和m_CaptionHeight作用,通过在OnInitDialog()判断窗口样式,使m_FrameWidth和m_CaptionHeight取不同的值。这部分的代码为:BOOL CTransBmpDlg::OnInitDialog(){……// TODO: Add extra initialization herem_nFirstRun = 1;//数据设置,窗口左上角坐标:m_Left=0,m_Top=0 //背景位图宽高:m_Width=535,m_Height=105SetSize(0, 0, 535, 105);//蒙板处理区域与窗口边框的距离m_MaskLeftOff=m_MaskTopOff=m_MaskRightOff=m_MaskBottomOff=0;//窗口边框与标题栏象素值m_FrameWidth = m_CaptionHeight = 0;//取得窗口样式LONG style = ::GetWindowLong(this->m_hWnd, GWL_STYLE);//如保留窗口风格样式,则根据不同的窗口边框类型    //选取不同的m_FrameWidth和m_CaptionHeight值, //也可以根据处理位置的需要进行付值if((style & WS_BORDER) == WS_BORDER)m_FrameWidth = ::GetSystemMetrics(SM_CXBORDER);if((style & WS_THICKFRAME) == WS_THICKFRAME)m_FrameWidth = ::GetSystemMetrics(SM_CXFIXEDFRAME);if((style & DS_MODALFRAME) == DS_MODALFRAME)m_FrameWidth = ::GetSystemMetrics(SM_CXFIXEDFRAME);if((style & WS_CAPTION) == WS_CAPTION){m_FrameWidth = ::GetSystemMetrics(SM_CXFIXEDFRAME);m_CaptionHeight = ::GetSystemMetrics(SM_CYSMCAPTION);}m_CaptionHeight += m_FrameWidth * 2;//重置窗口的位置和大小MoveWindow(m_Left, m_Top, m_Width + m_FrameWidth * 2, m_Height + m_CaptionHeight, TRUE);……return TRUE; // return TRUE unless you set the focus to a control}另外,为进一步增加灵活性,使窗口样式不仅仅受背景位图颜色的控制。通过指定SetupRegion()的MaskBitmapID 为一个我们称之为“蒙板”的双色位图(多色彩也可以,但一般没有必要),即可实现需要的操作。图4为在同一背景位图上,通过图3的蒙板位图实现的效果,并且增加了对话框窗体的边框和标题栏属性。图3图4利用这种蒙板技术,可以创建出任意形状的窗口,而与背景位图无关。需要注意的是,对于对话框中的控件如按钮等,如处在或部分处在通明区域中,则通明区域中部分一并被剪裁掉,是否剪裁和剪裁位置与大小,利用蒙板可以很方便地进行控制。需要特别指出的是,SetWindowRgn()所指定的区域是针对整个窗口的,而Bitblt()/ StretchBlt()的输出区域是针对于客户区,两者在定位上是不同的,编程中应加以注意并灵活应用,这也是前面之所以设置边框大小等变量的原因。5.结束语这种异形窗口的创建不仅适应于对话框,而且适应于所有的基于CWnd类的派生窗口。采用这一方法,你可以创建出任何只要你能够画出的窗体,实现只要可以画出,就可以做出的目标。本文代码在Visual C++ 5.0、6.0下调试通过,运行正常,操作系统为Windows98SE。

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧