开发者

How can I control the border size of a window?

I've got some forms that use absolute positioning and the extra pixels that Win7 adds into the "handles" to enhance translucency are screwing the controls up. I'd like to take them back. I tried using code in one of the answers here:

Can you make a Borderless Application Main Window in Windows, without WS_POPUP style?

Specifically the answer that GolezTrol provided utilizing an override in ShowFo开发者_如何学JAVArm with a call to SetWindowRgn. The code's behavior is a bit different under W7 than XP, and in any case I can't get the effect I'm looking for.

For a standard TForm in XP, the quantity Width-ClientWidth = 8, and in Win7, it's 16. I'd like those 8 pixels back. I'd like the height pixels back too while I'm at it, though the width is more important.


I think it is very bad practice to rely on the border width of a form, especially since the end-user can change this in the control panel! The ClientWidth property is there for you to use instead of Width. Set the former to whatever you like, and the latter will be computed.


You can see if the WinAPI function SystemParametersInfo will help, with the flag SPI_SETNONCLIENTMETRICS. You can set various parts of the non-client area of all windows with values provided in the NONCLIENTMETRICS record (structure in C).

Note that this is a global setting, and therefore won't affect just your windows but all windows on the system. It's most likely a very bad solution.


I implemented a control that emulates the border-resize behaviour, in Windows. Put this on your main form, align it to alClient, or use the anchor properties (anchors are probably better) and change your main form's border style to bsNone but do NOT do the hacks referenced in the other question you linked to.

unit ResizeBorderControlUnit;

// TResizeBorderControl:
//
//  This is a subclass of TShape made to handle the border resize
//  logic for a main form with border style bsNone.  I wanted to 
//  make the form resizeable (think of a post-it note app) but I didn't
//  want any Windows non-client painting or non-client manipulation logic. 
//
// Written by Warren Postma



interface

uses Windows,
      Messages,
      Controls,
      Forms,
      ExtCtrls,
      Classes,
      SysUtils;

const
  // if this value is too small, resizing gets too tricky.
   MinSideMargin = 4;
   MinBottomMargin = 4;

    //Perform(wm_SysCommand, sc_DragMove, 0) etc:
    sc_DragMove = $f012;
    sc_Leftsize = $f001;
    sc_Rightsize = $f002;
    sc_Upsize = $f003;
    sc_UpLeftsize = $f004;
    sc_UpRightsize = $f005;
    sc_Dnsize = $f006;
    sc_DnLeftsize = $f007;
    sc_DnRightsize = $f008;

type
  TResizeBorderControl = class(TShape)
  private
//      FParentFormResize:TForm;
    FSidesResizeHeight: Integer;
    FBottomResizeHeight: Integer;
    FBorderResizeFlag:Integer;
    FAutoSize: Boolean;
    FAutoSizeStartingAtTop: Integer; // currently active state.
    procedure SetBottomResizeHeight(const Value: Integer);
    procedure SetSidesResizeHeight(const Value: Integer);
    procedure SetAutoSize(const Value: Boolean);
    procedure SetAutoSizeStartingAtTop(const Value: Integer);

  protected
      procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
      procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
      procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE; //override;
      procedure CheckPosition(X,  Y: Integer);


      function MainFormMaximized:Boolean;

  public
      constructor Create(AOwner:TComponent); override;
  published
     property AutoSize:Boolean read FAutoSize write SetAutoSize;
     property AutoSizeStartingAtTop:Integer read FAutoSizeStartingAtTop write SetAutoSizeStartingAtTop;
     property BottomResizeHeight:Integer read FBottomResizeHeight write SetBottomResizeHeight;
     property SidesResizeHeight:Integer read FSidesResizeHeight write SetSidesResizeHeight;
  end;
implementation



// TResizeBorderControl 


procedure TResizeBorderControl.CMMouseLeave(var Message: TMessage);
begin
  Parent.Perform(CM_MOUSELEAVE, 0, Longint(Self));
  if (Message.LParam = 0) then
  begin
    if Assigned(OnMouseLeave) then
      OnMouseLeave(Self);

    if ShowHint and not (csDesigning in ComponentState) then
      if CustomHint <> nil then
        CustomHint.HideHint(Self);
  end;

  FBorderResizeFlag := 0; // reset any active state bits.
  Self.Cursor := crDefault;
end;

constructor TResizeBorderControl.Create(AOwner: TComponent);
begin
  inherited;
  Brush.Color := $202020;
end;

