RichEditBox speed

  • Thread starter Thread starter sb
  • Start date Start date
S

sb

Is there anyway to speed up the selecting and coloring of text in a
richedit. The parsing of the text is nothing in comparison with how long it
takes these two calls to take place (over many lines):

rtb.Select(currentPos, myLine.Length);
rtb.SelectionColor = myColor;

From my research, there are a few ways to speed up the richedit but none of
them help speed up the coloring process:
1) Inherit from the RichEdit and in an overloaded WndProc, ignore WM_PAINTs
while updating
2) Use SendMessage to pause redraws/events (EM_SETEVENTMASK, SETREDRAW)while
updating
3) Hide the RichTextBox while updating (seems to work the best...but it is
still slow)

Does anyone else out there have any better suggestions? I want to color the
entire richeditbox in one sweep...so I don't have flickering or other
noticeable side-effects caused by scrolling. I'm not looking to use a 3rd
party control either for a number of reasons.

TIA!
sb
 
Is there anyway to speed up the selecting and coloring of text in a
richedit. The parsing of the text is nothing in comparison with how long it
takes these two calls to take place (over many lines):

rtb.Select(currentPos, myLine.Length);
rtb.SelectionColor = myColor;

From my research, there are a few ways to speed up the richedit but none of
them help speed up the coloring process:
1) Inherit from the RichEdit and in an overloaded WndProc, ignore WM_PAINTs
while updating
2) Use SendMessage to pause redraws/events (EM_SETEVENTMASK, SETREDRAW)while
updating
3) Hide the RichTextBox while updating (seems to work the best...but it is
still slow)

Does anyone else out there have any better suggestions? I want to color the
entire richeditbox in one sweep...so I don't have flickering or other
noticeable side-effects caused by scrolling. I'm not looking to use a 3rd
party control either for a number of reasons.

I have a way of handling this problem that satisfies me. It is simple
enough that you could probably try it out without investing too much time.
The gist follows.

Associated with the rtb create a boolean flag bFrozen initialized to false.
So long as it stays false, the rtb behaves normally. Set bFrozen to true to
freeze the rtb during a bunch of updates. You handle the rtb's Invalidated
event by:
if bFrozen then Validate the entire rtb window
else do nothing (ie normal rtb operations)
To Validate the entire rtb window, you call win32 api ValidateRect:
ValidateRect(Rtb.Handle.ToInt32, 0)
Finally, when you want to unfreeze, set bFrozen to false and do
Rtb.Invalidate.

So, in essence, this mechanism prevents painting by making windows think the
rtb doesn't need to be painted. Any scrolling and flicker is thus stopped,
and these are the activities create poor appearance. Also, painting is
expensive cpu-wise. But be advised, if you are colorizing a very large rtb,
you may still have performance problems by using what is readily at hand with
the rtb. A really high performance alternative would produce rtb.rtf via
stringbuilder and would require considerable knowledge about rtf
specifications. I wouldn't want to go there.

Like you, I also have tried some alternatives and have found them wanting
for one reason or another.
 
I just ran a test of my suggestion in a larger setting than is my usual, and
it didn't perform as desired. There was flicker associated with making
selections. So I am dubious of my suggestion helping you. Sorry about that.
 
Thanks for trying anyway. Your idea should equate to my use of SendMessage
and WM_SETREDRAW to suspend drawing messages from being sent while I'm
updating the richtextbox. From your last post, I see that you had the same
results as I did...flickering.

Back to the drawing board...

I'm beginning to think that my only choice is to design my own usercontrol
(or maybe inherit from a normal textbox) and do all of the painting myself.
In my case, I'm only dealing with text (no pictures or anything else)...so
it's a viable option. Speed would no longer be a problem since I could just
parse/colorize what's visible on screen. However, doing it that way also
means that I have to handle all window scrolling manually...which isn't very
fun. I've written an editor before in C# that does that through interop
calls and I could copy a lot of the code from there...but I was really
hoping to avoid all of that :)

Thanks!
sb
 
Back to the drawing board...

What I suggested earlier failed because of selections and scrolling (I'm
fairly sure of this). It has worked well for me in cases where there wasn't
much data in the rtb, and I had forgotten about its limits.

I still have an interest in this problem. I think our uses of the rtb in
this problem area are similar. In my case, I have an rtb docked to all edges
of the form. There is generally one font, usually a monospace font, and
occasionally more than one font for highlighting. I have color highlighting
requirements. There is a vertical scroll bar. There is either a horizontal
scroll bar or wordwrap is enabled. It is basically a bottomless textbox. No
images, no embedded objects, nothing fancy. I want good speed and visual
(flicker-free) performance.

I ran one more experiment and had some success with it, but the results are
preliminary. What I did was add a second rtb to the form that is also docked
to all sides of the form. You will see one or the other based on z order.
While rtb1 is in view, I write to rtb2, select, scroll, colorize, and at the
end, bring rtb2 to the top of the z order. Double buffering with rtbs, if
you catch my drift.

A while back, I couldn't get anywhere by changing rtb.Visible. But staying
visible while obscured by zorder seems to work. I get only one flash at the
end of the updates.

So it seems to handle flicker. How fast is it? I don't know yet. I need
to test against some rtb contents that takes a few seconds the old way. How
robust is it? No clue, needs development and test. But this does show
promise, so I thought I'd post now.
 
I ran one more experiment and had some success with it, but the results are
preliminary. What I did was add a second rtb to the form that is also docked
to all sides of the form. You will see one or the other based on z order.
While rtb1 is in view, I write to rtb2, select, scroll, colorize, and at the
end, bring rtb2 to the top of the z order. Double buffering with rtbs, if
you catch my drift.

A while back, I couldn't get anywhere by changing rtb.Visible. But staying
visible while obscured by zorder seems to work. I get only one flash at the
end of the updates.

So it seems to handle flicker. How fast is it? I don't know yet. I need
to test against some rtb contents that takes a few seconds the old way. How
robust is it? No clue, needs development and test. But this does show
promise, so I thought I'd post now.

I ran some more tests with large and small rtb contents, and the results are
as follows. All I was doing was colorizing all occurrences of a common
substring in the rtb text. The good news is that there was no flicker. The
bad news is that there was only marginal improvement in performance. Under
profiling, I found that nearly half the time was in .Select and nearly half
was in property get .Text. So, even when the rtb was not actually being
visibly scrolled, the .Select calls were expensive. I might be able to cache
..Text to save speed things up, but the .Select calls can't be eliminated.

The bottom line, IMO, is that the technique is effective in stopping flicker
and it is not effective in improving performance. The natural way to make
text effects in an rtb is based on selection, so it is doomed to so-so
performance. Performance is linear with the number of .Select calls (ie it
is linear with the number of highlights actually applied). I've seen some
writeups by people promising high performance rtbs, but I haven't tried any
of them.
 
Thanks for the info...very useful.

I was going to try the duel RTB approach but you saved me the time. Just
like you, I profiled my code and noticed that rtb.Select calls are the
bottleneck. I'm going to use Reflector and see if I can find a bottleneck
in the framework code that I may be able to work around...it wouldn't be the
first time that the framework code did something stupid that killed
performance. I'll let you know if I find anything of interest there.

It would be so much simpler if we could just have the underlying RichEdit
provide a callback before it paints each line to allow code to adjust the
formatting if necessary. Then I could just parse/colorize what's about to
be displayed...which would be lightning fast.

sb
 
Back
Top