473,503 Members | 12,791 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

RichTextBox repainting artifacts

I have created a Control that extends RichTextBox to do syntax-hilighting. My
strategy is to have a timer that restarts every time a user types a key so
that it can wait until the user pauses for at least 500 milliseconds, then
perform its work. The hilighting simply goes through a list of keywords,
finding each instance in the RichTextBox, and selecting it in order to change
its color. I figured out how to remember where the cursor is and put it back
where the user left it. I even bracketed all my activity with a
SuspendLayout/ResumeLayout. But I cannot get around my problem: the RTB has
an annoying flash/scroll/jump each time my hilighting occurs (if there are
more lines in the box than the height of the box). How can I avoid this?

Here is the code basics:
==================================
private void SyntaxHilightTextBox_TextChanged(object sender, EventArgs e)
{
if (timer.Tag.Equals(1)) { return; }
if (timer.Enabled) { timer.Stop(); }
timer.Start(); // restart it
}

private void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
timer.Tag = 1; // disable TextChanged so our changes are transparent
SuspendLayout();
Colorize();
ResumeLayout();
timer.Tag = 0; // re-enable TextChanged
}

private void Colorize()
{
int saveCaret = CaretPosition();

// Restore all text to black.
// Prevents terminal hilighting from bleeding into new typing.
SelectAll();
SelectionColor = Color.Black;

ColorWords(myWordList);

SelectionStart = saveCaret; // restore caret
SelectionLength = 0;
}

public void ColorWords(string[] text)
{
foreach (string s in text) { ColorWord(s); }
}

public void ColorWord(string text)
{
RichTextBoxFinds options =
(RichTextBoxFinds.WholeWord | RichTextBoxFinds.NoHighlight);
int start = Find(text, options);
bool done = (start < 0);
while (!done)
{
SelectionStart = start;
SelectionLength = text.Length;
SelectionColor = hilightColor;
int lastStart = start;
start = Find(text, start + text.Length, options);
done = (start <= lastStart);
}
}

==================================
Mar 20 '07 #1
8 2575
Additional note:
If I disable the auto-hilight and put it on a button, the button works great
(i.e. no annoying flash/scroll). Is this possibly because the timer tick
occurs on a different thread? I tried adding some debug lines to identify
thread differences, but if I instrumented that correctly it is on the same,
main thread. Any suggestions from this point?

Mar 27 '07 #2
Hi Michael,

I performed a test based on your sample code and did see the problem on my
side. But I don't think the problem is caused by the timer tick occurring
on a thread other than the UI thread. It is UI thread that executes the
timer's Tick event handler when the timer's Tick event occurs.

I think the reason of the problem is that you're attempting to
select/unselect the text in the RichTextBox while it gets focused, which
causes the window flash/scroll.

I suggest that you remove the timer in your project and only check the
words near the current input cursor to see if they match the key words, if
yes, select them and change their color. In this way, you needn't always
re-check ALL the text and re-hilight those key words.

The following is a sample. It requires that you add a RichTextBox control
on the form.

