I've changed my form to a borderless form, I just changed the BorderStyle
property to bsNone
, but now my application loses the windows anchor and some commands like
WIN + ↑ (Align the form Client)
WIN + ↓ (Minimize the form)
WIN + →(Align the form Right)
WIN + ←(Align the form Left)
I've tried to set BorderStyle: bsSizeable
and use the below code inside of the FormCreate
, but this does not worked:
procedure TfrmBase.FormCreate(Sender: TObject);
begin
SetWindowLong(Handle
,GWL_STYLE
,GetWindowLong(Handle, GWL_STYLE)
AND (NOT WS_CAPTION)
AND (NOT WS_THICKFRAME)
);
Refresh;
FormColor := oLauncher.oCor;
end;
This results:
The image above is what I want, but the Windows commands that I already have mentioned don't work
Have any way to set the BorderStyle: bsNone
and don't lose these commands?
EDITED
If I use the WS_THICKFRAME
my form returns a little top border and the windows commands works well, but I don't want that top border.
EDITED 2
I got very close to the expected result, but have a little problem yet...
I put this on my FormCreate
SetWindowLong(Handle
,GWL_STYLE
,GetWindowLong(Handle, GWL_STYLE)
AND (NOT WS_CAPTION)
);
And I create the method
private
procedure WmNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;
and then
procedure TfrmBase.WmNCCalcSize(var Msg: TWMNCCalcSize);
begin
inherited;
if Msg.CalcValidRects then
begin
InflateRect(Msg.CalcSize_Params.rgrc[0], 0, 6);
Msg.Result := 0;
end;
end;
I got this method here
Now the border has disappeared, but when my Form loses the focus, the top / bottom border is shown again....
How can I avoid this?
SOLVED
I left the border as BorderStyle: bsSizeable
, then I did it:
private
procedure WmNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;
[...]
procedure TfrmBase.WmNCCalcSize(var Msg: TWMNCCalcSize);
var
R: TRect;
begin
if not Msg.CalcValidRects then
R := PRect(Msg.CalcSize_Params)^;
inherited;
if Msg.CalcValidRects then
Msg.CalcSize_Params.rgrc0 := Msg.CalcSize_Params.rgrc1
else
PRect(Msg.CalcSize_Params)^ := R;
Msg.Result := 0;
end;
procedure TfrmBase.FormCreate(Sender: TObject);
begin
BorderStyle := bsNone;
SetWindowLong(Handle
,GWL_STYLE
,WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW
);
end;
procedure TfrmBase.FormShow(Sender: TObject);
begin
Width := (Width - 1);
end;
Solution at GitHUB
I've create a repository here
Some of the commands you refer to are system commands related to sizing of the window. That requires the thick frame, without it "WIN + right" and "WIN + left" won't work. Additionally you need the minimize box and the maximize box for the WIN + up/down commands to work.
Best is to start from scratch and include the styles you need, otherwise VCL might interfere. If there's a possibility of your form to be recreated, put styling in a CreateWnd
override.
procedure TForm1.FormCreate(Sender: TObject);
begin
BorderStyle := bsNone;
SetWindowLong(Handle, GWL_STYLE, WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW);
end;
Then there's the frame that you don't want. In an edit in the question you inflate the client rectangle to get rid of it. Don't guess the frame width/height, do it like the below.
procedure TForm1.WMNCCalcSize(var Message: TWMNCCalcSize);
var
R: TRect;
begin
if not Message.CalcValidRects then
R := PRect(Message.CalcSize_Params)^;
inherited;
if Message.CalcValidRects then
Message.CalcSize_Params.rgrc0 := Message.CalcSize_Params.rgrc1
else
PRect(Message.CalcSize_Params)^ := R;
Message.Result := 0;
end;
Reading the documentation for the message is mandatory at this point, the parameters have different meanings at different stages, etc..
The above leaves a window without any non-client area at all. The client rectangle is equal to the window rectangle. Although the caption is not visible, you can activate the system menu by pressing Alt+Space. The problem is, the system insists on drawing activation state. Now it draws a frame in the client area!!
Get rid of it by intercepting WM_NCACTIVATE
, you also need it to draw your title according to the activation status:
procedure TForm1.WMNCActivate(var Message: TWMNCActivate);
begin
if Message.Active then
// draw active caption
else
// draw incactive caption
// don't call inherited
end;
You might have to deal with some glitches, messing up with the window has consequences. In my test, the minimized form does not have an associated icon in the alt+tab dialog for instance.
Below is my test unit in full.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
procedure WMNCActivate(var Message: TWMNCActivate); message WM_NCACTIVATE;
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
BorderStyle := bsNone;
SetWindowLong(Handle, GWL_STYLE, WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW);
end;
procedure TForm1.WMNCActivate(var Message: TWMNCActivate);
begin
if Message.Active then
// draw active caption
else
// draw incactive caption
// don't call inherited
end;
procedure TForm1.WMNCCalcSize(var Message: TWMNCCalcSize);
var
R: TRect;
begin
if not Message.CalcValidRects then
R := PRect(Message.CalcSize_Params)^;
inherited;
if Message.CalcValidRects then
Message.CalcSize_Params.rgrc0 := Message.CalcSize_Params.rgrc1
else
PRect(Message.CalcSize_Params)^ := R;
Message.Result := 0;
end;
end.