使用控件,想对一个static控件做一些操作,使用了SetWindowLong将其的WNDPROC修改成自己调用的一个函数,在这个函数里面如果对WM_PAINT进行操作,那么这时在对于其父窗口的WM_CTLCOLORSTATIC所进行的颜色修改就没有作用了,如果不处理WM_PAINT就没有问题。另外一点也很奇怪,如果在创建这个static时其属性中如果增加了颜色特征,WM_CTLCOLORSTATIC也会失去作用。所以很想知道static控件的颜色是如何控制的,修改它的HBRBKGROUDBRUSH没有任何用处。盼高手解答,越详细越好测试程序如下:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
TCHAR szBuffer[200];
HINSTANCE hInstance;
static HWND hstatic;
static HBRUSH hBrushStatic, hBrushStatic2;
LONG style; switch(message)
{
case WM_CREATE:
hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
hstatic = CreateWindow( TEXT("STATIC"), TEXT("LIST is joke"), 
WS_CHILD|WS_VISIBLE|SS_CENTER|SS_GRAYRECT,//如果有了SS_GRAYRECT,WM_CTLCOLORSTATIC就无效了
100, 100, 200, 200, 
hwnd, (HMENU)1, hInstance, NULL); OldStatic = (WNDPROC) SetWindowLong (hstatic, GWL_WNDPROC, (LONG) StaticProc );
hBrushStatic2 = (HBRUSH)GetStockObject(DKGRAY_BRUSH); 
SetClassLong(hstatic, GCL_HBRBACKGROUND, hBrushStatic2);
hBrushStatic = (HBRUSH)GetStockObject(BLACK_BRUSH); return 0; case WM_CTLCOLORSTATIC:
SetTextColor((HDC)wParam, RGB(70, 0, 80));
SetBkColor((HDC)wParam, RGB(0, 90, 130));
return (LRESULT)hBrushStatic;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
     }
   return DefWindowProc (hwnd, message, wParam, lParam) ;
}LRESULT CALLBACK StaticProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch(message)
{
case WM_PAINT:  ,//如果处理了此消息,WM_CTLCOLORSTATIC也无效了
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 10, "This is a Test", 14);
EndPaint(hwnd, &ps);
break;
}
return CallWindowProc( OldStatic, hwnd, message, wParam, lParam );
}

