情况是这样的:
我首先拦截了窗口的WM_PAINT消息,然后在该消息内对窗口的背景进行了绘制,我的绘制是这样的:
DrawBK(...);//背景绘制函数
InvalidateRect(NULL,true);
上面代码能够实现窗口背景的绘制,但是当拖大或是缩小窗口时,窗口上的其它子控件就闪烁的特别厉害。
这样肯定不行,我便把InvalidateRect(NULL,true);函数去掉,直接用DrawBk函数,可是发现当窗口
重绘时,窗口上的控件都被背景覆盖了,显示不出来!
于是,我便给窗口增加了WS_CLIPCHILDREN,再使用
DrawBK(...);//背景绘制函数
InvalidateRect(NULL,true);
进行绘制,这时发现,在窗口变量或缩小时大部分子控件没有闪烁了,但是也有一些控件发生了闪烁!我想问一下朋友们,对于我们自绘窗口时,怎么样消除窗口上其它子控件的闪烁问题呢?都有那些好的方法!大家的在这方面又如何处理的呢?

解决方案 »

  1.   

    DrawBK(...);//背景绘制函数 
    InvalidateRect(NULL,true); 这个会死循环的。InvalidateRect后,系统会自己再发Paint消息。
      

  2.   


    不会的!这两个语句不是放在WM_PINT消息对应该的消息映射函数中!是在我自己设计的绘制事件中!
      

  3.   

    我是自己写的类,所以我在Paint中直接读取状态然后DrawItem,基本上没有闪烁
      

  4.   

    建议自己写这些子控件控制它的OnPaint函数
      

  5.   

    我们看到MFC它默认的窗口背景下,窗口放大或缩小时窗口上的子控件都没有什么闪烁!得主要归功于它的WM_ERASEBKGND消息,其消息函数为:
    CWnd::OnEraseBkgnd 
    如果我们能找到这个函数的实现机制那就好了!不知道大家没有没有研究过该函数!谁有这个函数的原代码没有?
      

  6.   

    //全局背景
    HBITMAP   hbmBk = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BK));

    case WM_PAINT:
    {
    //绘制背景

    BITMAP    bminfo;
    GetObject(hbmBk, sizeof(bminfo), &bminfo);
    PAINTSTRUCT    ps;
    HDC dc = BeginPaint(hwnd, &ps);
    HDC memdc = CreateCompatibleDC(dc);
    SelectObject(memdc, hbmBk);
    BitBlt(dc,0,0,bminfo.bmWidth,bminfo.bmHeight,memdc,0,0,SRCCOPY);
    DeleteDC(memdc);
    EndPaint(hwnd, &ps);
    return TRUE;
    }
    //没有发现将子控件覆盖的情况,没有使用双缓冲,因为图比较小闪烁不明显子控件则是在DrawItem里面完成 case WM_DRAWITEM:
    {
    LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam; BOOL bIsPressed  = (lpDIS->itemState & ODS_SELECTED); HWND btnHwnd = GetDlgItem(hwnd,IDC_BUTTON1); if (bIsPressed)
    {
    ::kbtn32.SyncDown(btnHwnd,hwnd);
    }
    else
    {
    ::kbtn32.SyncNomal(btnHwnd,hwnd);
    }
    }
    return TRUE;没有使用RedrawWindow 这类重绘
      

  7.   


    非常感谢你的建议,你的这个方法我到没有试过!你把窗口上的子控件绘制从WM_DRAWITEM内拦截,这个我到没这样试过,而我是直接用InvalidateRect来使子窗获得重绘!你的方法值得借鉴。还有你说 你的case WM_PAINT内的绘制没有覆盖子控件那是因为你取得的DC是CPaintDC,而我取得的是窗口DC:GetWindowsDC,所以你的绘制才没有被覆盖,如果你也是窗口DC我想应该也会覆盖掉子控件的!
      

  8.   

    SetRedraw()  指定每次修改控件属性后是否自动重绘控件  
      语法objectname.SetRedraw(boolean)  
      参数objectname   要修改重绘属性的控件或对象名objectname   可以是子数据窗口  
      但不能是菜单  
      boolean   boolean   型值指定修改控件或对象的属性后PowerBuilder   是否自动重  
      绘控件或对象有效取值为  
            TRUE   每次修改属性后自动重绘该对象或控件  
            FALSE   修改属性后不自动重绘该对象或控件   
    将控件setredraw(false)就不闪了
      

  9.   

    没么这麻烦吧。。
    父窗口创建时要加上WS_CLIPCHILDREN
      

  10.   


    MFC窗口默认情况下,不管有没有这个属性,窗口在重绘时,其子控件都不会有闪烁!其背景的绘制是采用了CWnd::OnEraseBkgnd 这个函数!我想最好的消除背景重绘时如何消除子控件的闪烁还是要知道CWnd::OnEraseBkgnd 函数的实现机制是怎么样的!
      

  11.   

    我一般的做法是,不去刷新背景,让OnEraseBkgnd函数直接返回TRUE,这样窗口本身就不会绘制背景。置于上哪里去画背景呢,我们可以在OnPaint函数里面去做这个事情,先画一下底色,这个底色就是背景了,然后再画其它内容。在这里面可以用双缓冲实现。 
    一般的做法是这么做的: 
    BOOL OnEraseBkgnd(CDC * pDC) 

        CRect rect; 
        GetClientRect(&rect); 
        pDC->FillRect(m_bkBrush, &rect); 
    .... 

    现在这直接这么做: 
    BOOL OnEraseBkgnd(CDC * pDC) 

        return TRUE; 
    } void OnPaint() 

      CPaintDC dc(this); 
        CRect rect; 
        GetClientRect(&rect); 
        dc.FillRect(m_bkBrush, &rect); 
    ...... 
      

  12.   


    这个属性一开始我就说有加过!但并不是加了这个属性所有子控件就都不闪烁了!如:Slider,Tab Control就照闪不误!
      

  13.   

    还没搞定吗?用控件.setredraw(false)可以啊,我以前用过,一句代码就行了
      

  14.   

    你的方法我觉得还是有一定的局限性,比方说:如果我是在本窗口内部做消息拦截和绘制处理时,我到可以方便的获取窗口上每个子控件的对像,然后用 控件对象.setredraw(false)语句一一将各控件进行该设置!如果我是在其它地方拦截了某一窗口的WM_PAINT消息,然后进行了该窗口背景绘制,这个时刻,我们只能通过参数获取窗口句柄,但是我们又如何获取当前绘制窗口上的各子控件对象呢!这时获取子控件就有一定的困难了!
      

  15.   

    你用spy抓一下父窗口看是否真的有WS_CLIPCHILDREN
      

  16.   

    建议不要用tabcontrol这个控件,他的ITEM上面放图片,要控制闪烁,好难好难的,想用双缓冲,都无从下手