1

I have an mfc application in which i have to display text. Whenever I use the scrollbar , the OnDraw() function is called. This is my OnDraw() function:

CString fileText = pDoc->GetFileText();   //get text from file
CRect rect;
GetClientRect(&rect);

pDC->DrawText(fileText.GetString(), &rect, DT_LEFT|DT_NOCLIP);

This seems to be inefficient because scrolling is taking forever. The problem is that I am repainting the entire textfile again. I want to use the GetClipBox function to redraw only that which is required. Can anyone give me suggestions on how to proceed?

Thanks.

molu
  • 77
  • 1
  • 11

2 Answers2

1

Double buffering won't help you here since you're still drawing the whole string to the off-screen bitmap. What you want is to only draw the part of the string that is actually being shown, which is easier said than done.

First, if each line has the same height, that makes it 10 times easier (I'm also assuming you don't have funny stuff like in-line images, formatting, paragraph spacing, etc). Basically what you want to do is derive how far along the total amount of lines your scroll bar is (let's say you have 1000 lines, and your scrollbar is at 50%, that means you need to start drawing from the 500th line onwards) and how many lines of text you can display (easily calculated by dividing the height of the control by the height of each line).

Then, your extract those lines from the string, and you only pass those to DrawText(). The easiest way to do this is to store the total text not as one string, but as a vector of strings, one line in each entry.

Now there are still a bunch of details to get right such as what to display when you scroll all the way to the end, do you allow half lines to be visible, etc., but essentially the above is what it boils down to.

Furthermore, I hope you're not reading the text from a file on each OnDraw(), because that alone might cause the slowdown.

GetClipBox() isn't really relevant here, since you'll want to redraw the whole content of your content window anyway, even if you only scroll 1 pixel. The point is to reduce the amount of things to draw (that you pass to DrawText()), not to limit the amount of screen space that is being drawn to.

Roel
  • 19,338
  • 6
  • 61
  • 90
  • When you redraw the entire string I agree that double buffering is still going to be slow if you're drawing the whole string. However, just for scrolling, you don't need to redraw the string at all - just BitBlt your memory bitmap to screen which should be pretty quick. I agree with you though - to speed the full redraw up you need to break the text up into parts and work out which ones you need to draw. Which is tricky. – Redeye Jul 04 '12 at 20:32
  • Well, I guess the way forward is splitting the text in lines and drawing only the relevant ones. Like you said,it's gonna be tricky.Also, thanks for your answers. – molu Jul 05 '12 at 07:54
0

I think the best solution to your problem is probably double buffering. Basically, do your painting to an off-screen bitmap, then when OnPaint() is called, just call

CRect rcUpdate;
GetClipBox(rcUpdate);
pDC->BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(),
                        m_pMemDC, rcUpdate.left, rcUpdate.top, SRCCOPY);

Which will just copy the updated section of the screen and should improve your performance considerably.

I posted some code to help with the double buffer in a previous question here which might help. That also includes GDI+ code which you don't actually need and can just omit.

Community
  • 1
  • 1
Redeye
  • 1,582
  • 1
  • 14
  • 22
  • Thanks for your answer.Tried double buffering. Followed instructions [here](http://www.codeproject.com/Articles/33/Flicker-Free-Drawing-In-MFC). It doesn't work. It's worse, in fact. I'm working with text files of about 10mb each. GetClipBox() seems to be the only way( that i know of). However, I don't know how to go about it. – molu Jul 04 '12 at 08:23
  • 1
    I'm very surprised double buffering is slower - I can only assume that there's a problem with the implementation somewhere. However, rendering text files that big probably needs a different approach. You're probably right that you need to use GetClipBox(). You then somehow need to work out what text needs redrawing for that CRect and only draw that part to screen rather than the whole document. I think you'll need to break down that string into sub-strings and maintain a list of CRects that they're drawn into to work that out, but somebody else might be able to suggest a better approach. – Redeye Jul 04 '12 at 09:51
  • Also, when I try to follow the code in the link you mentioned, I'm getting an error with Graphics. VS2010 says its an unknown identifier.Why is that? – molu Jul 04 '12 at 09:59
  • You don't need the Graphics parts - that's just for the GDI+ parts. To get around it you'll need "using namespace Gdiplus" and also remember to initialise GDI+ when you start the application. – Redeye Jul 04 '12 at 20:26