模态对话框中有自绘的CListBox、CButton控件,对话框窗体也是自绘的,控件在不移动的情况下不闪烁,在移动的时候,不停闪烁,行了很久都没有解决的办法,请各位给点意见,谢谢了LRESULT CKwMusicDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
LRESULT lrst=CDialog::DefWindowProc(message, wParam, lParam);

if (!::IsWindow(m_hWnd))
return lrst;

if (message==WM_MOVE||message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE ||message == WM_NOTIFY)
{
                  //自绘窗体
CDC* pWinDC = GetWindowDC();
if (pWinDC)
DrawTitleBar(pWinDC);
ReleaseDC(pWinDC);
}
    
if (message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE)
{
                  //处理控件的消息
CRect rect;
::GetClientRect(m_wndSplitter1.m_hWnd,&rect);
m_wndSplitter1.InvalidateRect(rect); 
::GetClientRect(m_PlayList.m_hWnd,&rect);
m_PlayList.InvalidateRect(rect);
::GetClientRect(m_Bvolume.m_hWnd,&rect);
m_Bvolume.InvalidateRect(rect);
::GetClientRect(m_ProcessBar.m_hWnd,&rect);
m_ProcessBar.InvalidateRect(rect);
::GetClientRect(m_Logon.m_hWnd,&rect);
m_Logon.InvalidateRect(rect);
::GetClientRect(m_GetScore.m_hWnd,&rect);
m_GetScore.InvalidateRect(rect);
::GetClientRect(m_LogonAndScore.m_hWnd,&rect);
m_LogonAndScore.InvalidateRect(rect);
::GetClientRect(m_SLogon.m_hWnd,&rect);
m_SLogon.InvalidateRect(rect);
::GetClientRect(m_Singn.m_hWnd,&rect);
m_Singn.InvalidateRect(rect);
}
//分隔条消息处理
if (message == WM_NOTIFY)
{
if (wParam == IDC_SPLITER)
{
SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;
DoResize(pHdr->delta);
}
} return lrst;
}

