2016-05-03 5 views
0

Я пытаюсь создать пользовательский элемент управления ListBox в WinForms.Graphics.MeasureString() - Поиск относительных координат X, Y

Я подклассифицировал его, установил DrawMode.OwnerDrawFixed, и я перешагнул OnDrawItem. Я создал собственный класс ColoredListBoxItem, который имеет дополнительные свойства для устранения выделения.

Все это в порядке. Моя проблема заключается в том, что эта функция должна выделять слова в тексте элемента списка.

Здесь, насколько я понял, это не работает, потому что координата X выделения остается постоянной и не соответствует фактической координате X текста.

Как я могу получить значение Point (или Rectangle) для использования с DrawText, которое будет накладывать выделенный текст? Я пробовал сделать математику с границами исходного текста Rectangle против выделения Rectangle, но он не работает должным образом.

protected override void OnDrawItem(DrawItemEventArgs e) { 

    ColoredListBoxItem item = this.Items[e.Index] as ColoredListBoxItem; 

    e.DrawBackground(); 
    e.DrawFocusRectangle(); 

    Rectangle fullMessageRect = e.Bounds; 

    // Draw the original, full text 
    TextRenderer.DrawText(e.Graphics, item.Message, e.Font, 
      new Point(fullMessageRect.X, fullMessageRect.Y), 
      this.ForeColor); 

    // Check if we have any text to be highlighted 
    if (SomethingToHighlight(item)) { 

     // Find the text to highlight, and get its area 
     SizeF highlightedAreaSize = 
       e.Graphics.MeasureString(item.TextToHightlight, e.Font); 

     PointF highlightAreaPoint = highlightedAreaSize.ToPointF(); 

     Point point = new Point(Convert.ToInt32(highlightAreaPoint.X), 
      Convert.ToInt32(fullMessageRect.Y)); 

     TextRenderer.DrawText(e.Graphics, item.TextToHightlight, e.Font, 
      point, this.ForeColor, item.HighlightColor); 

    } 

} 

Вот что я вижу в демо-приложение, где выход только показывает работа делается, и я стараюсь, чтобы выделить одно конкретное слово .. в этом случае «высота».

Sample debugging output

Не обращайте внимание на фактический выпуск продукции, это куча ерунды, чтобы я мог увидеть, как другая часть системы регулирования PictureBox изображений на лета.

Линии, которые, по его мнению, должны быть подсвечены, отображаются дважды, один раз в исходном формате, а затем снова с использованием выделенного выделения. Обратите внимание на то, как выделенная часть верна в Y координат, но не меняется в X.

Вот что я вижу в окне Watch, когда я поставил точку останова перед записью выделенного текста:

Watch window

Очевидно, что мне не нужна переменная highlightAreaPoint, потому что это то же самое, что и у highlightedAreaSize.

Возможно, здесь есть что-то очевидное, но я устал возиться с ним в этот момент!

+0

Похоже, вы измеряете строку на hightlight, а затем берете эту ширину и начинаете выделение оттуда, не принимая во внимание, где это слово действительно начинается в предложении? Вам нужно сделать строку измерения всех слов перед ней, чтобы узнать, где начинается подсвеченное слово, а затем вы можете выписать выделенное слово. – MrApnea

+0

@FSDaniel Yep. Я получаю общую идею. Но каковы изменения кода, требуемые здесь для получения правильной области оверлея? В этом тестовом случае я имею дело только с подсветкой одного найденного слова, но в конечном итоге мне нужно получить все из них. Что нужно изменить с помощью того, что у меня есть сейчас, чтобы он знал координаты X, Y верхнего левого угла, чтобы поместить нарисованный текст? Я пропустил API здесь? Я «измеряю строку всех слов». Это сохраняется в переменной 'fullMessageRect'. – Patrick

ответ

1

Я чувствую вашу боль, как я был там раньше. На самом деле, я хотел создать собственное текстовое поле, не наследующее от элемента управления Microsoft.Textbox, и когда я исследовал он-лайн, я, как правило, не хотел изучать 1000 причин, почему нельзя изобретать велосипед и почему это так сложно сделать с нуля. Подчеркивание текста выбора было одной из главных проблем среди других, таких как право налево, позиционирование каретки, нефиксированные шрифты и т. Д. Но я решил лететь против ветра, потому что у меня были причины сделать это и, наконец, получил то, что я хотел , Поскольку мой код выбора текста был для TextBox, мне пришлось изменить его в соответствии с вашими требованиями, поскольку вы имеете дело с ListBox.

