+ -
当前位置:首页 → 问答吧 → 客户区重绘的问题

客户区重绘的问题

时间:2011-12-01

来源:互联网

我用GetWindowDC()获取了对话框的DC,并在OnPaint中用此DC重新绘制了界面。
我写了其他的类来做绘制操作,在OnPaint中将DC传进去了
后来我发现绘制有些闪烁,因此想在OnPaint中使用双缓冲,我创建了兼容DC以及兼容位图,将兼容DC传给了绘制函数
多个区域的绘制完成后,我再将兼容DC一次性绘制到之前获得的窗口DC上。
这样的操作有问题么?我绘制的结果变成了灰色图像····很是不解

另外,当点击其他窗口,如IE,将程序覆盖,再点击最小化后,发现程序的边框等非客户区重绘了,而OnPaint()里的绘制函数却没起到作用,我也在OnSize以及WM_NCPAINT的响应里添加了Invalidate,但是都没有起到作用。

-----------------------------------------------------------
以上,两个问题,请大家帮忙!谢谢

作者: jiratao   发布时间: 2011-12-01

1.不明白,2你应该在对话框自己的消息响应中去绘制。

作者: xuddk727   发布时间: 2011-12-01

贴出你的代码

作者: onlycs   发布时间: 2011-12-01

引用 1 楼 xuddk727 的回复:
1.不明白,2你应该在对话框自己的消息响应中去绘制。

第二个我就是在对话框的消息响应里做的
C/C++ code

LRESULT CTestFormDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    // TODO: 在此添加专用代码和/或调用基类
    LRESULT lrst = CDialog::DefWindowProc(message,wParam,lParam);                        //对话框类窗口过程函数    

    if(!IsWindow(m_hWnd))                                                    
        return lrst; 
    
    switch(message)
    {
    case WM_NCPAINT:        
    case WM_NCACTIVATE:
                Invalidate();
         //.......
        }
        //......
}

作者: jiratao   发布时间: 2011-12-01

OnPaint的代码如下
C/C++ code

void CTestFormDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        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;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        ModifyStyle(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, 0);
        // 绘图
        CDC *pWndDC = GetWindowDC();

         CRect rcWnd;
         GetWindowRect(rcWnd);
 
         CDC MemDC;
         MemDC.CreateCompatibleDC(pWndDC);
         CBitmap MemBmp, *pOldBitmap;
         MemBmp.CreateCompatibleBitmap(&MemDC, rcWnd.Width(), rcWnd.Height());
         pOldBitmap = MemDC.SelectObject(&MemBmp);        

        m_border_left.OnPaintBorder(&MemDC);
        m_border_right.OnPaintBorder(&MemDC);
        m_Menubar.OnPaintMenu(&MemDC);
        m_MainBody.OnPaintMainBody(&MemDC);
        m_space.OnPaintSpace(&MemDC);
        m_statusbar.OnPaintFrame(&MemDC);

        pWndDC->BitBlt(0, m_titlebar.GetFrameRect().Height(), rcWnd.Width(), rcWnd.Height(), &MemDC, 0, 0, SRCCOPY);
 
         MemDC.SelectObject(pOldBitmap);
         MemDC.DeleteDC();
         DeleteObject(MemBmp);

        //pWndDC->DeleteDC(); // 这句不注释掉程序会报错崩溃,不解

        CDialog::OnPaint();
    }
}

作者: jiratao   发布时间: 2011-12-01

注释最后面的CDialog::OnPaint();

作者: onlycs   发布时间: 2011-12-01

绘制客户区应该用ClientDC,绘制非客户区才用WindowDC

作者: buyong   发布时间: 2011-12-01

引用 6 楼 buyong 的回复:
绘制客户区应该用ClientDC,绘制非客户区才用WindowDC

我要一起绘制,边框也要覆盖的

作者: jiratao   发布时间: 2011-12-01

引用 5 楼 onlycs 的回复:
注释最后面的CDialog::OnPaint();

刚才试了一下,果然重绘可以了,这是什么原理呢?
但是还有个衍生问题··现在点击任务栏程序图标不能最小化了

作者: jiratao   发布时间: 2011-12-01

你的那个不注释掉 ,是不是每时每刻都在重绘。。。

作者: shen_wei   发布时间: 2011-12-01

引用 9 楼 shen_wei 的回复:
你的那个不注释掉 ,是不是每时每刻都在重绘。。。

刚好相反。。注释掉了,画面一直在刷

作者: jiratao   发布时间: 2011-12-01

CPaintDC的构造和析构过程用来使无效区域有效,不然你试下注释掉基类OnPaint(),但在else里定义一个CPaintDC好了,虽然不适用这个CPaintDC

作者: dream0411   发布时间: 2011-12-01

把CDialog::OnPaint()这个放到ModifyStyle(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, 0)这个函数的前面。。就可以解决灰色屏幕..。
DefWindowProc其实可以不使用这个函数都可以...因为当你刷屏的时候,程序会自动发送WM_PAINT消息,当你不对这个消息进行处理的时候,程序识别到这个消息不用进行处理,于是程序就会自动去调用OnPaint这个消息响应的函数。..自然就可以实现刷屏的时候,绘制的背景还会存在,不会消失....所以呢,可以不用重载DefWindowProc这个函数去过滤/处理WM_PAINT这个消息...

作者: allen_lanyuhai   发布时间: 2011-12-01

引用 12 楼 allen_lanyuhai 的回复:
把CDialog::OnPaint()这个放到ModifyStyle(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, 0)这个函数的前面。。就可以解决灰色屏幕..。
DefWindowProc其实可以不使用这个函数都可以...因为当你刷屏的时候,程序会自动发送WM_PAINT消息,当你不对这个消息进行处理的时候,程序识别到这个消息不用进行处理,于是程序……

改正前面的:
把CDialog::OnPaint()这个放到ModifyStyle(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, 0)这个函数的前面。。就可以解决灰色屏幕..。
DefWindowProc其实可以不使用这个函数都可以...因为当你刷屏的时候,程序就会接收到WM_PAINT消息,当你不对这个消息进行处理的时候,程序识别到这个消息不用进行处理,于是程序就会自动去调用OnPaint这个消息响应的函数。..自然就可以实现刷屏的时候,绘制的背景还会存在,不会消失....所以呢,可以不用重载DefWindowProc这个函数去过滤/处理WM_PAINT这个消息...

作者: allen_lanyuhai   发布时间: 2011-12-01

引用 13 楼 allen_lanyuhai 的回复:
引用 12 楼 allen_lanyuhai 的回复:
把CDialog::OnPaint()这个放到ModifyStyle(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, 0)这个函数的前面。。就可以解决灰色屏幕..。
DefWindowProc其实可以不使用这个函数都可以...因为当你刷屏的时候,程序会自动发送WM_PAINT消息,当你不对这个消……


DefWindowProc里面的Invalidate我去掉了,然后按照你说的,放到前面,客户区的确重绘了
但是边框有点问题了··
我在绘制时本来是覆盖了边框了的,当程序窗口被其他窗口覆盖,其他窗口移出对话框后,对话框内界面按照我的代码绘制了,但是边框又重绘成系统边框了···
难道我只能在无边框属性对话框上操作了么···

作者: jiratao   发布时间: 2011-12-01