解决方案 »

  1.   

    急,没有人顶,自己顶一下。SDK下面编程的,不知道控件的颜色是如何进行控制的,求解,小弟拜谢了
      

  2.   

    貌似不用这么复杂吧,只截获static的WM_PAINT消息,重写OnPain()函数不可以么?
      

  3.   

    我想情况是这样的,如果你指定了SS_GRAYRECT,那么static的WNDCLASS结构中的hbrBackground就有值了。看看msdn对这个字段的解释吧:
    When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function. 
    也就是说系统会帮你刷背景,轮不到你刷了。除非你把WNDCLASS结构中的hbrBackgroud置为空
      

  4.   

    具体的你可以看看PAINTSTRUCT结构中的fErase字段,就可以判断是不是需要刷背景了。看看MSDN对他的解释
    fErase 
    Specifies whether the background must be erased. This value is nonzero if the application should erase the background. The application is responsible for erasing the background if a window class is created without a background brush. For more information, see the description of the hbrBackground member of the WNDCLASS structure. 
      

  5.   

    感谢两位回复。答复Q342210738:SDK同MFC的编程方式会不一样,但关键还是要对其机制要清楚,就算用修改OnPaint仍然需要回答这些问题,程序主要是想去了解一下控件在处理颜色消息的机制答复zzw820626:指定了SS_GRAYRECT,hbrBackground仍然为空,已通过程序验证。fErase一直为0值,此点有一些奇怪,即使我使用了InvalidateRect(hstatic, NULL, TRUE),其值仍然为0。但如果说其不用刷子来刷背景,那又是用什么来更新背景的呢?另外如何让fErase为非零值?欢迎大家继续探讨
      

  6.   

    是:
    return CallWindowProc(OldStatic, hwnd, message, wParam, lParam );
    发出的:WM_CTLCOLORSTATIC,试试://
    LRESULT CALLBACK StaticProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    PAINTSTRUCT ps;
    HDC hdc;
    switch(message)
    {
    case WM_PAINT: //如果处理了此消息,WM_CTLCOLORSTATIC也无效了
    OutputDebugString("StaticProc\n");
    return CallWindowProc(OldStatic, hwnd, message, wParam, lParam );
    // hdc = BeginPaint(hwnd, &ps);
    // TextOut(hdc, 10, 10, "Test", 4);
    // EndPaint(hwnd, &ps);
    break;
    }
    return CallWindowProc( OldStatic, hwnd, message, wParam, lParam );
    }BeginPaint(hwnd, &ps);不发送WM_CTLCOLORSTATIC
      

  7.   

    经程序验证,调用了BeginPaint一样会产生WM_CTLCOLORSTATIC,同此没有关系,当然如果对于WM_PAINT消息利用其原有的处理函数肯定是不会有问题,就是我们自己调用BeginPaint就会出问题,看来需要看过BeginPaint源码实现的人才知道其中源由了。VC里面不明白的地方太多,微软又不开放源码,只能靠我们猜,MSDN也是讲得不透。问题也是可以搞定的,就是使用控件时老老实实地按步骤搞,不要自己想创新。
      

  8.   

    再看看:
    case WM_PAINT: //如果处理了此消息,WM_CTLCOLORSTATIC也无效了
    // OutputDebugString("StaticProc3\n");
    // return CallWindowProc(OldStatic, hwnd, message, wParam, lParam );
    hparentwnd=GetParent(hwnd);
    hdc = BeginPaint(hwnd, &ps);
    SendMessage(hparentwnd,WM_CTLCOLORSTATIC,(WPARAM)hdc,(LPARAM)hwnd); 
    TextOut(hdc, 10, 10, "Test", 4);
    EndPaint(hwnd, &ps);
    break;
      

  9.   

    在:
        case WM_CTLCOLORSTATIC:
      OutputDebugString("WM_CTLCOLORSTATIC3\n");
    可以发现,只是BeginPaint(hwnd, &ps)时,不输出以上信息,
      

  10.   

    我知道了为什么“经程序验证,调用了BeginPaint一样会产生WM_CTLCOLORSTATIC”。你用的是break,应该用return0;
    case WM_PAINT: ,//如果处理了此消息,WM_CTLCOLORSTATIC也无效了
    hdc = BeginPaint(hwnd, &ps);
    TextOut(hdc, 10, 10, "This is a Test", 14);
    EndPaint(hwnd, &ps);
    break;
    break后是:
       return CallWindowProc( OldStatic, hwnd, message, wParam, lParam );
    就是它又调用你的WM_CTLCOLORSTATIC。可惜已经晚了。
      

  11.   

    BeginPaint同是否会产生WM_CTLCOLORSTATIC并没有必然联系,可以在程序中这样尝试,WM_PAINT中使用ValidateRect,然后用break,仍然会产生WM_CTLCOLORSTATIC,如果用return,就不会产生WM_CTLCOLORSTATIC,根据MSDN上讲,在控件更新后,是会由控件由父窗口发一个WM_CTLCOLORSTATIC知会消息,然后由它再进行控件刷新,而此消息就是由windows的缺省窗口函数处理的,如果不调用此函数肯定是不会发送的,同BeginPaint是没有关系的。但奇怪的就是一旦使用了BeginPaint后,虽然还有此消息,但针对此消息的返回的brush就失去作用了。这是关心点,必须要知道其内幕才可以知道。不管怎样,很感谢schlafenhamster,贴子再挂一下,如没有想要的答案,将分全给你,技术上面可以多探讨。
      

  12.   

    "一旦使用了BeginPaint后,虽然还有此消息",注意并没有,你可以见10楼
    “用break,仍然会产生WM_CTLCOLORSTATIC(是因为CallWindowProc),如果用return,就不会产生WM_CTLCOLORSTATIC(也是因为CallWindowProc),”,很明显是CallWindowProc产生的WM_CTLCOLORSTATIC。你看看9楼的程序,试试。
      

  13.   

    程序我调试过了,使用了BeginPaint后,只要后面是break,就会产生此消息,如果你在WM_PAINT里面采用sendmessage,那么会在debug窗口里面看到两次显示,如果是用return,则只有一次了。谁产生WM_CTLCOLORSTATIC已比较清楚,目前不清楚的关键在回应WM_CTLCOLORSTATIC的消息时本来可以用刷子刷背景色的,目前却不行,还是其中的机制问题另外sendmessage的位置也很有意思,在textout之前,同其后,得到的结果也不一样。
      

  14.   

    我的:LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
    {...
        case WM_CTLCOLORSTATIC:
            i=GetWindowLong((HWND)lParam,GWL_ID);
            switch(i)
            {
            case 3:
                SetTextColor((HDC)wParam,crText[i%3]);// text 颜色变化
                SetBkColor((HDC)wParam,RGB(255,255,255));
    //
    OutputDebugString("WM_CTLCOLORSTATIC3\n");
                return (LRESULT)hStaticBrush;//这是Brush
                break;
    ...
    }
    //位置一定要对。
    hparentwnd=GetParent(hwnd);
    hdc = BeginPaint(hwnd, &ps);
    //!!!这句就是用来改变hdc的,放在TextOut还有什么用?
    SendMessage(hparentwnd,WM_CTLCOLORSTATIC,(WPARAM)hdc,(LPARAM)hwnd); 
    TextOut(hdc, 10, 10, "Test", 4);
      

  15.   

    至于背景要自己重绘了:
    case WM_PAINT: //如果处理了此消息,WM_CTLCOLORSTATIC也无效了
    // OutputDebugString("StaticProc3\n");
    // return CallWindowProc(OldStatic, hwnd, message, wParam, lParam );
    hparentwnd=GetParent(hwnd);
    hdc = BeginPaint(hwnd, &ps);
    //!!!
    brsh=(HBRUSH) SendMessage(hparentwnd,WM_CTLCOLORSTATIC,(WPARAM)hdc,(LPARAM)hwnd);
    ::FillRect(hdc,&ps.rcPaint,brsh);
    //!!!
    TextOut(hdc, 10, 10, "Test", 4);
    EndPaint(hwnd, &ps);
    return 0;
      

  16.   

    我们利用了SendMessage返回的刷子句柄。
    这下应该理解更深了吧。
      

  17.   

    感谢schlafenhamster,先结贴了。用此方法的确是能解决掉问题,但对于BeginPaint在窗口和控件的使用上面为什么存在差别,还需要再了解。上面的信息受益较多,给分了