Ниже приводится фрагмент кода:

using System; 
using System.Drawing; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace HowToHighlightPortionOfText 
{ 
    public static class Helper 
    { 
     private static Rectangle dummy 
     { 
      get 
      { 
       return new Rectangle(0, 0, 10, 10); 
      } 
     } 
     const uint H = 0x00000000; 
     const uint V = 0x00000001; 
     const uint T = 0x00000002; 

     #region api functions 
     [DllImport("user32.dll")] 
     static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Dimension lpRect, int wFormat); 

     [DllImport("gdi32.dll")] 
     public static extern IntPtr SelectObject(this IntPtr hdc, IntPtr hObject); 

     [DllImport("gdi32.dll")] 
     public static extern int DeleteObject(this IntPtr hObject); 

     [DllImport("gdi32.dll", EntryPoint = "GdiGradientFill", ExactSpelling = true)] 
     static extern bool GradientFill(IntPtr hdc, Trivertex[] pVertex, 
      uint dwNumVertex, uint[] pMesh, uint dwNumMesh, uint dwMode); 

     [DllImport("gdi32")] 
     public static extern int SetBkMode(this IntPtr hdc, int nBkMode); 

     [DllImport("gdi32.dll")] 
     public static extern uint SetTextColor(this IntPtr hdc, int crColor); 

     [DllImport("gdi32.dll")] 
     public static extern uint SetBkColor(this IntPtr hdc, int crColor); 
     #endregion 

     #region public methods 
     //use this function to hilight portion of listbox item text 
     public static void HilightItemText(this ListBox control, int itemIndex, int startIndex, int endIndex, 
      Color highlightForeColor, Color highlightBackColorStart, Color? highlightBackColorEnd = null) 
     { 
      var container = control.GetItemRectangle(itemIndex); 
      var text = control.GetItemText(itemIndex); 

      using (Graphics g = control.CreateGraphics()) 
      { 
       g.HighlightText(control.Font, text, container, startIndex, endIndex, 
        highlightForeColor, highlightBackColorStart, highlightBackColorEnd); 

      } 
     } 

     public static void HighlightText(this IDeviceContext dc, Font font, string text, 
      Rectangle container, int start, int end, Color highlightForeColor, Color highlightBackColorStart, 
      Color? highlightBackColorEnd, DrawTextFlags? flags = null) 
     { 
      IntPtr hdc = dc.GetHdc(); 
      IntPtr _font = SelectObject(hdc, font.ToHfont()); 

      Dimension dm = container; 
      var flag = flags.getMeasureFlag(false); 

      SetBkMode(hdc, ColorTranslator.ToWin32(Color.Transparent)); 

      //first draw whole text 
      DrawText(hdc, text, text.Length, ref dm, 0); 

      //now get the highlight rectangle which will draw the highlighted text 
      Rectangle textBound, uptoIndex; 
      var rect = hdc.rangeBound(text, container, start, end, out textBound, out uptoIndex, flags: flags); 
      dm = rect; 

      var _backColorEnd = highlightBackColorEnd ?? highlightBackColorStart; 
      hdc.Fill(rect, highlightBackColorStart, _backColorEnd, Angle.A0); 

      SetTextColor(hdc, ColorTranslator.ToWin32(highlightForeColor)); 

      if (start < 0 || start > text.Length - 1 || end < 0 || end > text.Length - 1) 
       throw new Exception("start and end value must be with in text length"); 

      var _text = text.Substring(start, end - start + 1); 
      DrawText(hdc, _text, _text.Length, ref dm, 0); 

      DeleteObject(SelectObject(hdc, _font)); 
      dc.ReleaseHdc(); 
     } 

     public static Rectangle RangeBound(this IDeviceContext dc, Font font, string text, 
      Rectangle container, int start, int end, DrawTextFlags? flags = null) 
     { 
      Rectangle textBound, uptoIndex; 
      return dc.RangeBound(font, text, container, start, end, out textBound, out uptoIndex, flags); 
     } 

     public static Rectangle GetPortionRectangleToHighlight(this ListBox control, int itemIndex, int startIndex, int endIndex) 
     { 
      var container = control.GetItemRectangle(itemIndex); 
      var text = control.GetItemText(itemIndex); 
      Rectangle rect; 

      using (Graphics g = control.CreateGraphics()) 
      { 
       rect = g.RangeBound(control.Font, text, container, startIndex, endIndex); 

      } 
      return rect; 
     } 

     public static bool Fill(this IntPtr hdc, Rectangle rc, Color c1, 
      Color c2, Angle angle) 
     { 
      return hdc.Fill(rc.X, rc.Y, rc.Right, rc.Bottom, c1, c2, angle); 
     } 

     public static bool Fill(this IntPtr hdc, int x0, int y0, int x1, int y1, Color c1, Color c2, Angle angle) 
     { 
      Trivertex[] t = new Trivertex[4] 
      { 
       new Trivertex(x0, y0, c1), 
       new Trivertex(x1, y1, c2), 
       new Trivertex(x0, y1, c1, c2), 
       new Trivertex(x1, y0, c1, c2) 
      }; 
      uint[] pMesh = new uint[] { 0, 1, 2, 0, 1, 3 }; 

      switch ((int)angle % 180) 
      { 
       case 0: 
        return GradientFill(hdc, t, 2, pMesh, 1, H); 
       case 45: 
        return GradientFill(hdc, t, 4, pMesh, 2, T); 
       case 90: 
        return GradientFill(hdc, t, 2, pMesh, 1, V); 
       case 135: 
        t[0].x = x1; 
        t[3].x = x0; 
        t[1].x = x0; 
        t[2].x = x1; 
        return GradientFill(hdc, t, 4, pMesh, 2, T); 
       default: 
        return false; 
      } 
     } 

     #endregion 

     #region get the highlight rectangle 
     static Rectangle RangeBound(this IDeviceContext dc, Font font, string text, 
      Rectangle container, int start, int end, out Rectangle textBound, out Rectangle uptoIndex, DrawTextFlags? flags = null) 
     { 
      textBound = Rectangle.Empty; 
      uptoIndex = Rectangle.Empty; 

      if (string.IsNullOrEmpty(text)) return Rectangle.Empty; 

      IntPtr hdc = dc.GetHdc(); 
      IntPtr _font = SelectObject(hdc, font.ToHfont()); 

      var rc = hdc.rangeBound(text, container, start, end, out textBound, out uptoIndex, flags: flags); 

      DeleteObject(SelectObject(hdc, _font)); 
      dc.ReleaseHdc(); 
      return rc; 
     } 

     static TextMeasurement charRectangle(this IntPtr hdc, string text, Rectangle container, 
      string wholeText = null, Point? point = null, bool adjustByPoint = false, DrawTextFlags? flags = null) 
     { 
      if (string.IsNullOrEmpty(text)) return TextMeasurement.Default; 

      TextMeasurement measurement = new TextMeasurement(); 
      Rectangle textBound; 

      wholeText = (wholeText ?? text); 

      var location = container.Location; 

      var measureWholeText = point == null; 
      measurement.UserPoint = point ?? Point.Empty; 


      textBound = hdc.textBound(wholeText, container, flags: flags); 

      var rect = textBound; 
      var p = point ?? new Point(container.Right, container.Y); 

      if (!measureWholeText) 
      { 
       if (p.X > textBound.Right) 
        p.X = textBound.Right; 
       else if (p.X < textBound.Left) 
        p.X = textBound.X; 
      } 

      var charIndex = 0; 

      var result = hdc.charRectangle(text, ref p, rect, flags, measureWholeText); 

      charIndex = Math.Max(0, result.Item2); 
      var rectangles = result.Item1; 

      measurement.Bounds = rectangles[0]; 
      measurement.TextBounds = (measureWholeText) ? rectangles[1] : textBound; 
      rectangles[1] = measurement.TextBounds; 

      if (!measureWholeText && adjustByPoint && charIndex > 0) 
      { 
       float middle = (float)measurement.Bounds.Left + 
        measurement.Bounds.Width/2; 
       if (p.X > middle - 1) 
       { 
        Rectangle r; 
        Dimension r1 = measurement.TextBounds; 

        var newresult = hdc.charBound(text, charIndex + 2, ref r1, 
         (int)flags.getMeasureFlag(false), out r); 

        if (!newresult.Equals(measurement.Bounds) && 
         newresult.X > measurement.Bounds.X) 
        { 
         charIndex++; 
         measurement.Bounds = newresult; 
        } 
       } 
      } 
      if (measurement.Bounds.Size.Width<=0) 
       measurement.Bounds = new Rectangle(measurement.Bounds.Location, new Size(2, 2)); 

      measurement.CharIndex = charIndex; 
      measurement.Char = '\0'; 
      measurement.Char = text[Math.Min(charIndex, text.Length - 1)]; 
      return measurement; 
     } 

     static Tuple<Rectangle[], int> charRectangle(this IntPtr hdc, string text, ref Point p, Rectangle rect, 
      DrawTextFlags? flags, bool measureWholeText = false) 
     { 
      int i = 0; 

      int middle = text.Length/2, start = 0; 
      bool first = true; 
      do 
      { 
       var upto = hdc.Measure(text.Substring(0, middle), null, rect, flags); 
       bool found = upto.Has(p); 
       if (!found) 
       { 
        start = middle; 
        middle += (text.Length - middle)/2; 
        first = false; 
        if (start == middle) break; 
       } 
       else break; 
      } while (middle > 1 && text.Length - middle > 1); 

      if (first) 
      { 
       return hdc.charRectangle(text.Substring(0, middle), 
        ref p, rect, flags); 
      } 
      else 
      { 
       Rectangle[] list = new Rectangle[2]; 
       for (i = start; i <= middle; i++) 
       { 
        if (hdc.Measure(text, out list, p, i + 1, rect, flags)) 
         break; 
       } 
       i = Math.Max(i, 0); 
       return new Tuple<Rectangle[], int>(list, i); 
      } 
     } 

     static Rectangle charBound(this IntPtr hdc, string text, int len, 
      ref Dimension bounds, int flag, out Rectangle whole) 
     { 
      DrawText(hdc, text, len, ref bounds, flag); 
      whole = bounds; 
      var rc = bounds; 
      if (len - 1 > 0 && len <= text.Length) 
      { 
       DrawText(hdc, text.Substring(0, len - 1), len - 1, ref rc, flag); 
       rc = Rectangle.FromLTRB(rc.Right, bounds.Top, bounds.Right, bounds.Bottom); 
      } 
      return rc; 
     } 

     static Rectangle rangeBound(this IntPtr hdc, string text, Rectangle container, int start, int end, 
      out Rectangle textBound, out Rectangle uptoIndex, DrawTextFlags? flags = null) 
     { 
      textBound = Rectangle.Empty; 
      uptoIndex = Rectangle.Empty; 

      if (string.IsNullOrEmpty(text)) return Rectangle.Empty; 

      var location = container.Location; 
      textBound = hdc.textBound(text, container, flags); 

      Dimension rect = textBound; 
      var flag = flags.getMeasureFlag(false); 

      start++; 
      var text1 = text.Substring(0, start); 
      var rc = hdc.charBound(text1, text1.Length, ref rect, (int)flag, out uptoIndex); 

      end++; 
      var text2 = text.Substring(0, end); 
      DrawText(hdc, text2, text2.Length, ref rect, (int)flag); 

      return Rectangle.FromLTRB(rc.Left, rect.Top, rect.Right, rect.Bottom); 
     } 

     static Rectangle textBound(this IntPtr hdc, string text, Rectangle container, DrawTextFlags? flags = null) 
     { 
      Rectangle rc = Rectangle.Empty; 

      if (string.IsNullOrEmpty(text)) return rc; 
      Point p = container.Location; 

      var r = hdc.Measure(text, text.Length, flags: flags); 
      return new Rectangle(p, r.Size); 
     } 


     static DrawTextFlags getMeasureFlag(this DrawTextFlags? flags, bool textboxControl = false) 
     { 
      DrawTextFlags flag = DrawTextFlags.CalculateArea; 
      if (flags != null) flag |= flags.Value; 

      flag |= DrawTextFlags.WordBreak | DrawTextFlags.NoPrefix 
       | DrawTextFlags.NoPadding | DrawTextFlags.NoClipping; 

      if (textboxControl) flag |= DrawTextFlags.TextBoxControl; 
      else flag |= DrawTextFlags.SingleLine; 
      return flag; 
     } 

     static Rectangle RangeBound(this IntPtr hdc, string text, 
      Rectangle container, int start, int end, DrawTextFlags? flags = null) 
     { 
      Rectangle textBound, uptoIndex; 
      return hdc.rangeBound(text, container, start, end, out textBound, out uptoIndex, flags); 
     } 

     static Rectangle Measure(this IntPtr hdc, string text, int? length = null, 
      Rectangle? rect = null, DrawTextFlags? flags = null) 
     { 
      if (string.IsNullOrEmpty(text)) return Rectangle.Empty; 
      Dimension bounds = rect ?? dummy; 

      var len = length ?? text.Length; 
      var flag = flags.getMeasureFlag(false); 

      var i = DrawText(hdc, text, len, ref bounds, (int)flag); 

      return bounds; 
     } 

     static bool Measure(this IntPtr hdc, string text, out Rectangle[] rectangles, Point p, 
      int? length = null, Rectangle? rect = null, DrawTextFlags? flags = null) 
     { 
      rectangles = new Rectangle[2]; 

      if (string.IsNullOrEmpty(text)) return true; 
      Dimension bounds = rect ?? dummy; 

      var len = length ?? text.Length; 
      var flag = flags.getMeasureFlag(false); 

      Rectangle rc, rc1; 
      rc1 = hdc.charBound(text, len, ref bounds, (int)flag, out rc); 
      rectangles = new Rectangle[] { rc1, rc }; 
      return (rectangles[0].Left < bounds.Left || rectangles[0].Has(p.X)); 
     } 

     static bool Has(this Rectangle rect, int x = -1, 
      int y = -1, int checkRightUpto = -1, int checkBottomUpto = -1) 
     { 
      if (x == -1 && y == -1) 
      { 
       x = 0; 
       y = 0; 
      } 
      else 
      { 
       x = x == -1 ? rect.X : x; 
       y = y == -1 ? rect.Y : y; 
      } 
      if (checkRightUpto == -1) 
      { 
       checkRightUpto = rect.Width; 
      } 
      if (checkBottomUpto == -1) 
      { 
       checkBottomUpto = rect.Height; 
      } 
      return x >= rect.Left && x <= rect.Left + 
       checkRightUpto && y >= rect.Top && 
       y <= rect.Top + checkBottomUpto; 
     } 

     static bool Has(this Rectangle rect, Point p, 
      int checkRightUpto = -1, int checkBottomUpto = -1) 
     { 
      return rect.Has(p.X, p.Y, checkRightUpto, checkBottomUpto); 
     } 
     #endregion 
    } 

    #region structs 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Dimension 
    { 
     public int Left, Top, Right, Bottom; 

     public Dimension(int left, int top, int right, int bottom) 
     { 
      this.Left = left; 
      this.Right = right; 
      this.Top = top; 
      this.Bottom = bottom; 
     } 
     public Dimension(Rectangle r) 
     { 
      this.Left = r.Left; 
      this.Top = r.Top; 
      this.Bottom = r.Bottom; 
      this.Right = r.Right; 
     } 
     public static implicit operator Rectangle(Dimension rc) 
     { 
      return Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom); 
     } 
     public static implicit operator Dimension(Rectangle rc) 
     { 
      return new Dimension(rc); 
     } 

     public static Dimension Default 
     { 
      get { return new Dimension(0, 0, 1, 1); } 
     } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct Trivertex 
    { 
     public int x; 
     public int y; 
     public ushort Red; 
     public ushort Green; 
     public ushort Blue; 
     public ushort Alpha; 

     public Trivertex(int x, int y, Color color) 
      : this(x, y, color.R, color.G, color.B, color.A) 
     { 
     } 
     public Trivertex(int x, int y, Color color, Color other) 
      : this(x, y, color.R, color.G, color.B, color.A, other) 
     { 
     } 
     public Trivertex(int x, int y, ushort red, ushort green, ushort blue, ushort alpha) 
     { 
      this.x = x; 
      this.y = y; 
      Red = (ushort)(red << 8); 
      Green = (ushort)(green << 8); 
      Blue = (ushort)(blue << 8); 
      Alpha = (ushort)(alpha << 8); 
     } 
     public Trivertex(int x, int y, ushort red, ushort green, ushort blue, ushort alpha, Color other) 
     { 
      this.x = x; 
      this.y = y; 
      Red = (ushort)((red + other.R/2) << 8); 
      Green = (ushort)((green + other.G/2) << 8); 
      Blue = (ushort)((blue + other.B/2) << 8); 
      Alpha = (ushort)((alpha + other.A/2) << 8); 
     } 

     public static ushort R(Color c) 
     { 
      return (ushort)(c.R << 8); 
     } 
     public static ushort G(Color c) 
     { 
      return (ushort)(c.G << 8); 
     } 
     public static ushort B(Color c) 
     { 
      return (ushort)(c.B << 8); 
     } 
     public static ushort R(Color c, Color c1) 
     { 
      return (ushort)(((c.R + c1.R/2)) << 8); 
     } 
     public static ushort G(Color c, Color c1) 
     { 
      return (ushort)(((c.G + c1.G/2)) << 8); 
     } 
     public static ushort B(Color c, Color c1) 
     { 
      return (ushort)(((c.B + c1.B/2)) << 8); 
     } 
    } 
    #endregion 

    #region textmeasurement interface + class 
    public interface ITextMeasurement : ICloneable 
    { 
     int CharIndex { get; set; } 
     int PreviousIndex { get; } 
     Rectangle Bounds { get; } 
     Rectangle TextBounds { get; } 
     char Char { get; } 
     Point UserPoint { get; } 

     void CopyFrom(ITextMeasurement other); 
    } 
    public class TextMeasurement : ITextMeasurement 
    { 
     Rectangle now, textBound; 

     public virtual Rectangle Bounds 
     { 
      get 
      { 
       return now; 
      } 
      set { now = value; } 
     } 
     public virtual Rectangle TextBounds 
     { 
      get 
      { 
       return textBound; ; 
      } 
      set { textBound = value; } 
     } 

     public virtual int CharIndex { get; set; } 
     public virtual int PreviousIndex { get; set; } 
     public virtual char Char { get; set; } 
     public Point UserPoint { get; set; } 

     public virtual void CopyFrom(ITextMeasurement tm) 
     { 
      PreviousIndex = tm.PreviousIndex; 
      CharIndex = tm.CharIndex; 
      Bounds = tm.Bounds; 
      Char = tm.Char; 
      TextBounds = tm.TextBounds; 
      UserPoint = tm.UserPoint; 
      if (UserPoint.IsEmpty) UserPoint = Bounds.Location; 
     } 
     public virtual object Clone() 
     { 
      var tm = new TextMeasurement(); 
      tm.CopyFrom(this); 
      return tm; 
     } 
     protected virtual void ResetBounds(Point p) 
     { 
      ResetBounds(p.X, p.Y); 
     } 
     protected virtual void ResetBounds(int? lineX = null, int? lineY = null) 
     { 
      if (lineX.HasValue) 
      { 
       now.X = lineX.Value; 
       textBound.X = lineX.Value; 
      } 
      if (lineY.HasValue) 
      { 
       now.Y = lineY.Value; 
       textBound.Y = lineY.Value; 
      } 
     } 
     protected virtual void ResetEmptyBounds(Rectangle rc) 
     { 
      now = rc; 
      textBound = rc; 
     } 
     public static TextMeasurement Default 
     { 
      get { return new TextMeasurement(); } 
     } 
    } 
    #endregion 

    #region enums 
    public enum DrawTextFlags 
    { 
     CalculateArea = 0x00000400, 
     WordBreak = 0x00000010, 
     TextBoxControl = 0x00002000, 
     Top = 0x00000000, 
     Left = 0x00000000, 
     HorizontalCenter = 0x00000001, 
     Right = 0x00000002, 
     VerticalCenter = 0x00000004, 
     Bottom = 0x00000008, 
     SingleLine = 0x00000020, 
     ExpandTabs = 0x00000040, 
     TabStop = 0x00000080, 
     NoClipping = 0x00000100, 
     ExternalLeading = 0x00000200, 
     NoPrefix = 0x00000800, 
     Internal = 0x00001000, 
     PathEllipsis = 0x00004000, 
     EndEllipsis = 0x00008000, 
     WordEllipsis = 0x00040000, 
     ModifyString = 0x00010000, 
     RightToLeft = 0x00020000, 
     NoFullWidthCharacterBreak = 0x00080000, 
     HidePrefix = 0x00100000, 
     PrefixOnly = 0x00200000, 
     NoPadding = 0x10000000, 
    } 
    public enum Angle 
    { 
     A0 = 0, 
     A45 = 45, 
     A90 = 90, 
     A135 = 135, 
     A180 = 180 
    } 
    #endregion 
} 

