【问题标题】:winform listbox drawitem change substring colorwinform listbox drawitem 更改子字符串颜色
【发布时间】:2016-08-19 22:26:59
【问题描述】:

我创建了一个 winform 自定义控件,它的文本框和列表框都共享相同的绑定源,以便可以使用文本框输入过滤列表框。

我需要覆盖 lisbox drawitem,以便将搜索文本作为子字符串的过滤项目具有不同的颜色或突出显示。 (即,)预期的黄色突出显示如下示例图像。

我做了如下

private void DrawItemHandler(object sender, DrawItemEventArgs e)
        {
            this.Invoke((MethodInvoker)delegate
            {
                e.DrawBackground();
                e.DrawFocusRectangle();

                string MyString = listBox.GetItemText(listBox.Items[e.Index]);
                string stringToFind = searchInput.Text ;

                if (!string.IsNullOrEmpty(stringToFind))
                {
                    List<int> positions = new List<int>();
                    int pos = 0;
                    while ((pos < MyString.Length) && (pos = MyString.IndexOf(stringToFind, pos, StringComparison.InvariantCultureIgnoreCase)) != -1)
                    {
                        positions.Add(pos);
                        pos += stringToFind.Length;
                    }

                    int c = 0, nLen = 0, width = 0;
                    Rectangle rect = e.Bounds;
                    rect.X = width;
                    do
                    {
                        if (positions.Contains(c))
                        {
                            //int opacity = 128;
                            e.Graphics.DrawString(MyString.Substring(c, stringToFind.Length),
                                                    e.Font,
                                //new SolidBrush(Color.FromArgb(opacity, Color.LightYellow)),
                                                    new SolidBrush(Color.LightYellow),
                                                    rect);
                            nLen = MyString.Substring(c, stringToFind.Length).Length;
                            width += nLen;
                        }
                        else
                        {
                            e.Graphics.DrawString(MyString[c].ToString(),
                            e.Font,
                            new SolidBrush(listBox.ForeColor),
                            rect);
                            nLen = MyString[c].ToString().Length;
                            width += nLen;
                        }
                        rect.X = width;
                    }
                    while ((c += nLen) < MyString.Length);
                }
                else
                {
                    e.Graphics.DrawString(MyString,
                        e.Font,
                        new SolidBrush(listBox.ForeColor),
                        e.Bounds);
                }

            });

        }

结果是项目文本被字符覆盖。

我无法识别错误部分,是在矩形边界还是在拉绳部分。除了项目背景颜色之外,如何更改项目文本中子字符串的背景。请帮我解决这个问题。

【问题讨论】:

  • 要更改子字符串的背景,我怀疑您必须先使用 FillRectangle,然后在该矩形上使用 DrawString
  • 要使用自定义背景色,请使用 TextRenderer 而不是 DrawString!您推进 rectangle.X 的方法是以字符而不是像素为单位使用字符串的长度。使用 Graphics.MeasureString(...Typographics) 找出突出显示部分的宽度。
  • 尝试了带有 FillRectangle 建议的 MeasureString,我可以看到差异,但仍然需要一些调整。谢谢大家。
  • 请注意,总会有一点松懈。使用带有两种颜色的 TextRenderer 重载来绘制字符串,至少可以将 BackColor 精确地置于文本之上或之下。
  • 感谢@TaW,我会使用 textrenderer 并会记住这一点。

标签: c# winforms listbox ondrawitem


【解决方案1】:

嗯,这项任务并不像应有的那么简单,因为 TextRenderer.MeasureTextGraphics.MeasureString 似乎都不太适合这项工作。但是使用传递矩形宽度的 Graphics.MeasureStringStringFormat.GenericTypographic 的不同重载似乎效果更好。

这是我对您的问题的尝试,希望对您有所帮助:

    private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
    {
        ListBox listBox = (ListBox)sender;
        this.Invoke((MethodInvoker)delegate
        {
            e.DrawBackground();
            e.DrawFocusRectangle();

            string MyString = listBox.GetItemText(listBox.Items[e.Index]);
            string stringToFind = searchInput.Text;


            if (!string.IsNullOrEmpty(stringToFind))
            {
                string[] strings = MyString.Split(new string[] { stringToFind }, StringSplitOptions.None);

                Rectangle rect = e.Bounds;

                for (int i=0;i<strings.Length;i++)
                {
                    string s = strings[i];
                    if (s != "")
                    {
                        int width = (int)e.Graphics.MeasureString(s, e.Font,e.Bounds.Width, StringFormat.GenericTypographic).Width;
                        rect.Width = width;
                        TextRenderer.DrawText(e.Graphics, s, e.Font, new Point(rect.X, rect.Y), listBox.ForeColor);
                        rect.X += width;
                    }

                    if (i < strings.Length - 1)
                    {
                        int width2 = (int)e.Graphics.MeasureString(stringToFind, e.Font, e.Bounds.Width, StringFormat.GenericTypographic).Width;
                        rect.Width = width2;
                        TextRenderer.DrawText(e.Graphics, stringToFind, e.Font, new Point(rect.X, rect.Y), listBox.ForeColor, Color.Yellow);
                        rect.X += width2;
                    }
                }
            }
            else
            {
                TextRenderer.DrawText(e.Graphics, MyString, e.Font, new Point(e.Bounds.X, e.Bounds.Y), listBox.ForeColor);
            }

        });


    }

【讨论】:

  • 终于!!!我一直尝试使用 DrawString,但在字符之间出现了空白,而不是在搜索模式中。您的解决方案是正确的。
猜你喜欢
  • 2012-04-13
  • 2012-12-16
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
相关资源
最近更新 更多