首页 > 解决方案 > 颜色 Listbox.Item[N] 其中 N 由代码生成

问题描述

我有一个列表框。我使用以下文件填充它:

IF Opendialog1.Execute then
   BEGIN
      Listbox1.Items.LoadfromFile(OpenDialog1.FileName);
   END;

加载的文件包含数字,并且仅包含数字(我假设)。是100 pct。当然,我现在开始扫描:(伪代码 :)

for N := 0 til Listbox1.Items.Count -1 DO
   BEGIN
      NUM := ScanForNotNumberInListbox1Item(Listbox1.Items[N]);
      // 
      // returns NUM = -1 if non digit is met..
      //    
      IF NUM <> 0 then      
         begin
            LISTBOX1.Items[N].BackGroundColor := RED;
            Exit;  (* or terminate *)
         END;
  END;  

我知道我必须使用 LIstbox1.DrawItem (); 并尝试了 Stack Exchange 中显示的示例,但似乎没有一个使用的示例是代码生成的。

那么我该怎么做呢?

克里斯

标签: delphi

解决方案


介绍

您可以将有关每个列表项的附加信息存储在其关联的“对象”中。这可以是一个(指向一个)真实对象的指针,或者您可以使用这个指针大小的整数来编码您想要的任何简单信息。

举个简单的例子,让我们将项目的背景颜色放在这个字段 ( uses Math) 中:

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin

  ListBox1.Items.BeginUpdate;
  try
    ListBox1.Clear;
    for i := 1 to 100 do
      ListBox1.Items.AddObject(i.ToString, TObject(IfThen(Odd(i), clSkyBlue, clMoneyGreen)));
  finally
    ListBox1.Items.EndUpdate;
  end;

end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
  Canvas: TCanvas;
  S: string;
begin
  ListBox := Control as TListBox;
  Canvas := ListBox.Canvas;

  Canvas.Brush.Color := TColor(ListBox.Items.Objects[Index]);
  Canvas.FillRect(Rect);
  S := ListBox.Items[Index];
  Canvas.TextRect(Rect, S, [tfSingleLine, tfVerticalCenter]);
end;

不要忘记将列表框的Style属性设置为lbOwnerDrawFixed(比如说)。

带有交替行颜色的列表框的表单的屏幕截图。

一种更“高级”的方法是将实际对象与每个项目相关联:

type
  TItemFormat = class
    BackgroundColor: TColor;
    TextColor: TColor;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  ItemFormat: TItemFormat;
begin

  ListBox1.Items.BeginUpdate;
  try
    ListBox1.Clear;
    for i := 1 to 100 do
    begin
      ItemFormat := TItemFormat.Create;
      ItemFormat.BackgroundColor := IfThen(Odd(i), clSkyBlue, clMoneyGreen);
      ItemFormat.TextColor := IfThen(Odd(i), clNavy, clGreen);
      ListBox1.Items.AddObject(i.ToString, ItemFormat);
    end;
  finally
    ListBox1.Items.EndUpdate;
  end;

end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
  Canvas: TCanvas;
  ItemFormat: TItemFormat;
  S: string;
begin
  ListBox := Control as TListBox;
  Canvas := ListBox.Canvas;
  ItemFormat := ListBox.Items.Objects[Index] as TItemFormat;

  Canvas.Brush.Color := ItemFormat.BackgroundColor;
  Canvas.FillRect(Rect);
  S := ListBox.Items[Index];
  Canvas.Font.Color := ItemFormat.TextColor;
  Canvas.TextRect(Rect, S, [tfSingleLine, tfVerticalCenter]);
end;

带有交替行颜色的列表框的表单屏幕截图; 在此图像中,文本颜色也交替出现。

(在这种情况下,您拥有这些对象,因此您有责任在不再需要它们时释放它们。)

将一切付诸行动

在您的特定情况下,我会尝试类似

procedure TForm1.Button1Click(Sender: TObject);
var
  i, dummy, FirstInvalidIndex: Integer;
begin

  with TOpenDialog.Create(Self) do
    try
      Filter := 'Text files (*.txt)|*.txt';
      Options := [ofPathMustExist, ofFileMustExist];
      if Execute then
        ListBox1.Items.LoadFromFile(FileName);
    finally
      Free;
    end;

  FirstInvalidIndex := -1;
  ListBox1.Items.BeginUpdate;
  try
    for i := 0 to ListBox1.Count - 1 do
      if not TryStrToInt(ListBox1.Items[i], dummy) then
      begin
        ListBox1.Items.Objects[i] := TObject(1);
        if FirstInvalidIndex = -1 then
          FirstInvalidIndex := i;
      end;
  finally
    ListBox1.Items.EndUpdate;
  end;

  if FirstInvalidIndex <> -1 then
  begin
    ListBox1.ItemIndex := FirstInvalidIndex;
    MessageBox(Handle, 'An invalid row was found.', PChar(Caption), MB_ICONERROR);
  end;

end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
  Canvas: TCanvas;
  S: string;
begin
  ListBox := Control as TListBox;
  Canvas := ListBox.Canvas;

  Canvas.Font.Assign(ListBox.Font);

  if odSelected in State then
  begin
    Canvas.Brush.Color := clHighlight;
    Canvas.Font.Color := clHighlightText;
  end
  else
  begin
    Canvas.Brush.Color := clWindow;
    Canvas.Font.Color := clWindowText;
  end;

  if ListBox.Items.Objects[Index] = TObject(1) then
  begin
    Canvas.Font.Color := clRed;
    Canvas.Font.Style := [fsBold, fsStrikeOut]
  end;

  Canvas.FillRect(Rect);
  S := ListBox.Items[Index];
  Canvas.TextRect(Rect, S, [tfSingleLine, tfVerticalCenter]);

end;

具有包含数字和偶尔的非数字行的列表框的表单。 非数字行以红色突出显示并删除。

细则:请注意,上面的代码片段只是用于演示基本方法的简单示例。在实际应用中,您需要更加注意细节。例如,如果背景颜色是系统颜色,则不能使用硬编码的红色文本颜色(因为该颜色很可能也是红色!)。

另外,如果文本文件是空的会发生什么(试试看!)?


推荐阅读