Пусть ваш ItemText с индексом 2, "StackOverflow замечательный сайт", и вы хотите, чтобы выделить "StackOverflow", то ваш STARTINDEX = 0 и ENDINDEX = 12.

чтобы выделить часть текста метода использования HighlightItemText:

listBox.HilightItemText(2, 0, 12, Color.Black, Color.Gold, Color.Yellow); 

чтобы получить выделенные координаты использовать метод GetPortionRectangleToHighlight, чтобы получить гр o-ordinates части текста, чтобы выделить. Обратите внимание, что вам просто нужно передать начальный и конечный индекс, а также часть текста.

так называют функцию, как:

var portionRectangle = listBox1.GetPortionRectangleToHighlight (2, 0, 12); 

Посмотрите на прилагаемом изображении, как работает доказательство концепции. enter image description here

+0

Спасибо. Я хорошо осведомлен о точке отказа от возврата в отношении таких вещей, как «право налево, позиционирование каретки, нефиксированные шрифты и т. Д.». Это, к счастью, «проще», чем это, и я бы даже не попытался это сделать, если бы мне пришлось иметь дело с этими случаями.Я попробую то, что вы предложили здесь, и сообщите об этом. – Patrick

+0

@Patrick, я отредактировал метод rangeBound, поэтому, пожалуйста, измените его соответствующим образом в конце, иначе код не будет работать, и он будет тратить ваше время. Я изменил textBound = Rectangle.Empty на textBound = hdc.textBound (текст, контейнер, флаги); –

