Adh*_*dhi 4 .net c# gdi+ highlight winforms
我需要使用填充矩形突出显示控件中的特定字符。我可以使用Graphics.MeasureString()下面的方法获取文本未换行时的位置,
var size = g.MeasureString(tempSearchText, style.Font, 0, StringFormat.GenericTypographic);
Run Code Online (Sandbox Code Playgroud)
如果文本被换行,那么我无法找到字符的确切边界来突出显示文本。
我需要在被包装的文本中获得给定字符的确切边界。提供您的建议以实现此场景。
没有明确指定要针对哪些控件,所以我正在测试 3 个不同的:
TextBox、RichTextbox和ListBox。
TextBox 和 RichTextbox 具有相同的行为并共享相同的工具,因此无需定义两种不同的方法来实现相同的结果。
当然 RichTextbox 提供了更多选项,包括RTF。
另外,我正在测试Graphics.DrawString()和TextRenderer.DrawText()。
这是本次测试的结果,因此代码的作用更加清晰。
警告:
对于本示例,我使用的是Control.CreateGraphics(),因为TextBox和RichTextBox控件不提供Paint()事件。对于真实世界的应用程序,您应该创建一个派生自TextBoxor RichTextBox、覆盖WndPrc和 handle的自定义控件WM_PAINT。
1)突出显示多行 TextBox 控件中的所有t。
TextRenderer->DrawText():
//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 prefer
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);
}
}
Run Code Online (Sandbox Code Playgroud)
使用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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
有行为没有显着的区别:
TextRenderer.DrawText()和Graphics.DrawString()这里做同样的事情。
设置Application.SetCompatibleTextRenderingDefault()为true或false似乎没有任何影响(至少在当前上下文中)。
2)在 TextBox 控件和多行 RichTextbox 控件中突出显示一些字符串模式(“Words”)。
TextRenderer仅使用,因为在行为上没有区别。
我只是让
IndexOf()找到第一次出现的字符串,但之前使用的相同搜索模式可以取而代之。正则表达式效果更好。
string[] TheStrings = {"for", "s"};
foreach (string pattern in TheStrings)
{
Point p = TextBox2.GetPositionFromCharIndex(TextBox2.Text.IndexOf(pattern));
using (var g = TextBox2.CreateGraphics()) {
TextRenderer.DrawText(g, 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);
}
Run Code Online (Sandbox Code Playgroud)
3)高亮显示所有小号中的所有ListItems列表框控制(当然也可以是任何其他字符串的:)
该ListBox.DrawMode设置为Normal,改变“对飞”,以OwnerDrawVariable评估是否TextRenderer和Graphics不同的表现在这里。
有一个小的区别:与标准实现相比,相对于 ListBox 的左边距有不同的偏移量。TextRenderer,
TextFormatFlags.NoPadding向左渲染 2 个像素(相反,没有标志)。图形向右渲染 1 个像素。
当然如果OwnerDrawVariable是在设计模式下设置,这个就不会被注意到了。
string HighLightString = "s";
int GraphicsPaddingOffset = 1;
int TextRendererPaddingOffset = 2;
private void button1_Click(object sender, EventArgs e)
{
listBox1.DrawMode = DrawMode.OwnerDrawVariable;
}
Run Code Online (Sandbox Code Playgroud)
以下代码的工作原理:
- 获取
ListItem文本中string HighLightString出现模式 ( ) 的所有位置。CharacterRange使用模式的位置和长度定义结构数组。StringFormat使用所有CharacterRange结构填充 a.SetMeasurableCharacterRanges()- 使用
Graphics.MeasureCharacterRanges()传递初始化的StringFormat.- 定义大小的矩形数组
Region.GetBounds()- 使用高亮颜色填充所有矩形
Graphics.FillRectangles()- 绘制
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);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
注意:
根据ListBox.DrawMode,可能需要订阅ListBox.MeasureItem()事件或将.ItemHeight属性设置为正确的值。
private void listBox1_MeasureItem(object sender, MeasureItemEventArgs e)
{
e.ItemHeight = listBox1.Font.Height;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
552 次 |
| 最近记录: |