2011-03-01 46 views
2

我已經有了一些使用絕對定位的形式,並且Win7添加到「手柄」中以增強半透明性的額外像素正在擰緊控件。我想收回他們。我想在這裏回答的一個使用代碼:如何控制窗口的邊框尺寸?

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

特別是GolezTrol提供利用ShowForm的控裝置,帶至一的SetWindowRgn通話答案。 W7下的代碼行爲與XP相比有點不同,無論如何我無法得到我期待的效果。

對於XP中的標準TForm,數量Width-ClientWidth = 8,而在Win7中,它的數量是16.我希望返回8個像素。我也喜歡高像素,雖然寬度更重要。

+2

字體縮放會發生什麼?您的應用是否認視力不好的人的存在? – 2011-03-01 21:42:44

+0

通常,正確的方法是放大客戶區而不是縮小窗口區域。但前者可能會更復雜。 'WM_NCCALCSIZE'是告訴你的客戶區域在哪裏的消息,但是一旦你改變它,你*真的*必須繪製所有的非客戶區域,默認的繪畫將不適合任何其他大小。之後,你會有一些更多的經驗 - 併發症。雖然不是在Delphi中,[這篇文章]可能會給你一些啓示。 – 2011-03-02 02:39:21

+0

我發現所有這些非常複雜,我決定去無邊界,只是模擬自己調整大小(請參閱我的答案)。 – 2011-03-02 14:19:45

回答

7

我認爲這是非常糟糕的做法,依賴於窗體的邊框寬度,尤其是,因爲最終用戶可以在控制面板中更改此設置! ClientWidth屬性在那裏供您使用,而不是Width。將前者設置爲任何你喜歡的,後者將被計算。

+0

這是非常不好的做法。但對於這些特殊形式,我的看法並不相關。我可以嘗試在OnShow中爲Win7客戶端修改ClientWidth,但不會減少Width-ClientWidth數量。 – Cromulent 2011-03-01 21:04:00

+2

爲什麼'Width-ClientWidth'的值是什麼對你很重要? – 2011-03-01 21:06:19

+5

@Cromulent:但是你想要的是違背Windows的整個設計,特別是因爲添加了用戶主題。用戶可以控制邊框寬度,圖標大小,文本字體以及UI的許多其他方面,並且您的應用應該尊重這些選擇。不管你喜不喜歡,都不相干。 ;-) – 2011-03-01 21:07:58

2

您可以看到WinAPI函數SystemParametersInfo是否有幫助,標記爲SPI_SETNONCLIENTMETRICS。您可以使用NONCLIENTMETRICS記錄(C中的結構)中提供的值設置所有窗口的非客戶端區域的各個部分。

請注意,這是一個全局設置,因此不會影響系統上的所有窗口。這很可能是一個非常糟糕的解決方案。

+1

當然,除非產品嚴格按照內部使用設計(或類似的東西),否則「全局設置」部分就是個不錯的選擇。 – 2011-03-01 21:37:04

+1

@Andreas Rejbrand:我完全同意。這就是爲什麼我最後一句話說這是一個不好的解決方案。 :) – 2011-03-01 22:51:06

0

我在Windows中實現了一個模擬邊界調整行爲的控件。把它放在主窗體上,將它與alClient對齊,或使用錨定屬性(錨點可能更好),並將主窗體的邊框樣式更改爲bsNone,但不要執行鏈接到的其他問題中引用的黑客。

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.請注意,這種類型的東西有一些副作用,使它成爲「一個整潔的Hack」,但不是我在真實軟件中發佈的東西。這是一個玩具。