+0

Я только что пришел сюда, чтобы прокомментировать, что я не могу использовать статический метод Rectangle rangeBound! Я изменю его, спасибо! – Patrick

0

Простой пример будет что-то вроде этого:

private string[] _sentences = { 
     "Old height on pictureOne: 766", 
     "New height on pictureOne: 900", 
     "", 
     "Forcing width on objectX" 
    }; 

    private void Form1Paint(object sender, PaintEventArgs e) { 
     int y = 10; //Start position 
     int x; 

     foreach (string s in _sentences) { 
      x = 0; //Start position 
      foreach (string word in s.Split(' ')) { 
       if (ShouldHeighlightWord(word)) { 
        e.Graphics.DrawString(word + " ", this.Font, new SolidBrush(Color.Red), x, y); 
       } 
       else { 
        e.Graphics.DrawString(word + " ", this.Font, new SolidBrush(Color.Black), x, y); 
       } 
       x += (int)e.Graphics.MeasureString(word + " ", this.Font).Width; 
      } 

      y += (int)Math.Ceiling(e.Graphics.MeasureString("I", this.Font).Height); 
     } 
    } 

    private bool ShouldHeighlightWord(string word) { 
     switch (word) { 
      case "on": 
      case "Old": 
       return true; 
      default: 
       return false; 
     } 
    } 

