我需要使用fill rect突出显示控件中的特定字符。
我可以通过使用下面的Graphics.MeasureString()
方法来获取文本的位置,
var size = g.MeasureString(tempSearchText, style.Font, 0, StringFormat.GenericTypographic);
如果文本被包装,那么我无法找到角色的确切界限来突出显示文本。
我需要在包装的文本中获取给定字符的确切界限。提供您的建议以实现此方案。
答案 0 :(得分:4)
没有明确说明要针对哪些控件,因此我测试了3种不同的控件:
sendToDevice(tokens, patchedPayload, options)
,TextBox
和RichTextbox
。
TextBox和RichTextbox具有相同的行为并共享相同的工具,因此无需定义两种不同的方法来实现相同的结果。
当然,RichTextbox提供了更多选项,包括RTF。
另外,我正在测试Graphics.DrawString()
和TextRenderer.DrawText()
。
这是此测试的结果,因此代码的作用更清晰。
警告强>:
对于此示例,我使用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
评估OwnerDrawVariable
和TextRenderer
在此处的行为是否不同。
存在一个小差异:相对于左侧的不同偏移 与标准实现相比,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