如何使用图形突出显示控件中的包装文本?

时间:2018-01-12 08:54:20

标签: c# winforms highlight textwrapping

我需要使用fill rect突出显示控件中的特定字符。 我可以通过使用下面的Graphics.MeasureString()方法来获取文本的位置,

var size = g.MeasureString(tempSearchText, style.Font, 0, StringFormat.GenericTypographic);

enter image description here

如果文本被包装,那么我无法找到角色的确切界限来突出显示文本。

enter image description here

我需要在包装的文本中获取给定字符的确切界限。提供您的建议以实现此方案。

1 个答案:

答案 0 :(得分:4)

没有明确说明要针对哪些控件,因此我测试了3种不同的控件:
sendToDevice(tokens, patchedPayload, options)TextBoxRichTextbox

TextBox和RichTextbox具有相同的行为并共享相同的工具,因此无需定义两种不同的方法来实现相同的结果。
当然,RichTextbox提供了更多选项,包括RTF

另外,我正在测试Graphics.DrawString()TextRenderer.DrawText()

这是此测试的结果,因此代码的作用更清晰。

enter image description here

警告
对于此示例,我使用ListBox,因为Control.CreateGraphics()TextBox控件未提供RichTextBox事件。对于真实世界的应用程序,您应创建一个源自Paint()TextBox的自定义控件,并覆盖RichTextBox方法

1)突出显示多行TextBox控件中的所有 t

TextRenderer-> DrawText的():

OnPaint()

使用//Define some useful flags for TextRenderer TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.NoPadding | TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl; //The char to look for char TheChar = 't'; //Find all 't' chars indexes in the text List<int> TheIndexList = textBox1.Text.Select((chr, idx) => chr == TheChar ? idx : -1) .Where(idx => idx != -1).ToList(); //Or with Regex - same thing, pick the one you like best List<int> TheIndexList = Regex.Matches(textBox1.Text, TheChar.ToString()) .Cast<Match>() .Select(chr => chr.Index).ToList(); //Using .GetPositionFromCharIndex(), define the Point [p] where the highlighted text is drawn if (TheIndexList.Count > 0) { foreach (int Position in TheIndexList) { Point p = textBox1.GetPositionFromCharIndex(Position); using (Graphics g = textBox1.CreateGraphics()) TextRenderer.DrawText(g, TheChar.ToString(), textBox1.Font, p, textBox1.ForeColor, Color.LightGreen, flags); } } Graphics.FillRectangle()的相同操作:

Graphics.DrawString()
  

行为没有显着差异:if (TheIndexList.Count > 0) { using (Graphics g = textBox1.CreateGraphics()) { foreach (int Position in TheIndexList) { PointF pF = textBox1.GetPositionFromCharIndex(Position); SizeF sF = g.MeasureString(TheChar.ToString(), textBox1.Font, 0, StringFormat.GenericTypographic); g.FillRectangle(Brushes.LightGreen, new RectangleF(pF, sF)); using (SolidBrush brush = new SolidBrush(textBox1.ForeColor)) { g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; g.DrawString(TheChar.ToString(), textBox1.Font, brush, pF, StringFormat.GenericTypographic); } } } }   并且TextRenderer.DrawText()在这里完成同样的事情   将Application.SetCompatibleTextRenderingDefault()设为Graphics.DrawString()或   true似乎没有任何影响(至少在目前的情况下)。


2)在TextBox控件和多行RichTextbox控件中突出显示一些字符串模式(&#34; Words&#34;)。

仅使用false,因为行为没有区别。

  

我只是让TextRenderer找到第一次出现的。{1}}   字符串,但之前使用的相同搜索模式可以占据它的位置。正则表达式更好。

IndexOf()


3)突出显示ListBox控件的所有string[] TheStrings = {"for", "s"}; foreach (string pattern in TheStrings) { Point p = TextBox2.GetPositionFromCharIndex(TextBox2.Text.IndexOf(pattern)); TextRenderer.DrawText(TextBox2.CreateGraphics(), pattern, TextBox2.Font, p, TextBox2.ForeColor, Color.LightSkyBlue, flags); } TheStrings = new string []{"m", "more"}; foreach (string pattern in TheStrings) { Point p = richTextBox1.GetPositionFromCharIndex(richTextBox1.Text.IndexOf(pattern)); using (Graphics g = richTextBox1.CreateGraphics()) TextRenderer.DrawText(g, pattern, richTextBox1.Font, p, richTextBox1.ForeColor, Color.LightSteelBlue, flags); } 中的所有 s (当然它可以是任何其他字符串:)