Этот код просто рисунок строки на пустую форму и вместо подсветки она просто меняет цвет на красный.

Но я думаю, вы понимаете, что я имею в виду. Так как у меня больше нет кода, чтобы сделать лучший пример для вас.

При проверке:

if (SomethingToHighlight(item)) { 

Это только возвращает истина/ложь я думаю, и вам нужно что-то, что возвращает все слова, которые будут выделены, но так как слово может происходить в два раза (или больше) в одном предложении вы должны также иметь возможность получить позицию в строке.Или просто произведите одно слово за раз и проверьте, следует ли выделить его или нет, а затем нарисуйте его в элементе управления.

+0

Это не сработает. Я упростил ваш пример, удалив цикл по всему предложению, поэтому он просто пытается его одним словом. В примере на первом проходе, если он найдет слово, чтобы выделить его, он будет помещать его в X, Y 0, 10 без какой-либо логики (которые являются значениями по умолчанию для первого прохода). Это сложнее, чем это. Он должен знать координаты X, Y совпадающего слова, найденного в объекте «ListItem», а затем нарисовать OVER в этой области с помощью выделения. Я просто не могу определить, как правильно разместить его в направлении X. – Patrick

+0

Поскольку вы сначала рисуете строку в правильном месте, используя fullMessageRect, вы можете просто установить ее как начальную точку для x и y? – MrApnea

+0

Моя текущая атака на это состоит в том, чтобы разделить строку, как вы предложили, определить, нужно ли выделить конкретную область, а затем нарисовать ее так или иначе. К сожалению, я не могу использовать пространство как разделитель (или что-то еще). «SomethingChangedHeight» и «(Height) были изменены», чтобы обе имели выделенную «Height». Кажется, что требуется сделать это по одному персонажу за раз. Должен быть лучший способ. – Patrick

 Смежные вопросы

  • Нет связанных вопросов^_^