如何为 window 自定义尺寸且边框不可调整?
How to make custom sizing for window with non-sizeable borders?
如何为 window 哪些边框本身不能调整大小实施自定义大小调整例程?
例如BorderStyle
设置为 bsToolWindow
的表单
这里是自定义表单 -class 实现了不可调整大小的边框大小和禁用指定边缘大小的可能性。它还支持双击边框以在两个矩形边界之间切换:AutoSizeRect
到在 dblclick 上移动的表单边的值和 SavedSizeRect
更改之前保存的表单边坐标的值。因此 AutoSizeRect
可以在 运行 时设置到屏幕的某个区域,让用户能够在指定区域和当前 BoundsRect 之间交换边界侧的坐标。非常方便各种调色板-windows (aka ToolWindows)。最好结合自定义 sticking/aligning.
{...}
const
crMin=-32768; {lowest value for tCursor}
{predefined variable for tRect with undefined values:}
nullRect:tRect=(Left:MaxInt;Top:MaxInt;Right:MaxInt;Bottom:MaxInt);
type
{all sides and corners of Rect including inner part (rcClient):}
TRectCorner=(rcClient,rcTopLeft,rcTop,rcTopRight,rcLeft,rcRight,rcBottomLeft,rcBottom,rcBottomRight);
{here goes the mentioned class:}
TCustomSizingForm = class(TForm)
protected
private
disSizing:tAnchors; {edges with disabled sizing}
cCorner:tRectCorner; {current corner}
cCurSaved:tCursor; {saved cursor value for sizing}
coordsSv:tRect; {saved side's coordinates}
coordsASize:tRect; {auto-sizing area for dblclicks}
aSizeAcc:byte; {auto-sizing accuracy}
{checking if current edge-side is not disabled:}
function cCornerAvailable:boolean;
{setting sizing-cursor based on the edge-side:}
procedure setCursorViaCorner(Corner:tRectCorner);
{checking if mouse on borders and setting sizing cursor:}
function checkMouseOnBorders(msg:tWmNcHitMessage):boolean;
{NcHitTes and other NC-messages handlers:}
procedure WMNCHitTest(var msg:tWmNcHitTest); message WM_NCHITTEST;
procedure BordersLButtonDown(var msg:tWmNcHitMessage); message WM_NCLBUTTONDOWN;
procedure BordersLButtonUp(var msg:tWmNcHitMessage); message WM_NCLBUTTONUP;
procedure BordersMouseMove(var msg:tWmNcHitMessage); message WM_NCMOUSEMOVE;
procedure BordersLDblClick(var msg:tWmNcHitMessage); message WM_NCLBUTTONDBLCLK;
public
{Create-override for initializing rect-values:}
constructor Create(AOwner: TComponent); override;
{calculation of edge-side from tPoint:}
function getCornerFromPoint(BoundsRect:tRect; x,y:smallInt):tRectCorner;
{properties:}
property CursorSaved:tCursor read cCurSaved write cCurSaved default crMin;
property AutoSizeRect:tRect read coordsASize write coordsASize;
property SavedSizeRect:tRect read coordsSv write coordsSv;
published
{overwriting default BorderStyle:}
property BorderStyle default bsToolWindow;
{publishing disSizing property for Object Inspector:}
property DisabledSizingEdges:tAnchors read disSizing write disSizing default [];
end;
{...}
implementation
{--- TCustomSizingForm - public section: ---}
constructor TCustomSizingForm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
SavedSizeRect:=nullRect;
AutoSizeRect:=nullRect;
end;
function TCustomSizingForm.getCornerFromPoint(BoundsRect:tRect; x,y:smallInt):tRectCorner;
var CornerSize,BorderSize:tBorderWidth;
begin
BorderSize:=4+self.BorderWidth;
CornerSize:=8+BorderSize;
with BoundsRect do
if y<Top+BorderSize then
if x<Left+CornerSize then Result:=rcTopLeft
else if x>Right-CornerSize then Result:=rcTopRight
else Result:=rcTop
else if y>Bottom-BorderSize then
if x<Left+CornerSize then Result:=rcBottomLeft
else if x>Right-CornerSize then Result:=rcBottomRight
else Result:=rcBottom
else if x<Left+BorderSize then
if y<Top+CornerSize then Result:=rcTopLeft
else if y>Bottom-CornerSize then Result:=rcBottomLeft
else Result:=rcLeft
else if x>Right-BorderSize then
if y<Top+CornerSize then Result:=rcTopRight
else if y>Bottom-CornerSize then Result:=rcBottomRight
else Result:=rcRight
else Result:=rcClient;
end;
{--- TCustomSizingForm - private section: ---}
function TCustomSizingForm.cCornerAvailable:boolean;
var ca:tAnchorKind;
begin
result:=true;
if(disSizing=[])then exit;
if(cCorner in[rcTopLeft,rcLeft,rcBottomLeft])then begin
ca:=akLeft;
end else if(cCorner in[rcTopRight,rcRight,rcBottomRight])then begin
ca:=akRight;
end else if(cCorner in[rcTopLeft,rcTop,rcTopRight])then begin
ca:=akTop;
end else ca:=akBottom;
if(ca in disSizing)then result:=false;
end;
procedure TCustomSizingForm.setCursorViaCorner(Corner:tRectCorner);
var c:tCursor;
begin
case Corner of
rcLeft,rcRight: c:=crSizeWE;
rcTop,rcBottom: c:=crSizeNS;
rcTopLeft,rcBottomRight: c:=crSizeNWSE;
rcTopRight,rcBottomLeft: c:=crSizeNESW;
else exit;
end;
if(cursorSaved=crMin)then cursorSaved:=screen.Cursor;
setCursor(screen.Cursors[c]);
end;
function TCustomSizingForm.checkMouseOnBorders(msg:tWmNcHitMessage):boolean;
begin
result:=true;
cCorner:=rcClient;
if(msg.HitTest<>HTBORDER)then exit;
cCorner:=getCornerFromPoint(self.BoundsRect,msg.XCursor,msg.YCursor);
if(cCorner=rcClient)then exit;
if(cCornerAvailable)then begin
setCursorViaCorner(cCorner);
result:=false;
end;
end;
{--- TCustomSizingForm - WinApi_message_handlers: ---}
procedure TCustomSizingForm.WMNCHitTest(var msg:tWmNcHitTest);
var hitMsg:tWmNcHitMessage;
begin
inherited;
if(msg.Result=HTNOWHERE)and(PtInRect(self.BoundsRect,point(msg.XPos,msg.YPos)))then msg.Result:=HTBORDER
else if(msg.Result<>HTBORDER)then exit;
hitMsg.HitTest:=msg.Result;
hitMsg.XCursor:=msg.XPos;
hitMsg.YCursor:=msg.YPos;
checkMouseOnBorders(hitMsg);
end;
procedure TCustomSizingForm.BordersLButtonDown(var msg:tWmNcHitMessage);
const SC_SIZELEFT=1; SC_SIZERIGHT=2; SC_SIZETOP=3; SC_SIZEBOTTOM=6;
var m:integer;
begin
inherited;
if(checkMouseOnBorders(msg))then exit;
m:=SC_SIZE;
if(cCorner in[rcTopLeft,rcLeft,rcBottomLeft])then begin
inc(m,SC_SIZELEFT);
end else if(cCorner in[rcTopRight,rcRight,rcBottomRight])then begin
inc(m,SC_SIZERIGHT);
end;
if(cCorner in[rcTopLeft,rcTop,rcTopRight])then begin
inc(m,SC_SIZETOP);
end else if(cCorner in[rcBottomLeft,rcBottom,rcBottomRight])then begin
inc(m,SC_SIZEBOTTOM);
end;
ReleaseCapture;
SendMessage(self.Handle,WM_SYSCOMMAND,m,0);
end;
procedure TCustomSizingForm.BordersLButtonUp(var msg:tWmNcHitMessage);
begin
inherited;
if(cursorSaved=crMin)then exit;
setCursor(screen.Cursors[cursorSaved]);
cursorSaved:=crMin;
end;
procedure TCustomSizingForm.BordersMouseMove(var msg:tWmNcHitMessage);
begin
inherited;
checkMouseOnBorders(msg);
end;
procedure TCustomSizingForm.BordersLDblClick(var msg:tWmNcHitMessage);
var es:tAnchors; old,new:tRect;
begin
inherited;
if(checkMouseOnBorders(msg))or(EqualRect(coordsASize,nullRect))then exit;
es:=[];
ReleaseCapture;
if(cCorner in[rcTopLeft,rcLeft,rcBottomLeft])then es:=es+[akLeft];
if(cCorner in[rcTopRight,rcRight,rcBottomRight])then es:=es+[akRight];
if(cCorner in[rcTopLeft,rcTop,rcTopRight])then es:=es+[akTop];
if(cCorner in[rcBottomLeft,rcBottom,rcBottomRight])then es:=es+[akBottom];
if(es=[])then exit;
old:=self.BoundsRect;
new:=old;
if(akLeft in es)and(coordsASize.Left<MaxInt)then begin
if(abs(old.Left-coordsASize.Left)<=aSizeAcc)then begin
new.Left:=coordsSv.Left;
end else begin
coordsSv.Left:=old.Left;
new.Left:=coordsASize.Left;
end;
end;
if(akRight in es)and(coordsASize.Right<MaxInt)then begin
if(abs(old.Right-coordsASize.Right)<=aSizeAcc)then begin
new.Right:=coordsSv.Right;
end else begin
coordsSv.Right:=old.Right;
new.Right:=coordsASize.Right;
end;
end;
if(akTop in es)and(coordsASize.Top<MaxInt)then begin
if(abs(old.Top-coordsASize.Top)<=aSizeAcc)then begin
new.Top:=coordsSv.Top;
end else begin
coordsSv.Top:=old.Top;
new.Top:=coordsASize.Top;
end;
end;
if(akBottom in es)and(coordsASize.Bottom<MaxInt)then begin
if(abs(old.Bottom-coordsASize.Bottom)<=aSizeAcc)then begin
new.Bottom:=coordsSv.Bottom;
end else begin
coordsSv.Bottom:=old.Bottom;
new.Bottom:=coordsASize.Bottom;
end;
end;
self.BoundsRect:=new;
end;
{...}
DisabledSizingEdges
属性 是一组将被关闭的边缘(例如 DisabledSizingEdges:=[akLeft,akTop];
将关闭左侧、顶部、左下角、左上角的尺寸调整-角和右上角)
P.S。实际上,可以通过将 BorderStyle
设置为 bsNone
并将 BorderWidth
设置为高于零来创建表单,以通过内部边框实现大小调整:
{...}
type
TForm1 = class(TCustomSizingForm)
procedure FormCreate(Sender: TObject);
private
public
end;
{...}
procedure TForm1.FormCreate(Sender: TObject);
begin
BorderStyle:=bsNone;
BorderWidth:=4;
end;
{...}
如何为 window 哪些边框本身不能调整大小实施自定义大小调整例程?
例如BorderStyle
设置为 bsToolWindow
这里是自定义表单 -class 实现了不可调整大小的边框大小和禁用指定边缘大小的可能性。它还支持双击边框以在两个矩形边界之间切换:AutoSizeRect
到在 dblclick 上移动的表单边的值和 SavedSizeRect
更改之前保存的表单边坐标的值。因此 AutoSizeRect
可以在 运行 时设置到屏幕的某个区域,让用户能够在指定区域和当前 BoundsRect 之间交换边界侧的坐标。非常方便各种调色板-windows (aka ToolWindows)。最好结合自定义 sticking/aligning.
{...}
const
crMin=-32768; {lowest value for tCursor}
{predefined variable for tRect with undefined values:}
nullRect:tRect=(Left:MaxInt;Top:MaxInt;Right:MaxInt;Bottom:MaxInt);
type
{all sides and corners of Rect including inner part (rcClient):}
TRectCorner=(rcClient,rcTopLeft,rcTop,rcTopRight,rcLeft,rcRight,rcBottomLeft,rcBottom,rcBottomRight);
{here goes the mentioned class:}
TCustomSizingForm = class(TForm)
protected
private
disSizing:tAnchors; {edges with disabled sizing}
cCorner:tRectCorner; {current corner}
cCurSaved:tCursor; {saved cursor value for sizing}
coordsSv:tRect; {saved side's coordinates}
coordsASize:tRect; {auto-sizing area for dblclicks}
aSizeAcc:byte; {auto-sizing accuracy}
{checking if current edge-side is not disabled:}
function cCornerAvailable:boolean;
{setting sizing-cursor based on the edge-side:}
procedure setCursorViaCorner(Corner:tRectCorner);
{checking if mouse on borders and setting sizing cursor:}
function checkMouseOnBorders(msg:tWmNcHitMessage):boolean;
{NcHitTes and other NC-messages handlers:}
procedure WMNCHitTest(var msg:tWmNcHitTest); message WM_NCHITTEST;
procedure BordersLButtonDown(var msg:tWmNcHitMessage); message WM_NCLBUTTONDOWN;
procedure BordersLButtonUp(var msg:tWmNcHitMessage); message WM_NCLBUTTONUP;
procedure BordersMouseMove(var msg:tWmNcHitMessage); message WM_NCMOUSEMOVE;
procedure BordersLDblClick(var msg:tWmNcHitMessage); message WM_NCLBUTTONDBLCLK;
public
{Create-override for initializing rect-values:}
constructor Create(AOwner: TComponent); override;
{calculation of edge-side from tPoint:}
function getCornerFromPoint(BoundsRect:tRect; x,y:smallInt):tRectCorner;
{properties:}
property CursorSaved:tCursor read cCurSaved write cCurSaved default crMin;
property AutoSizeRect:tRect read coordsASize write coordsASize;
property SavedSizeRect:tRect read coordsSv write coordsSv;
published
{overwriting default BorderStyle:}
property BorderStyle default bsToolWindow;
{publishing disSizing property for Object Inspector:}
property DisabledSizingEdges:tAnchors read disSizing write disSizing default [];
end;
{...}
implementation
{--- TCustomSizingForm - public section: ---}
constructor TCustomSizingForm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
SavedSizeRect:=nullRect;
AutoSizeRect:=nullRect;
end;
function TCustomSizingForm.getCornerFromPoint(BoundsRect:tRect; x,y:smallInt):tRectCorner;
var CornerSize,BorderSize:tBorderWidth;
begin
BorderSize:=4+self.BorderWidth;
CornerSize:=8+BorderSize;
with BoundsRect do
if y<Top+BorderSize then
if x<Left+CornerSize then Result:=rcTopLeft
else if x>Right-CornerSize then Result:=rcTopRight
else Result:=rcTop
else if y>Bottom-BorderSize then
if x<Left+CornerSize then Result:=rcBottomLeft
else if x>Right-CornerSize then Result:=rcBottomRight
else Result:=rcBottom
else if x<Left+BorderSize then
if y<Top+CornerSize then Result:=rcTopLeft
else if y>Bottom-CornerSize then Result:=rcBottomLeft
else Result:=rcLeft
else if x>Right-BorderSize then
if y<Top+CornerSize then Result:=rcTopRight
else if y>Bottom-CornerSize then Result:=rcBottomRight
else Result:=rcRight
else Result:=rcClient;
end;
{--- TCustomSizingForm - private section: ---}
function TCustomSizingForm.cCornerAvailable:boolean;
var ca:tAnchorKind;
begin
result:=true;
if(disSizing=[])then exit;
if(cCorner in[rcTopLeft,rcLeft,rcBottomLeft])then begin
ca:=akLeft;
end else if(cCorner in[rcTopRight,rcRight,rcBottomRight])then begin
ca:=akRight;
end else if(cCorner in[rcTopLeft,rcTop,rcTopRight])then begin
ca:=akTop;
end else ca:=akBottom;
if(ca in disSizing)then result:=false;
end;
procedure TCustomSizingForm.setCursorViaCorner(Corner:tRectCorner);
var c:tCursor;
begin
case Corner of
rcLeft,rcRight: c:=crSizeWE;
rcTop,rcBottom: c:=crSizeNS;
rcTopLeft,rcBottomRight: c:=crSizeNWSE;
rcTopRight,rcBottomLeft: c:=crSizeNESW;
else exit;
end;
if(cursorSaved=crMin)then cursorSaved:=screen.Cursor;
setCursor(screen.Cursors[c]);
end;
function TCustomSizingForm.checkMouseOnBorders(msg:tWmNcHitMessage):boolean;
begin
result:=true;
cCorner:=rcClient;
if(msg.HitTest<>HTBORDER)then exit;
cCorner:=getCornerFromPoint(self.BoundsRect,msg.XCursor,msg.YCursor);
if(cCorner=rcClient)then exit;
if(cCornerAvailable)then begin
setCursorViaCorner(cCorner);
result:=false;
end;
end;
{--- TCustomSizingForm - WinApi_message_handlers: ---}
procedure TCustomSizingForm.WMNCHitTest(var msg:tWmNcHitTest);
var hitMsg:tWmNcHitMessage;
begin
inherited;
if(msg.Result=HTNOWHERE)and(PtInRect(self.BoundsRect,point(msg.XPos,msg.YPos)))then msg.Result:=HTBORDER
else if(msg.Result<>HTBORDER)then exit;
hitMsg.HitTest:=msg.Result;
hitMsg.XCursor:=msg.XPos;
hitMsg.YCursor:=msg.YPos;
checkMouseOnBorders(hitMsg);
end;
procedure TCustomSizingForm.BordersLButtonDown(var msg:tWmNcHitMessage);
const SC_SIZELEFT=1; SC_SIZERIGHT=2; SC_SIZETOP=3; SC_SIZEBOTTOM=6;
var m:integer;
begin
inherited;
if(checkMouseOnBorders(msg))then exit;
m:=SC_SIZE;
if(cCorner in[rcTopLeft,rcLeft,rcBottomLeft])then begin
inc(m,SC_SIZELEFT);
end else if(cCorner in[rcTopRight,rcRight,rcBottomRight])then begin
inc(m,SC_SIZERIGHT);
end;
if(cCorner in[rcTopLeft,rcTop,rcTopRight])then begin
inc(m,SC_SIZETOP);
end else if(cCorner in[rcBottomLeft,rcBottom,rcBottomRight])then begin
inc(m,SC_SIZEBOTTOM);
end;
ReleaseCapture;
SendMessage(self.Handle,WM_SYSCOMMAND,m,0);
end;
procedure TCustomSizingForm.BordersLButtonUp(var msg:tWmNcHitMessage);
begin
inherited;
if(cursorSaved=crMin)then exit;
setCursor(screen.Cursors[cursorSaved]);
cursorSaved:=crMin;
end;
procedure TCustomSizingForm.BordersMouseMove(var msg:tWmNcHitMessage);
begin
inherited;
checkMouseOnBorders(msg);
end;
procedure TCustomSizingForm.BordersLDblClick(var msg:tWmNcHitMessage);
var es:tAnchors; old,new:tRect;
begin
inherited;
if(checkMouseOnBorders(msg))or(EqualRect(coordsASize,nullRect))then exit;
es:=[];
ReleaseCapture;
if(cCorner in[rcTopLeft,rcLeft,rcBottomLeft])then es:=es+[akLeft];
if(cCorner in[rcTopRight,rcRight,rcBottomRight])then es:=es+[akRight];
if(cCorner in[rcTopLeft,rcTop,rcTopRight])then es:=es+[akTop];
if(cCorner in[rcBottomLeft,rcBottom,rcBottomRight])then es:=es+[akBottom];
if(es=[])then exit;
old:=self.BoundsRect;
new:=old;
if(akLeft in es)and(coordsASize.Left<MaxInt)then begin
if(abs(old.Left-coordsASize.Left)<=aSizeAcc)then begin
new.Left:=coordsSv.Left;
end else begin
coordsSv.Left:=old.Left;
new.Left:=coordsASize.Left;
end;
end;
if(akRight in es)and(coordsASize.Right<MaxInt)then begin
if(abs(old.Right-coordsASize.Right)<=aSizeAcc)then begin
new.Right:=coordsSv.Right;
end else begin
coordsSv.Right:=old.Right;
new.Right:=coordsASize.Right;
end;
end;
if(akTop in es)and(coordsASize.Top<MaxInt)then begin
if(abs(old.Top-coordsASize.Top)<=aSizeAcc)then begin
new.Top:=coordsSv.Top;
end else begin
coordsSv.Top:=old.Top;
new.Top:=coordsASize.Top;
end;
end;
if(akBottom in es)and(coordsASize.Bottom<MaxInt)then begin
if(abs(old.Bottom-coordsASize.Bottom)<=aSizeAcc)then begin
new.Bottom:=coordsSv.Bottom;
end else begin
coordsSv.Bottom:=old.Bottom;
new.Bottom:=coordsASize.Bottom;
end;
end;
self.BoundsRect:=new;
end;
{...}
DisabledSizingEdges
属性 是一组将被关闭的边缘(例如 DisabledSizingEdges:=[akLeft,akTop];
将关闭左侧、顶部、左下角、左上角的尺寸调整-角和右上角)
P.S。实际上,可以通过将 BorderStyle
设置为 bsNone
并将 BorderWidth
设置为高于零来创建表单,以通过内部边框实现大小调整:
{...}
type
TForm1 = class(TCustomSizingForm)
procedure FormCreate(Sender: TObject);
private
public
end;
{...}
procedure TForm1.FormCreate(Sender: TObject);
begin
BorderStyle:=bsNone;
BorderWidth:=4;
end;
{...}