5
votes

I am willing to designed one Application in Delphi XE2 Borderlessly and Captionlessly by using the following code :

  BorderIcons = []
  BorderStyle = bsNone

But the problem is that there is no Menu on Right Click on the Application on Taskbar just like in the above image. Then I have tried the following codes on FormShow event, but there is also another problem. One Border is created on Left side and Left-Botton side. The codes are :

procedure TForm1.FormShow(Sender: TObject);
var
  r: TRect;
begin
  r := ClientRect;
  OffsetRect(r, 0, GetSystemMetrics(SM_CYCAPTION));
  OffsetRect(r, GetSystemMetrics(SM_CXFRAME), GetSystemMetrics(SM_CYFRAME));
  SetWindowRgn(Handle,
  CreateRectRgn(
  r.Left, r.Top,
  ClientWidth + r.Left, ClientHeight + r.Top), True);

end;

Please help me.

4
Reason that the above is a duplicate is because what is happening inside the TForm component, is that when you set the BorderStyle=bsNone, you also get (for free!) the style WS_POPUP set up. The linked duplicate actually shows a really low level way you can get your window recognized as a top-level Window, even though it is chromeless (borderless). Quote: " In short, borderless forms using BorderStyle=bsNone (dwStyle=WS_POPUP) block all Windows functionality that usually applies to main windows of applications, and all the solutions below solve part of it."Warren P

4 Answers

2
votes

You could do what David says and/or also take a look at: SetWindowRgn API.

If you use just the SetWindowRgn you don't have to remove the TForm's border, just make a rectangle that starts below it.

7
votes

The simple solution is not to remove the system menu in the first place. Note that the system menu is the official name for the menu that is missing in your app.

Make your .dfm file look like this:

BorderIcons = [biSystemMenu]
BorderStyle = bsNone

Get rid of that FormShow code–it's not needed.

OK, it looks like a stray bit of code from my experimentation was confounding me. Here's what works.

Do exactly what you originally did in your .dfm form:

BorderIcons = []
BorderStyle = bsNone

Then add back the system menu using CreateParams:

TForm1 = class(TForm)
protected
  procedure CreateParams(var Params: TCreateParams); override;
end;
...
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := Params.Style or WS_SYSMENU;
end;
5
votes
procedure TForm1.FormCreate(Sender: TObject);
begin
  BorderStyle := bsNone;
  SetWindowLong(Handle, GWL_STYLE, 
      WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN or WS_SYSMENU);
  SetWindowLong(Handle, GWL_EXSTYLE, WS_EX_CONTROLPARENT or WS_EX_APPWINDOW);
end;

You don't need the code in the OnShow handler with this solution.

The above code can be called any time (not just in OnCreate), it can be used to alter the behavior of a running form for instance (just include WS_VISIBLE to window styles if the form is already visible).

If you want the behavior to be in effect for the life time of the form, it's better to set the flags in an overriden CreateParams (where form styles are applied by VCL). This will also take possible recreation of the form into account. Don't set any form property from the OI for this solution, all of the flags are explicitly set in the code:

type
  TForm1 = class(TForm)
    ..
  protected
    procedure CreateParams(var Params: TCreateParams); override;

..

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN or WS_SYSMENU;
  Params.ExStyle := WS_EX_CONTROLPARENT or WS_EX_APPWINDOW;
end;
3
votes

You can have a window that appears not to have a caption bar, or a standard caption, by simply taking over the painting of the entire window:

Create a new empty application. Use this code for your form:

unit ncUnit1;

interface

// XE2 uses clause
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,      
  Vcl.Graphics,   Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
// If you're not using XE2 take out the prefixes (WinApi, Vcl, System, etc)

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  protected
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
    procedure SolidColorNcPaint(solidColor,frameColor:TColor);
    procedure Resizing(State: TWindowState); override;


  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.WMNCPaint(var Message: TWMNCPaint);
begin
  SolidColorNcPaint(clBtnFace,clBtnFace);
end;

procedure TForm1.Resizing(State: TWindowState);
begin
  inherited;
  PostMessage(Self.Handle,WM_NCPAINT,0,0); {force initial paint}
end;

procedure TForm1.SolidColorNcPaint(solidColor,frameColor:TColor);
var
 aBorder:Integer;
 ahdc : HDC;
begin
 aBorder := GetSystemMetrics(SM_CYSIZEFRAME);
 canvas.Lock;
 ahdc := GetWindowDC(Handle);
 canvas.Handle := ahdc;
 ExcludeClipRect(canvas.Handle, aBorder, 0, Width-aBorder, Height - aBorder) ;
 Canvas.Brush.Style := bsSolid;
 Canvas.Brush.Color := frameColor;
 Canvas.Pen.Color := solidColor;
 Canvas.Rectangle( 0,0, Width,Height);
 ReleaseDC(Self.Handle, ahdc);
 canvas.Handle := 0;
 canvas.Unlock;
end;


end.

What you see above is only enough code to redraw a solid color over the non-client area of the window, not to remove it completely. Depending on the style of custom window you want, you should render whatever you want on the form. If you don't want a Close button then remove the close button, and if you do not want the resizing behaviour, remove the resizing behaviour. If you set the FormStyle=fsDialog plus the above code, you would get a window that has a complete custom drawn title area (which you can put whatever you want into). If you actually don't want the title area to exist at all, you can modify the above code to achieve that too.