This was the draft for another article published June 1997 in Visual Developer magazine as hax # 257.

Have you seen those fly-by buttons in products like Microsoft’s Internet Explorer where they do not become active until the mouse cursor passes over them? Using Delphi’s TSpeedButton as a base, we can simply and quickly construct a work-alike button.

There are two tricks that really pull our explorer style buttons together quickly. The first one is found by looking down the object hierarchy of TSpeedButton, beyond its base of TGraphicControl, and down into TControl where you find two useful events. One tells you when the mouse passes onto your control, and the other when it leaves. These are CM_MOUSEENTER and CM_MOUSELEAVE.

The second trick is that the paint method for TSpeedButton already displays nicely grayed out text and graphics when the button is disabled. By capturing the CM_MOUSEENTER and CM_MOUSELEAVE events, you can bring the button to life, enabling it as the mouse passes over, and disabling it as the mouse leaves. We gray out the button initially in the Create method by setting Enable to False. As an added bonus, we use the Create method to make the button a little larger since speed buttons are so tiny by default.

If you have the VCL source code, you could just copy out the Paint method and modify it to your whims. Instead we will let the button draw out normally and paint our changes over top. Our Paint method flattens out the button by drawing new lines over the TSpeedButton’s existing 3D lines. The line color is set to the same color, clBtnFace, as the speed button background. When the button is enabled, our Paint method draws a focus box around the button, showing it as active. The focus box is inset by 1 pixel around the button since you normally overlap speed buttons slightly.

One small ‘unfeature’ caused by taking over the normal Enable property is that there is no way to completely disable buttons anymore. This is remedied by adding a new property called Disable. Three extra lines of code, and all it does is prevent the button from being enabled as the mouse passes over. Way too simple?

Listing 1: PGRID.PAS

unit Xplorbtn;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, Buttons;

type
  TExplorerButton = class(TSpeedButton)
  private
    FDisabled: boolean;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Disable: boolean read FDisabled write FDisabled default FALSE;
  end;

procedure Register;

implementation

constructor TExplorerButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  SetBounds(0, 0, 33, 33);
  enabled:=false;
end;

procedure TExplorerButton.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  if not FDisabled then enabled:=true;
end;

procedure TExplorerButton.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  enabled:=false;
end;

procedure TExplorerButton.Paint;
begin
     inherited paint;
     with Canvas do begin
     { Paint over the 3D rectangle }
     Font.Color := clBtnFace;
     Pen.Color := clBtnFace;
     Pen.width:=3;
     MoveTo( 0, 0); LineTo( 0, Height-2); LineTo( Width-2, Height-2); LineTo( Width-2, 0); LineTo( 0, 0);
     { Draw a box around active selection. Indent by 1 pixel since speedbuttons tend to be overlapped in design. }
     if enabled or ( csDesigning in ComponentState ) then begin
       Font.Color := clWindowText;
       Pen.Color := clWindowText;
       Pen.width:=1;
       MoveTo( 1, 1); LineTo( 1, Height-2); LineTo( Width-2, Height-2); LineTo( Width-2, 1); LineTo( 1, 1);
       end
     end;
end;

procedure Register;
begin
  RegisterComponents('Samples', [TExplorerButton]);
end;

end.

Delphi - Explorer-Style Fly-By Buttons By Brad Trupp © 1997