public partial class Form1 : Form
{
string[] myWordList = new string[] { "the", "a", "an" };
Color hilightColor = Color.Orange;

public Form2()
{
InitializeComponent();
this.richTextBox1.TextChanged += new
EventHandler(richTextBox1_TextChanged);
}

void richTextBox1_TextChanged(object sender, EventArgs e)
{
if (this.richTextBox1.Text.Trim() != "")
{
if (this.GetCharBeforeSelectionStart() == 0)
{
this.ProcessNextWord(this.richTextBox1.SelectionSt art);
}
if (this.GetCharBeforeSelectionStart() == ' ' ||
this.GetCharBeforeSelectionStart() == '\n')
{
this.ProcessPreWord(this.richTextBox1.SelectionSta rt);
this.ProcessNextWord(this.richTextBox1.SelectionSt art);
}
else
{

this.ProcessCurrentWord(this.richTextBox1.Selectio nStart);
}
}
}

private char GetCharBeforeSelectionStart()
{
if (this.richTextBox1.SelectionStart == 0)
{
return '0';
}
else
{
return
this.richTextBox1.Text[this.richTextBox1.SelectionStart - 1];
}
}
private bool IsMatchKeyword(string text)
{
int i = 0;
for (; i < myWordList.Length; i++)
{
if (myWordList[i] == text)
{
break;
}
}
if (i < myWordList.Length)
return true;
else
return false;
}

private void ProcessCurrentWord(int carsetIndex)
{
int wordstart = carsetIndex -1;
while ((wordstart - 1 >= 0) &&
(this.richTextBox1.Text[wordstart - 1] != ' ' &&
this.richTextBox1.Text[wordstart-1]!='\n'))
{
wordstart--;
}
int wordend = carsetIndex - 1;
while ((wordend + 1 < this.richTextBox1.TextLength) &&
this.richTextBox1.Text[wordend + 1] != ' ' &&
this.richTextBox1.Text[wordend +1] != '\n')
{
wordend++;
}
string wordtext = this.richTextBox1.Text.Substring(wordstart,
wordend - wordstart + 1);
this.richTextBox1.SelectionStart = wordstart;
this.richTextBox1.SelectionLength = wordend - wordstart + 1;

if (IsMatchKeyword(wordtext))
{
this.richTextBox1.SelectionColor = this.hilightColor;
}
else
{
this.richTextBox1.SelectionColor =
this.richTextBox1.ForeColor;
}
this.richTextBox1.SelectionStart = carsetIndex;
this.richTextBox1.SelectionLength = 0;
}

private void ProcessPreWord(int carsetIndex)
{
int wordend = carsetIndex -1;
while (wordend >= 0 && (this.richTextBox1.Text[wordend] == ' '
|| this.richTextBox1.Text[wordend] == '\n'))
{
wordend--;
}
int wordstart = wordend;
if (wordstart 0)
{
while ((wordstart - 1 >= 0) &&
this.richTextBox1.Text[wordstart-1] != ' ' &&
this.richTextBox1.Text[wordstart-1]!='\n')
{
wordstart--;
}
}
if (wordstart >= 0)
{
this.richTextBox1.SelectionStart = wordstart;
this.richTextBox1.SelectionLength = wordend - wordstart + 1;

string wordtext =
this.richTextBox1.Text.Substring(wordstart, wordend - wordstart + 1);
if (IsMatchKeyword(wordtext))
{
this.richTextBox1.SelectionColor = this.hilightColor;
}
else
{
this.richTextBox1.SelectionColor =
this.richTextBox1.ForeColor;
}
this.richTextBox1.SelectionStart = carsetIndex;
this.richTextBox1.SelectionLength = 0;
}
}

private void ProcessNextWord(int carsetIndex)
{
int wordstart = carsetIndex -1;
while ((wordstart < this.richTextBox1.TextLength) &&
(this.richTextBox1.Text[wordstart] == ' ' ||
this.richTextBox1.Text[wordstart]=='\n'))
{
wordstart++;
}
int wordend = wordstart;
if (wordend < this.richTextBox1.TextLength - 1)
{
while (wordend + 1 < this.richTextBox1.TextLength &&
this.richTextBox1.Text[wordend +1]!= ' '&&
this.richTextBox1.Text[wordend+1]!='\n')
{
wordend++;
}
}
if (wordstart < this.richTextBox1.TextLength)
{
this.richTextBox1.SelectionStart = wordstart;
this.richTextBox1.SelectionLength = wordend - wordstart + 1;
string wordtext = this.richTextBox1.Text.Substring
(wordstart,wordend - wordstart +1);
if (IsMatchKeyword(wordtext))
{
this.richTextBox1.SelectionColor = this.hilightColor;
}
else
{
this.richTextBox1.SelectionColor =
this.richTextBox1.ForeColor;
}
this.richTextBox1.SelectionStart = carsetIndex;
this.richTextBox1.SelectionLength = 0;
}
}
}

Hope this helps.
If you have anything unclear, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Apr 13 '07 #3
While I appreciate your industriousness in providing a good bit of code, it
seems like a lot of code to workaround a simple repaint issue. Also, it will
handle typing but I do not think it could deal with cut-and-paste very well.

I do agree that it is not a thread issue and that it is related to the
selection/focus issue. So is there not a simple way to suspend the UI
activity while doing some processing? That is what I was hoping the
SuspendLayout/ResumeLayout bracketing would do, but it did not.
Apr 16 '07 #4
Hi Michael,

Thank you for your reply.

Yes, you're right that my code doesn't work well when the user pastes a
block of text into the RichTextBox.

The key point of your solution is that the RichTextBox get focused when
you're trying to select its text. So a better way solve the problem is to
make the RichTextBox lose the keyboard focus before we're trying to select
the text and restore the focus after we finish the task, based on your
original code.

To make a control lose focus, we could use the Win32API function
'SendMessage' to to send a 'WM_KILLFOCUS' message to the RichTextBox.

The following is a sample.

using System.Runtime.InteropServices;
class API
{
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd,uint msg, IntPtr
wParam, IntPtr lParam);
}

