9

以 Office XP 样式显示焦点/选定列表框项目的最简单和干净的方法是什么?

请参阅此示例图像以更清晰地显示该想法:

在此处输入图像描述

我想我需要将 Listbox Style 设置为lbOwnerDrawFixedorlbOwnerDrawVariable然后修改 OnDrawItem 事件?

这就是我卡住的地方,我不确定要在那里写什么代码,到目前为止我尝试过:

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  with (Control as TListBox).Canvas do
  begin
    if odSelected in State then
    begin
      Brush.Color := $00FCDDC0;
      Pen.Color   := $00FF9933;
      FillRect(Rect);
    end;

    TextOut(Rect.Left, Rect.Top, TListBox(Control).Items[Index]);
  end;
end;

我应该知道那是行不通的,我会遇到各种时髦的事情:

在此处输入图像描述

我做错了什么,更重要的是我需要改变什么才能让它工作?

谢谢。

4

2 回答 2

13

您忘记为不同状态绘制项目。您需要确定该项目当前处于什么状态并根据该状态绘制它。

您可以通过这种方式获得图片上的内容。但是,如果您启用了多选并选择了多个项目,这看起来不太好:

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  Offset: Integer;
begin
  with (Control as TListBox) do
  begin
    Canvas.Font.Color := Font.Color;
    if (odSelected in State) then
    begin
      Canvas.Pen.Color := $00FF9932;
      Canvas.Brush.Color := $00FDDDC0;
    end
    else
    begin
      Canvas.Pen.Color := Color;
      Canvas.Brush.Color := Color;
    end;
    Canvas.Rectangle(Rect);
    Canvas.Brush.Style := bsClear;
    Offset := (Rect.Bottom - Rect.Top - Canvas.TextHeight(Items[Index])) div 2;
    Canvas.TextOut(Rect.Left + Offset + 2, Rect.Top + Offset, Items[Index]);
  end;
end;

结果ItemHeight设置为 16:

在此处输入图像描述

奖金 - 连续选择:

这是一个实现连续选择的棘手解决方案。原理是像以前一样绘制项目,然后根据上一个项目和下一个项目的选择状态,用一种颜色的线覆盖项目的边框顶部和底部线。除此之外,还必须在当前项目之外渲染,因为项目选择不会自然地调用要重新绘制的相邻项目。因此,水平线画在当前项目边界上方一个像素和一个像素下方(这些线的颜色也取决于相对选择状态)。

这里比较奇怪的是使用 item 对象来存储每个 item 的选中状态。我这样做是因为在使用拖放项目选择时,该Selected属性在您释放鼠标按钮之前不会返回真实状态。幸运的是,OnDrawItem事件当然会以真实状态触发,因此作为一种解决方法,我使用了从OnDrawItem事件中存储这些状态。

重要的:

请注意,我正在使用项目对象来存储实际的选择状态,所以要小心,当您将项目对象用于其他用途时,请将此实际状态存储到布尔数组中。

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
const
  SelBackColor = $00FDDDC0;
  SelBorderColor = $00FF9932;
var
  Offset: Integer;
  ItemSelected: Boolean;
begin
  with (Control as TListBox) do
  begin
    Items.Objects[Index] := TObject((odSelected in State));    

    if (odSelected in State) then
    begin
      Canvas.Pen.Color := SelBorderColor;
      Canvas.Brush.Color := SelBackColor;
      Canvas.Rectangle(Rect);
    end
    else
    begin
      Canvas.Pen.Color := Color;
      Canvas.Brush.Color := Color;
      Canvas.Rectangle(Rect);   
    end;

    if MultiSelect then
    begin
      if (Index > 0) then
      begin
        ItemSelected := Boolean(ListBox1.Items.Objects[Index - 1]);
        if ItemSelected then
        begin
          if (odSelected in State) then
          begin
            Canvas.Pen.Color := SelBackColor;
            Canvas.MoveTo(Rect.Left + 1, Rect.Top);
            Canvas.LineTo(Rect.Right - 1, Rect.Top);
          end
          else
            Canvas.Pen.Color := SelBorderColor;
        end
        else
          Canvas.Pen.Color := Color;
        Canvas.MoveTo(Rect.Left + 1, Rect.Top - 1);
        Canvas.LineTo(Rect.Right - 1, Rect.Top - 1);
      end;

      if (Index < Items.Count - 1) then
      begin
        ItemSelected := Boolean(ListBox1.Items.Objects[Index + 1]);
        if ItemSelected then
        begin
          if (odSelected in State) then
          begin
            Canvas.Pen.Color := SelBackColor;
            Canvas.MoveTo(Rect.Left + 1, Rect.Bottom - 1);
            Canvas.LineTo(Rect.Right - 1, Rect.Bottom - 1);
          end
          else
            Canvas.Pen.Color := SelBorderColor;
        end
        else
          Canvas.Pen.Color := Color;
        Canvas.MoveTo(Rect.Left + 1, Rect.Bottom);
        Canvas.LineTo(Rect.Right - 1, Rect.Bottom);
      end;
    end;

    Offset := (Rect.Bottom - Rect.Top - Canvas.TextHeight(Items[Index])) div 2;
    Canvas.Brush.Style := bsClear;
    Canvas.Font.Color := Font.Color;
    Canvas.TextOut(Rect.Left + Offset + 2, Rect.Top + Offset, Items[Index]);
  end;
end;

结果:

在此处输入图像描述

于 2012-08-12T13:39:57.073 回答
2

您需要查看传递给函数的 State 变量的值。这会告诉您是否选择了该项目,然后您可以适当地设置画笔和笔。

于 2012-08-12T12:24:35.063 回答