ListItems设置为ListBox.DrawMode并且即时更改&#34;&#34;到Normal评估OwnerDrawVariableTextRenderer在此处的行为是否不同。

  

存在一个小差异:相对于左侧的不同偏移   与标准实现相比,ListBox的边距。   带有Graphics的TextRenderer渲染2像素   离开(没有国旗的对面)。图形渲染1像素   是的。
当然如果在设计模式中设置TextFormatFlags.NoPadding,   这不会被注意到。

OwnerDrawVariable
  

以下代码的工作原理:
  1)获取string HighLightString = "s"; int GraphicsPaddingOffset = 1; int TextRendererPaddingOffset = 2; private void button1_Click(object sender, EventArgs e) { listBox1.DrawMode = DrawMode.OwnerDrawVariable; } 文本中出现模式(ListItem)的所有位置   2)使用模式的位置和长度定义CharacterRange结构数组   3)使用StringFormat为所有string HighLightString结构填充.SetMeasurableCharacterRanges()   4)使用Graphics.MeasureCharacterRanges()通过初始化的CharacterRange定义一个区域数组   5)使用Region.GetBounds()定义一个大小的矩形数组   6)使用Graphics.FillRectangles()
使用高亮颜色填充所有矩形   7)绘制StringFormat文本   

ListItem实施:

TextRenderer.DrawText()


private void listBox1_DrawItem(object sender, DrawItemEventArgs e) { e.DrawBackground(); TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.NoPadding | TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl; Rectangle bounds = new Rectangle(e.Bounds.X + TextRendererPaddingOffset, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); string ItemString = listBox1.GetItemText(listBox1.Items[e.Index]); List<int> TheIndexList = Regex.Matches(ItemString, HighLightString) .Cast<Match>() .Select(s => s.Index).ToList(); if (TheIndexList.Count > 0) { CharacterRange[] CharRanges = new CharacterRange[TheIndexList.Count]; for (int CharX = 0; CharX < TheIndexList.Count; CharX++) CharRanges[CharX] = new CharacterRange(TheIndexList[CharX], HighLightString.Length); StringFormat format = new StringFormat(StringFormat.GenericDefault); format.SetMeasurableCharacterRanges(CharRanges); Region[] regions = e.Graphics.MeasureCharacterRanges(ItemString, e.Font, e.Bounds, format); RectangleF[] rectsF = new RectangleF[regions.Length]; for (int RFx = 0; RFx < regions.Length; RFx++) rectsF[RFx] = regions[RFx].GetBounds(e.Graphics); e.Graphics.FillRectangles(Brushes.LightGreen, rectsF); } TextRenderer.DrawText(e.Graphics, ItemString, e.Font, bounds, e.ForeColor, flags); } 实施

Graphics.DrawString()
  

注意:
根据private void listBox1_DrawItem(object sender, DrawItemEventArgs e) { e.DrawBackground(); Rectangle bounds = new Rectangle(e.Bounds.X - GraphicsPaddingOffset, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); string ItemString = listBox1.GetItemText(listBox1.Items[e.Index]); List<int> TheIndexList = Regex.Matches(ItemString, HighLightString) .Cast<Match>() .Select(s => s.Index).ToList(); StringFormat format = new StringFormat(StringFormat.GenericDefault); if (TheIndexList.Count > 0) { CharacterRange[] CharRanges = new CharacterRange[TheIndexList.Count]; for (int CharX = 0; CharX < TheIndexList.Count; CharX++) CharRanges[CharX] = new CharacterRange(TheIndexList[CharX], HighLightString.Length); format.SetMeasurableCharacterRanges(CharRanges); Region[] regions = e.Graphics.MeasureCharacterRanges(ItemString, e.Font, e.Bounds, format); RectangleF[] rectsF = new RectangleF[regions.Length]; for (int RFx = 0; RFx < regions.Length; RFx++) rectsF[RFx] = regions[RFx].GetBounds(e.Graphics); e.Graphics.FillRectangles(Brushes.LightGreen, rectsF); } using (SolidBrush brush = new SolidBrush(e.ForeColor)) e.Graphics.DrawString(ItemString, e.Font, brush, bounds, format); } ,可能需要   订阅ListBox.DrawMode个事件或设置ListBox.MeasureItem()   财产到正确值。

.ItemHeight