uint WM_KILLFOCUS = 0x0008;
// this is your original method
void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
timer1.Tag = 1; // disable TextChanged so our changes are
transparent
// SuspendLayout();
API.SendMessage(this.richTextBox1.Handle, WM_KILLFOCUS,
IntPtr.Zero, IntPtr.Zero);

Colorize();
// note that we need to get the form focused first
this.Focus();
this.richTextBox1.Focus();

// ResumeLayout();
timer1.Tag = 0; // re-enable TextChanged
}

Please try my suggestion and let me know the result.

Sincerely,
Linda Liu
Microsoft Online Community Support

Apr 18 '07 #5
That works great--thank you!!

Just a couple followup questions (marginally related to your solution
details):

(1) I had already been using SendMessage in the same class for another
purpose with this signature:
private static extern IntPtr
SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

That differs subtlely from the signature you provided:
public static extern int SendMessage(IntPtr hWnd,uint msg, IntPtr
wParam, IntPtr lParam);

However, I was able to alter the arguments you provided to fit my existing
signature and it worked fine:
const int WM_KILLFOCUS = 0x0008;
HandleRef hr = new HandleRef(this, base.Handle);
SendMessage(hr, WM_KILLFOCUS, 0, 0);

My question: Is one of these SendMessage signatures more "correct" ? My
knowledge of the Win32API is very minimal.

(2) Could you provide a URL to the Win32API documentation root? In the
future when I want to tinker with a control I would like to be able to dig
through the documentation to see if there is a command to do what I might
need.

Apr 18 '07 #6
Hi Michael,

Thank you for your prompt feedback.

The parameters of the SendMessage function may differ for different Windows
message it is going to send. It is OK to use your existing signature of
SendMessage to send the WM_KILLFOCUS message.

MSDN has provided a full reference for Win32API. You may visit the
following link for it:

'Windows API'
http://msdn2.microsoft.com/en-us/library/aa383750.aspx

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

Apr 19 '07 #7
Hi Michael,

How about the problem now?

If you have anything unclear, please feel free to let me know.

Thank you for using our MSDN Managed Newsgroup Support Service!

Sincerely,
Linda Liu
Microsoft Online Community Support

Apr 23 '07 #8
As I indicated on my 4/18 post, your information at that point solved my
problem (and I marked your post with a checkmark indicating it answered the
question).
The follow-up questions were just for future reference.

Thanks again.

"Linda Liu [MSFT]" wrote:
Hi Michael,

How about the problem now?

If you have anything unclear, please feel free to let me know.

Thank you for using our MSDN Managed Newsgroup Support Service!

Sincerely,
Linda Liu
Microsoft Online Community Support

Apr 23 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
1273
by: Mike Richardson | last post by:
Hello, I am using VB.net. Is there a way to stop the screen from repainting. I would perfer to stop screen repainting for the entire application. Example when a form is loading. Stop...
0
3213
by: nouno | last post by:
I am trying to spell check a richtextbox. Through code (shown below) I save the contents of the richtextbox to a rtf file, open the rtf file in Word, spell check it, save it, and then load the ftf...
2
17266
by: JonnyT | last post by:
I searched high and low for an answer on how to auto scroll a richtextbox and now I finally have it. Since it took me a while to get a good efficient way of doing it that didn't require focus to...
5
1420
by: Jesse Aufiero | last post by:
Hello all, I have many buttons on a form and at the bottom of the form is a grid that behaves as though it is 'retractable' - at various times during the life of the app, the grid becomes taller...
9
4838
by: James Wong | last post by:
Hi, I use the RichTextBox in my program. It will use different language in this RichTextBox (chinese and english characters), and it set the "DualFont" and use different fonts. By the way, how...
1
1081
by: kjensen | last post by:
Hi I'm working on a simple FTP server implementation but I've run into a strange problem. I use this function to recieve: def stor(self): f = open('test', 'w') while 1:
2
2111
by: vunet.us | last post by:
Please, explain an interesting phenomenon, if you can. I have an array of references to an HTML element: <div id='container'> <div id='someId1'></div> <div id='someId2'></div> </div> ........
0
2028
by: Vimalathithan | last post by:
I just developing a editor. I have provide the options like Bold, Italic, underlin, font change, font size change. These font options are keep in with one toolstripbutton. the toolstripbar keep...
0
1536
by: =?Utf-8?B?UmF5IE1pdGNoZWxs?= | last post by:
Hello, I have a scrolling RichTextBox to which I add characters one at a time using the AppendText method as they are received by my application. Some of these characters may be backspace...
0
7212
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7296
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7364
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
7017
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
5604
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5026
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
3174
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1524
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
751
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.