.NET GUI中实现字符串搜索高亮

在开发协议分析器的过程中,被要求编写一个图形用户界面(GUI),该界面能够将字符串中的某些部分用不同的背景颜色标记出来,以指示字符串中的搜索结果。由于字符串需要在自定义控件上绘制,因此必须自己进行绘制。

本可以将字符串分割成几个子字符串,并分别用不同的颜色绘制,但这将非常慢且不准确。幸运的是,.NET提供了一些复杂的(尽管存在bug)API:

  • SetMeasurableCharacterRanges
  • MeasureCharacterRanges

这对API能够提供绘制所需的信息,使能够在不需要进行复杂计算的情况下,精确地在请求的字符串部分下方绘制背景颜色。

首先,在搜索功能中,通过插入开始和结束标签来标记高亮部分,类似于HTML中的包围想要高亮的子字符串。因此,字符串看起来像这样:

"This is the highlighted portion of a string"

现在,在绘制函数中,首先调用GetCharacterRanges方法,该方法创建一个CharacterRange结构的列表。这个结构将包含每个高亮部分的字符串的起始位置和长度。然后,调用.NETAPI StringFormat.SetMeasurableCharacterRanges,它接受一个这些结构的数组,以便在下一次API调用中使用。

实现

调用Graphics.MeasureCharacterRanges现在将返回一个Region数组。每个Region包含基于先前传递的CharacterRegion数组的确切绘制信息。现在只剩下为每个这样的Region绘制FillRectangle来创建背景。最后,绘制字符串。

以下是C#代码实现:

private static string startTag = ""; private static string endTag = ""; private void Form1_Paint(object sender, PaintEventArgs e) { RectangleF f = new RectangleF(0, 0, 300, 30); DrawTaggedString(e.Graphics, "This is the highlighted portion of a string", Font, Brushes.Magenta, f, new StringFormat()); } private String GetCleanText(String text) { if (text == null) { return null; } string cleanString = text.Replace(startTag, ""); cleanString = cleanString.Replace(endTag, ""); return cleanString; } private static List GetCharacterRanges(string text) { int start = 0; List characterRanges = new List(); int charsRemoved = 0; while (start < text.Length) { start = text.IndexOf(startTag, start); if (start >= 0) { int end = text.IndexOf(endTag, start); int ofs = start - charsRemoved; int length = end - charsRemoved - startTag.Length - ofs; characterRanges.Add(new CharacterRange(ofs, length)); start = end + startTag.Length; charsRemoved += (startTag.Length + endTag.Length); } else { break; } } return characterRanges; } public void DrawTaggedString(Graphics g, String text, Font font, Brush brush, RectangleF layoutRect, StringFormat stringFormat) { List characterRanges = GetCharacterRanges(text); int offset = 0; int countLeft = characterRanges.Count; do { int count = Math.Min(countLeft, 32); List subRange = characterRanges.GetRange(offset, count); int ranges = subRange.Count; string cleanString = GetCleanText(text); stringFormat.SetMeasurableCharacterRanges(subRange.ToArray()); Region[] stringRegions; stringRegions = g.MeasureCharacterRanges(cleanString, font, layoutRect, stringFormat); for (int i = 0; i < ranges; i++) { RectangleF measureRect = stringRegions[i].GetBounds(g); g.FillRectangle(Brushes.Blue, Rectangle.Round(measureRect)); } g.DrawString(cleanString, font, brush, layoutRect, stringFormat); offset += count; countLeft -= count; } while (countLeft > 0); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485