解决方案 »

  1.   

    画图都是双缓冲+BOOL CKwMusicDlg::OnEraseBkgnd(CDC* pDC) 
    {
    return TRUE;
    }
    贴图不闪啊,只是控件在移动窗体时不停的闪烁
      

  2.   


    if (message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE)
        {
                      //处理控件的消息
            CRect rect;
            ::GetClientRect(m_wndSplitter1.m_hWnd,&rect);
            m_wndSplitter1.InvalidateRect(rect); 
            ::GetClientRect(m_PlayList.m_hWnd,&rect);
            m_PlayList.InvalidateRect(rect);
            ::GetClientRect(m_Bvolume.m_hWnd,&rect);
            m_Bvolume.InvalidateRect(rect);
            ::GetClientRect(m_ProcessBar.m_hWnd,&rect);
            m_ProcessBar.InvalidateRect(rect);
            ::GetClientRect(m_Logon.m_hWnd,&rect);
            m_Logon.InvalidateRect(rect);
            ::GetClientRect(m_GetScore.m_hWnd,&rect);
            m_GetScore.InvalidateRect(rect);
            ::GetClientRect(m_LogonAndScore.m_hWnd,&rect);
            m_LogonAndScore.InvalidateRect(rect);
            ::GetClientRect(m_SLogon.m_hWnd,&rect);
            m_SLogon.InvalidateRect(rect);
            ::GetClientRect(m_Singn.m_hWnd,&rect);
            m_Singn.InvalidateRect(rect);
        }
    感觉问题关键在上一部分,但是也不知道怎么解决?给点思路...
      

  3.   

    if (message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE)
    {
    }
    把这个if块整个删掉。绘制非客户区时不要动客户区。
      

  4.   

    if (message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE)
        {
                      //处理控件的消息
            CRect rect;
            ::GetClientRect(m_wndSplitter1.m_hWnd,&rect);
            m_wndSplitter1.InvalidateRect(rect); 
            ::GetClientRect(m_PlayList.m_hWnd,&rect);
            m_PlayList.InvalidateRect(rect);
            ::GetClientRect(m_Bvolume.m_hWnd,&rect);
            m_Bvolume.InvalidateRect(rect);
            ::GetClientRect(m_ProcessBar.m_hWnd,&rect);
            m_ProcessBar.InvalidateRect(rect);
            ::GetClientRect(m_Logon.m_hWnd,&rect);
            m_Logon.InvalidateRect(rect);
            ::GetClientRect(m_GetScore.m_hWnd,&rect);
            m_GetScore.InvalidateRect(rect);
            ::GetClientRect(m_LogonAndScore.m_hWnd,&rect);
            m_LogonAndScore.InvalidateRect(rect);
            ::GetClientRect(m_SLogon.m_hWnd,&rect);
            m_SLogon.InvalidateRect(rect);
            ::GetClientRect(m_Singn.m_hWnd,&rect);
            m_Singn.InvalidateRect(rect);
        }
    楼主自己也知道问题在这。 那我就给你分析下吧当对话框移动的时候会重绘窗体,也就是message==WM_PAINT,这个时候你在以上的代码中,都把控件给刷新了一遍。 试想,对话框移动,会触发N个WM_PAINT消息,你的控件不闪烁才怪了。  就算是用了双缓冲也会出现闪烁了。楼主刷新控件的代码明显不应该放到以上的代码中。
      

  5.   

    同意5、6楼。这样下去WM_PAINT消息会永远执行下去,每次处理WM_PAINT消息时如果调用了InvalidateRect,就会有新的WM_PAINT消息进入消息队列,如此周而复始,耗费大量CPU资源。
      

  6.   

    那要怎么解决呢?关键是不在这里触发WM_PAINT消息,移动窗体的时候,控件显示不出来啊,好象被窗体背景覆盖了啊,各位给点意见
      

  7.   

    OnPaint()不会覆盖控件的啊。你把你的OnPaint()函数贴出来看看。再有你这样试一下:响应WM_ERASEBKGND消息,  在OnEraseBkgnd()函数里直接返回TRUE,把 return CDialog::OnEraseBkgnd(pDC);屏蔽掉
      

  8.   


    void CKwMusicDlg::OnPaint() 
    {
    if (IsIconic())
    {
    CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle
    int cxIcon = GetSystemMetrics(SM_CXICON);
    int cyIcon = GetSystemMetrics(SM_CYICON);
    CRect rect;
    GetClientRect(&rect);
    int x = (rect.Width() - cxIcon + 1) / 2;
    int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon
    dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
    CDialog::OnPaint();
    }
    }
    //双缓冲时已经用上了
    BOOL CKwMusicDlg::OnEraseBkgnd(CDC* pDC) 
    {
        return TRUE;
    }移动窗体时系统处理WM_NCPAINT||message==WM_NCACTIVATE ||message == WM_NOTIFY重画窗体
    覆盖控件造成的,如果不重绘控件的话,控件就显示不了啊,可是重绘又产生控件的闪烁,该怎么处理呢?
    谢谢楼上的朋友们!!!
      

  9.   


    if (message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE)
        {
                      //处理控件的消息
            CRect rect;
            ::GetClientRect(m_wndSplitter1.m_hWnd,&rect);
            m_wndSplitter1.InvalidateRect(rect); 
            ::GetClientRect(m_PlayList.m_hWnd,&rect);
            m_PlayList.InvalidateRect(rect);
            ::GetClientRect(m_Bvolume.m_hWnd,&rect);
            m_Bvolume.InvalidateRect(rect);
            ::GetClientRect(m_ProcessBar.m_hWnd,&rect);
            m_ProcessBar.InvalidateRect(rect);
            ::GetClientRect(m_Logon.m_hWnd,&rect);
            m_Logon.InvalidateRect(rect);
            ::GetClientRect(m_GetScore.m_hWnd,&rect);
            m_GetScore.InvalidateRect(rect);
            ::GetClientRect(m_LogonAndScore.m_hWnd,&rect);
            m_LogonAndScore.InvalidateRect(rect);
            ::GetClientRect(m_SLogon.m_hWnd,&rect);
            m_SLogon.InvalidateRect(rect);
            ::GetClientRect(m_Singn.m_hWnd,&rect);
            m_Singn.InvalidateRect(rect);
        }这里的控件都是子类化的,他们的刷新应该不会造成主窗体的刷新啊
      

  10.   

    看你的代码:
    if (message==WM_MOVE||message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE ||message == WM_NOTIFY)
        {
                      //自绘窗体
            CDC* pWinDC = GetWindowDC();
            if (pWinDC)
                DrawTitleBar(pWinDC);
            ReleaseDC(pWinDC);
        }
    自绘只是画了个Titlebar而已,不至于把客户区都覆盖了吧,用不着把控件都刷一遍.窗口类型有WS_CLIPCHILDREN吗?加上试试。如果不行的话,教你个办法,把控件区域排除掉再画:
    if (message==WM_MOVE||message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE ||message == WM_NOTIFY)
        {
                      //自绘窗体
            CDC* pWinDC = GetWindowDC();
            if (pWinDC)
            {
             CRect rect;
            ::GetClientRect(m_wndSplitter1.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_PlayList.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_Bvolume.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_ProcessBar.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_Logon.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_GetScore.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_LogonAndScore.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_SLogon.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect); 
            ::GetClientRect(m_Singn.m_hWnd,&rect);
            pWinDC.ExcludeClipRect(rect);         DrawTitleBar(pWinDC);
            }
            ReleaseDC(pWinDC);
        }下面的那一堆刷控件的代码就不要了。
      

  11.   

    应该是pWinDC->ExcludeClipRect(rect); 
      

  12.   

    同意5、6楼。这样下去WM_PAINT消息会永远执行下去,每次处理WM_PAINT消息时如果调用了InvalidateRect,就会有新的WM_PAINT消息进入消息队列,如此周而复始,耗费大量CPU资源。
      

  13.   

    5.6 楼点出问题所在
    14楼的代码值得一试。
    InvalidateRect 是造成闪烁的主凶,不管是刷新控件还是对话框。而且,你是利用点击鼠标拖动的时候去判断是否进行重绘的,
    只要鼠标有消息,重绘就会不断进行下去。
      

  14.   

    另外提一下,
    一般要重载窗口处理消息,最好在WindowProc内实现,尽量别在DefWindowProc中处理。
      

  15.   

    让窗口和控件不闪:
    1. 画窗口或控件时, 在WM_PAINT中尽量用双缓存
    2. 把父窗口的窗口Style设置成WS_CLIPCHILDREN. [ ModifyStyle( 0, WS_CLIPCHILDREN ); ]
    3. 楚用WM_ERASEBKGND消息.注意以上3点基本不会有控件闪动的问题了~~
      

  16.   

    把InvalidateRect(rect)改成ShowWindow(SW_SHOW)试试
      

  17.   

    给你一个最正确的方法:
    1. 把所有父窗口的属性加上WS_CLIPCHILDREN和WS_CLIPSIBLINGS属性
    2.所有的子窗口的WM_ERASEBKGND消息直接返回TRUE.
    3.子窗口所有内容,都在WM_PAINT消息中,使用双缓存绘制.
      

  18.   

    28楼的是正确方法.... 一般的闪烁 足够解决了
    闪烁只是背景在画完控件后才刷上 导致闪烁... 
    不过还有更高级闪烁 不是28楼的方法能搞定的... 
    还有很多要注意的 移动和改变大小 用defwindow什么什么的 忘了
    我最近遇到 各种防闪烁技术都没用的闪烁.... 虽然轻微的 但是很影响效果
    都快被搞疯了...
    哎 如果你的不是透明png图片自绘的按钮 那么这个方法够你用的了