【问题标题】:How to remove the dotted focus line from a TCustomListBox?如何从 TCustomListBox 中删除虚线焦点线?
【发布时间】:2025-12-17 08:40:01
【问题描述】:

我有一个TCustomListBox 派生控件,我在其中覆盖了DrawItem 过程以使其具有更好的外观和感觉。

我注意到的一件事似乎也影响了标准TListBox 是,当控件获得焦点并且没有项目时,它仍然绘制虚线焦点线。


这是一个标准,未更改的TListBox,没有项目:

当控件获得焦点(即点击)时绘制虚线


现在使用我的自定义控件,虚线仍然出现,只是不同:


如果我的自定义列表框包含项目,则不会绘制虚线:


这是自定义列表框的主要代码:

type
  TMyListBox = class(TCustomListBox)
  private
    FFillColor: TColor;
    FFrameColor: TColor;
  protected
    procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

{ TMyListBox }

constructor TMyListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FFillColor  := GetShadowColor(clMenuHighlight, 60);
  FFrameColor := GetShadowColor(clMenuHighlight, -20);

  Style := lbOwnerDrawVariable;
end;

destructor TMyListBox.Destroy;
begin
  inherited Destroy;
end;

procedure TMyListBox.DrawItem(Index: Integer; Rect: TRect;
  State: TOwnerDrawState);
var
  Offset: Integer;
begin
  inherited;

  with (Self as TMyListBox) do
  begin
    Canvas.FillRect(Rect);

    if (odSelected in State) then
    begin
      Canvas.Pen.Color := FFrameColor;
      Canvas.Brush.Color := FFillColor;
      Canvas.Rectangle(Rect);
    end
    else
    begin
      Canvas.Pen.Color := Color;
      Canvas.Brush.Color := Color;
      Canvas.Rectangle(Rect);
    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;

我还需要做什么才能从控件中删除虚线焦点线?

【问题讨论】:

  • 这是标准行为,为什么要更改它?如果您不想选择没有项目的列表框,只需禁用列表框
  • @SirRufo 我理解你的意思,但是因为我希望列表框看起来不错,所以我需要删除这些点。对于它的价值,我想有单独的项目颜色来指示列表框没有聚焦,有点像列表视图的外观(蓝色表示聚焦,灰色表示非聚焦)

标签: delphi delphi-xe


【解决方案1】:

您可以为WM_SETFOCUS 添加一个处理程序,以防止在没有项目时处理:

procedure TMyListBox.WMSetFocus(var Message: TWMSetFocus);
begin
  Message.Result := 0;
  if Count <> 0 then
    inherited;
end;

【讨论】:

  • 不初始化,它的值是多少?
  • 这是否类似于将 TabStop 设置为 False?
  • @Blobby - 不是真的,它是用于标签导航的。
  • @Blobby - 但是似乎仍然存在一个问题,当至少有一个项目但没有选择时,当框有焦点时,您仍然可以看到焦点矩形。但是,当有项目时,我们无法从 WM_SETFOCUS 返回。
  • @David - classes.pas 中的 StdWndProc 将其设置为 0。