Search code examples
delphivcl

How to make a ListBox item a given color?


I have a number of files in a directory, where each file has two lines, line 1 is the string that I want to put into my ListBox, and line 2 is the background color that I want that ListBox item to have (represented as an 8-digit hex value).

The contents of each file looks like this:

string
14603481

This is my code so far:

for i := 0 to PathList.Count - 1 do
begin
  FileLines := TStringList.Create;
  try   
    FileLines.LoadFromFile(PathList.Strings[i]);
    s := FileLines[0]; { Loads string to add to ListBox1 }
    RGBColor := FileLines[1];
  finally
    FileLines.Free;
  end;
ListBox1.Items.AddObject(s, TObject(RGBColor)); { This code doesn't work, but hopefully you get what I'm }
end;                                            { trying to do                                           }

All other examples that do anything similar to this declare the color in the DrawItem procedure, but I need to set the color from within this for loop, since each entry will have a unique color.

How do I set the color of each item uniquely from within this loop?


Solution

  • The VCL's TListBox does not natively support any kind of per-item coloring. The TListBox.Font and TListBox.Color properties apply to all items equally.

    To do what you are asking for, you will have to set the TListBox.Style property to lbOwnerDrawFixed and then use the TListBox.OnDrawItem event to custom-draw the items manually however you want, eg:

    var
      ...
      s: string;
      RGBColor: Integer;
    begin
      ...
      for i := 0 to PathList.Count - 1 do
      begin
        FileLines := TStringList.Create;
        try   
          FileLines.LoadFromFile(PathList[i]);
          s := FileLines[0];
          RGBColor := StrToInt(FileLines[1]);
        finally
          FileLines.Free;
        end;
        ListBox1.Items.AddObject(s, TObject(RGBColor));
      end;
      ...
    end;
    
    ...
    
    procedure TMyForm.ListBox1DrawItem(Control: TWinControl;
      Index: Integer; const Rect: TRect; State: TOwnerDrawState);
    var
      LB: TListBox;
    begin
      LB := TListBox(Control);
    
      if odSelected in State then
      begin
        LB.Canvas.Brush.Color := clHighlight;
        LB.Canvas.Font.Color := clHighlightText;
      end else
      begin
        LB.Canvas.Brush.Color := TColor(Integer(LB.Items.Objects[Index]));
        LB.Canvas.Font.Color := LB.Font.Color;
      end;
    
      LB.Canvas.FillRect(Rect);
      LB.Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top + 2, LB.Items[Index]);
    
      if (odFocused in State) and not (odNoFocusRect in State) then
        LB.Canvas.DrawFocusRect(Rect);
    end;