袁大哥,我现在写了一个从CView派生下来的类当作文本编辑器,现在我使用了内存DC,兼容Bitmap,局部刷新所有已知的方法来重绘文本,(我用的是BitBlt把内存DC拷贝到设备DC)但是效率都无法忍受,我想要实现象Windows记事本那样的刷新效率,最好是UltraEdit那样的效率,我的程序在P3 733的机器上面刷新都是有闪烁的,请问还有什么办法可以解决啊,在下感激不尽啊!

解决方案 »

  1.   

    回复人: DelphiBoy2003(梦想的妻子是赵灵儿) ( ) 信誉:100  2005-02-16 11:32:00  得分: 0  
     
     
       人气咋就这么低啊
      
     
    ===============帮忙UP
    不为求分
      

  2.   

    应该是你的自绘代码有问题
    在OnEraseBkgnd中使用PatBlt处理背景自画并return TRUE;
    在OnPaint不做任何处理
    在OnDraw中BitBlt你的事先准备好的内存DC
      

  3.   

    应该是你的paint中的代码的问题,还有,你可以限制你的刷新的区域,比如,有一个新的字符输入,然后你可以通过gettextextent函数取得这个字符串的显示的大小,然后计算出输入一个字符串后需要更新的区域.不是说输入了一个字符,就整个屏幕刷新的.或者整行刷新.
      

  4.   

    GetTextExtent函数是cdc的成员函数,可以取得使用当前字体显示一个字符串占用的区域大小.
      

  5.   

    请各位大哥看一下我的话咯,我已经是局部重绘了,并且已经处理了OnEraseBkgnd事件处理函数,但是我是在其中直接返回TRUE来完成的。OnPaint没有做任何事情,OnDraw中实现了BitBlt。
    我现在已经是只绘制需要绘制的部分,而没有重绘整个客户区
      

  6.   

    直接DrawText上去的效果和BitBlt的差别不大!
      

  7.   

    MSDN里面的DrawCLI示例(MFC)里面的CDrawView::OnDraw中演示了如何使用双缓冲来消除闪烁
      

  8.   

    to: nlstone(天外流星)
    我就是在拖动滚动条时候刷新实在无法忍受,特别是滚动大片区域的时候,非常明显的闪烁。你的意思是开多线程来避免闪烁?
    to:jiangsheng(蒋晟.MSMVP2004Jan)
    谢谢,我看看试一试
      

  9.   

    1 文本编辑器为什么不用现成的一些如CRichEdit之流?
    2 如果你要实现滚动的平滑,就不要在滚动条消息中不停地重绘,而是要把内存DC里的位图做大一些,譬如三个显示区域高,这样,在三个显示
      

  10.   

    1 文本编辑器为什么不用现成的一些如CRichEdit之流?
    2 如果你要实现滚动的平滑,就不要在滚动条消息中不停地重绘,而是要把内存DC里的位图做大一些,譬如三个显示区域高,这样,在三个显示区域内的滚动就无须重绘,而只是调整bitblt贴图的位置,这样是不会有闪烁的.若超出此范围,则进行一次重绘另,既然屏幕上的东东都是位图贴出来的,是不应该有"闪烁"的问题,充其量你重绘过于频繁造成移动不平滑,有迟滞感.如果是"闪烁"的话,还是要检查你自己的代码了...
      

  11.   

    1.使用CRichEdit不能满足我的需求,并且我没有源代码,无法对它进行修改!
    2.我现在的局部重绘,也是调整BitBlt贴图的位置,就是有非常明显的闪烁(大块区域),如果是一行高度的话,闪烁并不明显,但是还是看的出来,使用两种颜色就很明显,(意思就是一个视图分割为2块,一块区域填充一种颜色,另外一块区域填充为白色,这样当滚动一行的时候,就可以比较明显的看到闪烁!
      

  12.   

    我借鉴了一些开源的代码,很多代码效率非常的低下,通过整屏的bitblt来进行重绘,当滚动一页的时候,也有很明显的闪烁,另外一些代码就简直是夸张至极,首先支持跨平台,能用设计模式的地方狂用设计模式,所有的东西都是类,代码没有注释,效率的确很高,但是不是使用MFC(因为要跨平台),首先构建了一个Window类,然后跨平台的缘故,里面的#IFDEF...#ELSE...#ENDIF之类的宏非常的多。代码量很大,我找了半天还是没有找到他的代码哪里在进行真正的控件平面的重绘操作,封装的非常的深。所以也没有看出所以然,在此发贴求教,希望可以得到些建议和意见。
      

  13.   

    我一直在关注类似的GDI重绘效率的问题,强烈关注此贴
      

  14.   

    看到闪烁是不对的,你可以想一想造成"视觉闪烁"的根本原因......
    在拖动滚动条的时候并不存在"局部重绘"的情况...
    你可以把你的具体方案说一下,你的描述还不足以看清问题的本质另,2D显示要追求效率的极致,在win32下还是要用到DDraw/OpenGL,但在你的需求中,似乎还不必出此绝招
      

  15.   

    我现在的处理方式是,滚动滚动条时候一定会绘制出正确的文本内容,这样我就先绘制到内存DC上面,然后使用BitBlt拷贝到设备DC上面,这里的代码我可以保证是正确的,但是不知道是否有效率问题,但是我觉得GDI的能力足以应付像文本编辑器这样的需求!
    当滚动条滚动一行内容的时候,就是一个明显的局部重绘了阿,我只BitBlt一行文本高度宽度的兼容位图给设备DC阿
      

  16.   

    nlstone(天外流星):那么你的意思就是说不要建立内存DC,而是直接建立兼容位图咯?如果建立内存DC的话,一定是需要经过一次BitBlt的,否则不可能把兼容位图的内容给拷贝到设备DC上面,那么是否就是建立兼容位图,选入到当前的设备DC上面,直接在这个兼容位图上面进行绘图和滚动?这里的滚动如果使用ScrollWindow恐怕还是不会有内容被绘制出来吧
      

  17.   

    事实上ultraedit和ie6都运用了directdraw技术。闪烁可能是重绘太频繁引起的。
      

  18.   

    to: pagechen(天外飞来的仙) 
    我觉得UltraEdit没有用到DirectDraw技术!以GDI的能力我觉得完全可以轻松的完成平滑滚动文本这样的需求,只是我现在还没有找到一个好的办法来解决而已!我相信一定是可以的
      

  19.   

    我也不理解uedit为何在p3-667和4M显卡上运行的那么好。期待ing
      

  20.   

    to:nlstone(天外流星)
    那么应该把兼容位图选入到兼容DC中,但是要把兼容DC的内容传递给设备DC还是需要经过一次BitBlt才行,而不能经过ScrollWindow来进行滚动阿
      

  21.   

    http://community.csdn.net/Expert/topic/3790/3790991.xml?temp=.6798059借宝地一用,友情UP。
      

  22.   

    Why do you need to use bitmap in the first place?For scrolling, you should use ScrollDC and then just repaint the newly exposed window.Why do you want to write another editor?
      

  23.   

    1. 输入的时候使用局部刷新 InvalidateRect
    2. 滚动的时候使用 ScrollWindow 函数
      

  24.   

    袁峰老大终于出面了,感动阿T_T!
    因为我使用了DrawText来绘制文本到设备DC上的效果和使用双缓冲后的效果差别不大,但是我觉得使用DrawText的速度还是比BitBlt的速度快一些,因为闪烁感没有那么强烈。
    袁大哥ScrollDC这个API是滚动DC用的,那么我用它直接滚动设备DC是否有效呢?我现在的代码写了很多了,不知道如何下手去修改这些代码了。敬请指教!
    因为Windows自带的Edit和RichEdit不能满足我的需求,所以我才下定决心自己写一个Editor的
      

  25.   

    ScrollDC is the answer,try it
      

  26.   

    我试验过使用ScrollDC来滚动窗口,效果和ScrollWindow差不多阿?我原来使用的是ScrollWindow来滚动客户区域的,我现在觉得问题可能出在我的输出文本的代码上面!
      

  27.   

    1) Show your code.
    2) Measure the performance of your code.
    3) Setup a goal on how fast do you want it to be.
      

  28.   

    我把我的垂直滚动条滚动后计算的代码和刷新的代码贴出来.
    void xxxx::ScrollToLine(int nNewLineOffset, bool bNoSmoothScroll /*= false*/, bool bTrackScrollBar /*=true*/)
    {
    if (nNewLineOffset != nTopLine)
    {
    if (bNoSmoothScroll || !bSmoothScroll) {
                             int ScrollLines = nTopLine - nNewLineOffset; //滚动多少行
                             nTopLine = nNewLineOffset;
                             CRect rect;
                             ScrollDC(GetDC()->m_hDC, 0, ScrollLines * GetLineHeight(), 
                             &mClientRect, NULL, NULL, &rect);
           InvalidateRect(&rect, TRUE);
           UpdateWindow();
             }
    {
    int nLineHeight = GetLineHeight(); //得到行高度
    if (nTopLine > nNewLineOffset)
    {
    int nIncrement = (nTopLine - nNewLineOffset) / 
    SMOOTH_SCROLL_FACTOR;
    nIncrement += 1;
    while (nTopLine > nNewLineOffset)
    {
    int TopLine = nTopLine - nIncrement;
    if (nTopLine < nNewLineOffset)
    nTopLine = nNewLineOffset;
    int ScrollLines = TopLine - nTopLine;
    nTopLine = TopLine;
    ScrollDC(GetDC()->m_hDC, 0, -nLineHeight * 
                                                  ScrollLines, NULL, NULL, NULL, NULL);
    UpdateWindow();
    if (bTrackScrollBar)
    RecalcVertScrollBar(true);
    }
    }
    else //if (nTopLine <= nNewLineOffset)
    {
                                         int nIncrement = (nNewLineOffset - nTopLine) / 
                                         SMOOTH_SCROLL_FACTOR ;
    nIncrement += 1;
    while (nTopLine < nNewLineOffset)
    {
    int TopLine = nTopLine + nIncrement;
    if (nTopLine > nNewLineOffset)
    nTopLine = nNewLineOffset;
    int nScrollLines = TopLine - nTopLine;
    //&micro;±&Euml;ü&Ouml;&micro;&Icirc;&ordf;&cedil;&ordm;&Ecirc;&yacute;&micro;&Auml;&Ecirc;±&ordm;ò,±í&Atilde;÷&acute;&Oacute;&Eacute;&Iuml;&Iacute;ù&Iuml;&Acirc;&sup1;&ouml;&para;&macr;,·&acute;&Ouml;&reg;&Ocirc;ò&Ecirc;&Ccedil;&acute;&Oacute;&Iuml;&Acirc;&Iacute;ù&Eacute;&Iuml;&sup1;&ouml;&para;&macr;
    //mnNeedRepaintLine = nScrollLines;
    nTopLine = TopLine;
    //ScrollWindow(0, -nLineHeight * nScrollLines);
    ScrollDC(GetDC()->m_hDC, 0, -nLineHeight * nScrollLines, NULL, NULL, NULL, NULL);
    UpdateWindow();
    if (bTrackScrollBar)
    RecalcVertScrollBar(true);
    }
    }
      

  29.   

    void xxxx::ReDrawLines(CDC *pDC)
    {
    CRect rcLine;       
    if (mrcNeedRepaint.IsRectNull() == FALSE)
    rcLine = mrcNeedRepaint;
    else
    rcLine = mClientRect;
    rcLine.top = rcLine.top - rcLine.top % nLineHeight;
    rcLine.bottom = rcLine.bottom - rcLine.bottom % nLineHeight; unsigned int uiCurrentLine = nTopLine;
    unsigned int uiDrawEndLine = 0;
    unsigned int uiCurrentChar = nOffsetChar;
    unsigned int uiDrawEndChar = 0;

    int iMarginWidth = GetMarginWidth();
    if ((bShowSideColumn) && (mrcNeedRepaint.left / nCharWidth))
    {
    uiCurrentChar += (mrcNeedRepaint.left - iMarginWidth) / nCharWidth;
    uiDrawEndChar = ((mrcNeedRepaint.right - iMarginWidth) / nCharWidth) + nOffsetChar;
    }
    else
    {
    uiCurrentChar += mrcNeedRepaint.left / nCharWidth;
    uiDrawEndChar += mrcNeedRepaint.right / nCharWidth + nOffsetChar;
    } uiCurrentLine += (mrcNeedRepaint.top - mClientRect.top) / nLineHeight;
    uiDrawEndLine = ((mrcNeedRepaint.bottom - mrcNeedRepaint.top) / nLineHeight) + uiCurrentLine;
    if (uiDrawEndLine > nLineCount)
    uiDrawEndLine = nLineCount;
    CRect rcSideColumn(0, rcLine.top, GetMarginWidth(), rcLine.top + nLineHeight);
    CRect rcCacheLine(GetMarginWidth(), rcLine.top, rcLine.Width(), rcLine.top + nLineHeight);
    CFont *pOldFont = pDC->SelectObject(fCurFont); while(rcLine.top < mClientRect.bottom)
    {
    if(uiCurrentLine < uiDrawEndLine)
    {
      if (bShowSideColumn)
    {
    DrawMargin(pDC, rcSideColumn, uiCurrentLine);
    }
    DrawSingleLine(pDC, rcCacheLine, uiCurrentLine, uiCurrentChar, uiDrawEndChar);
    }
    else
    {
    if ((mClientRect.bottom % nLineHeight != 0) && (uiCurrentLine <= uiDrawEndLine))
    {
    if (uiCurrentLine < uiDrawEndLine)
    {
    rcSideColumn.top = mClientRect.bottom - mClientRect.bottom % nLineHeight;
    rcSideColumn.bottom = mClientRect.bottom;
    rcCacheLine.top = rcSideColumn.top ;
    rcCacheLine.bottom = rcSideColumn.bottom ;
    } if (bShowSideColumn)
    {
    DrawMargin(pDC, rcSideColumn, uiCurrentLine, true);
    }
    DrawSingleLine(pDC, rcCacheLine, uiCurrentLine, uiCurrentChar, uiDrawEndChar, true);
    }
    else
    {
    if (bShowSideColumn)
    {
    DrawMargin(pDC, rcSideColumn, -1);
    }
    DrawSingleLine(pDC, rcCacheLine, -1, 0, 0);
    }
    }
    ++uiCurrentLine;
    rcLine.OffsetRect(0, nLineHeight);
    rcSideColumn.OffsetRect(0, nLineHeight);
    rcCacheLine.OffsetRect(0, nLineHeight);
    }
    //VERIFY(pDC->BitBlt(mrcNeedRepaint.left, mrcNeedRepaint.top, mrcNeedRepaint.Width(), 
    // mrcNeedRepaint.Height(), pCacheDC, mrcNeedRepaint.left, mrcNeedRepaint.top, SRCCOPY));
    //pCacheDC->SelectObject(pOldFont);
    pDC->SelectObject(pOldFont);
    }这段代码是重绘行使用的代码
      

  30.   

    I've read some of your code. The basic scrolling code is:ScrollDC(GetDC()->m_hDC, 0, ScrollLines * GetLineHeight(), &mClientRect, NULL, NULL, &rect);
    InvalidateRect(&rect, TRUE);
    UpdateWindow();I do not need bitmaps being used.1) How slow is your current code? Measure it.
    2) How fast do you want your code to be? 100% faster, 200% faster.
    3) Measure now much time is spent on ScrollDC. You have no way to improve it, except to minimize its area.
    4) Check whether rect returned by ScollDC is right
    5) UpdateWindow should call your OnDraw routine eventually. A faster ways is just call OnDraw, or functions called by it directly.
    6) Check if the parameters passed to OnDraw is optimal.
    7) Measure how much time is spent within OnDraw, check how can you reduce the area, how can you improve speed.BTW, what is the design goal of your code? Do you want it to be able to print? If so, you should avoid using DrawText.
      

  31.   

    因为兼容位图的使用已经被我注释掉了,我使用了内存DC和兼容位图以后,发现速度还没有直接使用DrawText快,因为最后我是使用BitBlt进行位块拷贝的,我要求文本在滚动时候的速度就是达到无闪烁的目标,类似UltraEdit和现在的主流的开发环境中的编辑器那样的程度.当使用滚动条滚动一屏的时候,BitBlt会造成很明显的刷新,所以我后来改代码的时候把这些相关代码注释掉了.我发给您的代码中应该还是可以看到那些被注释掉的代码.没有写这个类之前还不觉得,写了之后才发现我的基础是如此的薄弱,真的让自己有些无地自容.
      

  32.   

    粗扫描了一眼,发现 ScrollToLine 里面的 UpdateWindow() 是不是太多了?每个UpdateWindow都会引起OnPaint | OnDraw, 一次滚动 就要多次 OnPaint | OnDraw,效率自然不高。
      

  33.   

    不好意思,细看了一下,发现UpdateWindow也不是太多,虽然也没必要2次。
    不过贴出的代码部分也未看到涉及到绘图性能的关键部分。
      

  34.   

    could you give me your whole project? i'm interested in such problem...
    [email protected]
      

  35.   

    to:nlstone(天外流星)
    完整的工程实在不方便给出,视图类部分的代码可以给你一份。
      

  36.   

    > 这个问题真的那么难吗?这么多牛人都解决不了Do not expect other people to tell you which line to change. You have to do your own investigation. What have you done after I gave you a list of things to do?
      

  37.   

    进来一睹袁大哥芳容........
       拙才认为:一次把所有要显示的都画到ScrollDC上(当然不能很大,用全部绘制,局部绘制还是会有闪烁的),只有滚动条滚动到要超出该页的显示范围时才再次BitBlt。
      

  38.   

    to:zhaogaojian(米柑年成)
    这个方法就是我现在用的方法,效率不能接受
      

  39.   

    ??????
    我真的觉的好奇怪。
    又不是啥3D动画之类的。怎么会让人觉的闪?
    实现windows记事本的效果并不困难啊!!你说的大块区域,到底有多大?2M?
    那我可以肯定的说,拖来拖去,记事本也闪的。(不过俺的显卡集成的才1M显存,别人的不知道)
      

  40.   

    你贴的代码是不够的,如果双缓冲解决不了的话,我想问是哪种类型的闪烁?绘图太慢?楼主如果不方便发整个工程,能否把编译好的程序(或demo)发过来看看?([email protected])
      

  41.   

    我也做过记事本类似的程序,我使用双缓冲不会出现你说的闪烁问题,闪烁问题的产生有时候并不是速度的问题,而是你擦除背景再bitblt时造成的视觉闪烁。也有可能是你要求过于严格,如楼上所说,最好有编译好的程序看看效果,再做结论。
      

  42.   

    我已经发送了Demo给ipgk(loboho)了,不知道你看出什么端倪了吗?
    to:gameboy999(-'_'-) 
    我已经重载了OnEraseBkgnd并且直接返回TRUE但是没有什么作用啊
      

  43.   

    gz
    我也想写过类似的代码ps:其实如果文本多的话
     windows的记事本显示也很慢 可以 看着它是一大块 一大块的刷的
      

  44.   

    不好意思,一直没看邮箱,现在收到了。看了程序确实闪得很厉害,我看是你双缓冲没用好。只在OnEraseBackground返回TRUE是不够的,你要保证每次刷新向屏幕BitBlt只有一次,也就是所有画图操作在内存DC完成后再一次性显示到屏幕。不过用SCrollView滚动显示文本应该是不必要用双缓冲的。我做过一个十六进制显示文件的程序,使用了SCrollView,根据滚动条的位置实时读取文件显示,在显示很大的文件时比UE快得多,在这个程序我并没用双缓冲,但不存在闪烁的问题。
      

  45.   

    我发给你的例子中的方法已经改成直接往设备DC上面TextOut了,以前使用内存兼容位图BitBlt的时候会看到的是一大块一大块的重绘,而现在改成直接TextOut到设备DC上面后,就是看的很清楚的闪烁!
      

  46.   

    你确认你除了TextOut外,没有其他的绘图操作吗?比如擦除背景。OnEraseBkgnd有没做消息映射?在这个函数数下个断点,看有没执行到这里?我只告诉你,你的代码没问题的话,不会这样闪。