Search code examples
delphibuttondevexpressdelphi-7vcl

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


Solution

  • 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