Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Out-of-the-box flat borderless button

I'm looking for an out-of-the-box way of configuring a flat borderless button. So that I can add a button from palette and configure it in design-time, without runtime overrides. I can use DevExpress components, however I would like to avoid LookAndFeel overrides or creating a custom theme for that.

The problem is that some controls allow to edit properties, but miss others.

Here's what I have tried:

Component      TabStop    FocusRect     Text V.Align    Borderless    Color
----------------------------------------------------------------------------
TButton        V          V             V               -             -
TSpeedButton   V          V             V               -             -
TLabel         -          -             V               V             V
TPanel         V          -             V               V             V
TStaticText    V          -             -               V             V
TcxButton      V          V             V               -             V
TcxLabel       -          -             V               V             V
----------------------------------------------------------------------------
* Text V.Align - vertical text alignment to center
* Borderless - no borders in default/unfocused state
** Color - ability to set face color

Another approach could be to override a TButton class via some OwnerDraw magic and put that unit first into every forms' uses clause?

Do you know of any alternatives that would allow to create/configure such a flat button in designtime having only standard Delphi 7 and basic DevExpress components?

EDIT: To address downvoters, who presumably think this is a bad question because it asks how to do something with existing tools without reinventing the bicycle.

  • This is not a garage project. There are half a dozen developers and build-machines, meaning that installing an updated component containing custom button each time for each one of them is a noticeable trouble overall.
  • The question is not about looking for a 3rd party component. I'm asking if there's a known way to configure existing controls to suit the need. You don't create a new control each time you need a hotlink label right?

P.S. Target OS is Windows XP and up

like image 416
Kromster Avatar asked Oct 21 '25 11:10

Kromster


1 Answers

Below is an interposer class example that modifies TButton to be of BS_OWNERDRAW style. As you noted, it can be put into a unit that is to be used after 'stdctrls'.

type
  TButton = class(stdctrls.TButton)
  protected
    procedure SetButtonStyle(ADefault: Boolean); override;
    procedure CNCtlcolorbtn(var Message: TMessage); message CN_CTLCOLORBTN;
    procedure CNDrawitem(var Message: TWMDrawItem); message CN_DRAWITEM;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  end;

...

procedure TButton.SetButtonStyle(ADefault: Boolean);
begin
  if HandleAllocated then
    Perform(BM_SETSTYLE, BS_OWNERDRAW, 1);
end;

procedure TButton.CNCtlcolorbtn(var Message: TMessage);
begin
  DWORD(Message.Result) := CreateSolidBrush($79FF);
end;

procedure TButton.CNDrawitem(var Message: TWMDrawItem);
var
  DC: HDC;
  SaveObj: HGDIOBJ;
  R: TRect;
begin
  R := ClientRect;
  DC := Message.DrawItemStruct.hDC;
  SaveObj := SelectObject(DC, Font.Handle);
  SetBkMode(DC, TRANSPARENT);
  DrawText(DC, PChar(Caption), -1, R, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
  SelectObject(DC, SaveObj);
  Message.Result := 1;
end;

procedure TButton.WMPaint(var Message: TWMPaint);
var
  DC: HDC;
  R: TRect;
begin
  inherited;
  if GetFocus = Handle then begin
    DC := GetDC(Handle);
    SelectObject(DC, GetStockObject(DC_BRUSH));
    SetDCBrushColor(DC, $FF);
    R := ClientRect;
    InflateRect(R, -2, -2);
    FrameRect(DC, R, DC_BRUSH);
    ReleaseDC(Handle, DC);
  end;
end;

Looks on W7 like this:

enter image description here

like image 51
Sertac Akyuz Avatar answered Oct 23 '25 07:10

Sertac Akyuz