function TResizeBorderControl.MainFormMaximized: Boolean;
var
 fm:TCustomForm;
begin
  result := true;
  fm := GetParentForm(Self);
  if Assigned(fm) then
      result := (fm.WindowState=wsMaximized);


end;

procedure TResizeBorderControl.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);

   procedure DoResize(aType:Integer);
   var
     pw:TCustomForm;
   begin
       ReleaseCapture;
       pw := Forms.GetParentForm(Self);
       if Assigned(pw) then begin
         ReleaseCapture;
         pw.Perform(WM_syscommand, aType, 0);
       end;
   end;
begin
  inherited;

  if csDesigning in ComponentState then exit;
  if MainFormMaximized then exit;

 if (FBorderResizeFlag=0) then begin
    CheckPosition(X, Y);
 end;

 if FBorderResizeFlag  =1 then
      DoResize( sc_Leftsize)
 else if FBorderResizeFlag  =2 then
     DoResize( sc_Rightsize)
 else if FBorderResizeFlag  =4 then
      DoResize( sc_Dnsize )
 else if FBorderResizeFlag  =5 then
      DoResize( sc_DnLeftsize)
 else if FBorderResizeFlag  =6 then
       DoResize( sc_DnRightsize)
 else if FBorderResizeFlag  =8 then
        DoResize( sc_Upsize)
 else
   Self.Cursor := crDefault;

 //FBorderResizeFlag  := 0; // nope. second time mouse down without a move would glitch us.
end;

procedure TResizeBorderControl.MouseMove(Shift: TShiftState; X,
  Y: Integer);
begin
  if MainFormMaximized then exit;

 CheckPosition(X,Y);
end;

procedure TResizeBorderControl.CheckPosition(X,  Y: Integer);
var
 SideMargin,BottomMargin:Integer;
begin


  if csDesigning in ComponentState then begin
    inherited;
    exit;
  end;

  FBorderResizeFlag  := 0;

  if MainFormMaximized then exit;

  BottomMargin := FBottomResizeHeight;
  if BottomMargin<MinBottomMargin then
   BottomMargin := MinBottomMargin;

  SideMargin := FSidesResizeHeight;
  if SideMargin < MinSideMargin then
      SideMargin := MinSideMargin;


 if (X<SideMargin) then
    FBorderResizeFlag   := FBorderResizeFlag   or 1 // left
 else if (X>=Self.Width-SideMargin) then
    FBorderResizeFlag   := FBorderResizeFlag   or 2; // right

 if (Y>=Self.Height-BottomMargin) then
    FBorderResizeFlag   := FBorderResizeFlag   or 4; // bottom
//
// else if (Y<BottomMargin) then // BottomMargin could also be used for top!
//    FBorderResizeFlag   := FBorderResizeFlag   or 8; // top


if FBorderResizeFlag  =1 then
      Self.Cursor := crSizeWE
 else if FBorderResizeFlag  =2 then
      Self.Cursor := crSizeWE
 else if FBorderResizeFlag  =4 then
      Self.Cursor := crSizeNS
 else if FBorderResizeFlag  =5 then
      Self.Cursor := crSizeNESW // bottom left
 else if FBorderResizeFlag  =6 then
      Self.Cursor := crSizeNWSE // bottom right
 else if FBorderResizeFlag  =8 then
      Self.Cursor := crSizeNS  // up
 else begin
      Self.Cursor := crDefault;
      inherited;
 end;

end;

procedure TResizeBorderControl.SetAutoSize(const Value: Boolean);
begin
  FAutoSize := Value;

  if FAutoSize then begin
    Align := alNone;

    if Self.Left<>0 then
        Self.Left := 0;
    if Self.Width<>Parent.Width then
        Self.Width := Parent.Width;
    if Self.Height<>Parent.Height then
        Self.Width := Parent.Width;

    Anchors := [akLeft, akTop, akRight, akBottom];


  end;


  Invalidate;
end;

procedure TResizeBorderControl.SetAutoSizeStartingAtTop(
  const Value: Integer);
begin
  FAutoSizeStartingAtTop := Value;
end;

procedure TResizeBorderControl.SetBottomResizeHeight(
  const Value: Integer);
begin
  FBottomResizeHeight := Value;
end;

procedure TResizeBorderControl.SetSidesResizeHeight(
  const Value: Integer);
begin
  FSidesResizeHeight := Value;
end;

end.

P.S. Note that there are some side effects to this kind of thing that made it "a neat Hack" but not something I would ship in a real world piece of software. This is a toy.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