2015-09-13 25 views
2

我試圖複製與分隔符一樣的大小調整,就像MS SQL Managment Studio所做的那樣,如this question中所述。使用分隔符調整控件的大小超出父級的客戶區

所以我有一個滾動框與許多面板和分配器對,垂直堆疊在一起。當我想用相應的分離器放大面板時,它將可能的增長限制在滾動框中的剩餘大小。我無法將分隔線拖動到滾動框的客戶端大小之外。

有沒有人可以幫助我解決這個問題?

我試圖擴大滾動框VertScrollBar.Range,都沒有成功:

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; 

type 
    tDataBlock = class(TComponent) 
    fPanel: TPanel; 
    fLabel: TLabel; 
    fSplitter: TSplitter; 
    fOwner: TWinControl; 
    published 
    property Panel: TPanel read fPanel write fPanel; 
    property Text: TLabel read fLabel write fLabel; 
    property Owner: TWinControl read fOwner write fOwner; 
    public 
    constructor Create(Owner: TWinControl; var t: integer); 
    end; 

    TForm1 = class(TForm) 
    ScrollBox1: TScrollBox; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    BlockCount: integer; 
    procedure ConfigureScreen; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.ConfigureScreen; 
var i: integer; 
    TotalHeight: integer; 
begin 
    TotalHeight := 0; 
    for I := 0 to ScrollBox1.ComponentCount - 1 do begin 
    if ScrollBox1.Components[i] is TPanel then 
     TotalHeight := TotalHeight + TPanel(ScrollBox1.Components[i]).Height; 
    if ScrollBox1.Components[i] is TSplitter then 
     TotalHeight := TotalHeight + TSplitter(ScrollBox1.Components[i]).Height; 
    end; 
    ScrollBox1.VertScrollBar.Range := TotalHeight; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    I: Integer; 
    db: tDataBlock; 
    t: integer; 
begin 
    t := 0; 
    BlockCount := 0; 
    for I := 0 to 3 do begin 
    db := tDataBlock.Create(ScrollBox1, t); 
    Inc(BlockCount); 
    end; 
    ConfigureScreen; 
end; 

{ tDataBlock } 

constructor tDataBlock.Create(Owner: TWinControl; var t: integer); 
begin 
    fOwner := Owner; 

    fPanel := TPanel.Create(Owner); 
    fPanel.Parent := Owner; 
    fPanel.Height := 150; 
    fPanel.Top := t; 
    fPanel.Align := alTop; 
    fPanel.AlignWithMargins := false; 
    fPanel.Color := clRed; 
    fPanel.ParentBackground := false; 
    fPanel.BorderWidth := 0; 
    fPanel.BorderStyle := bsNone; 
    fPanel.Ctl3D := false; 
    fPanel.AutoSize := false; 
    fPanel.UseDockManager := false; 
    t := fPanel.Top + Panel.Height + 1; 

    fLabel := TLabel.Create(self); 
    fLabel.Parent := fPanel; 
    fLabel.Align := altop; 
    fLabel.Caption := inttostr(fPanel.Height); 
    fLabel.Font.Size := 10; 

    fSplitter := TSplitter.Create(Owner); 
    fSplitter.Parent:= Owner; 
    fSplitter.Height := 3; 
    fsplitter.Top := t; 
    fSplitter.AutoSnap := false; 
    fSplitter.AlignWithMargins := false; 
    fSplitter.MinSize := 1; 
    fSplitter.Align := alTop; 

    t := fSplitter.Top + fSplitter.Height + 1; 
end; 

end. 
+2

一些旁白。作爲一個規則,TComponent有一個虛擬構造函數,您應該覆蓋它。你不這樣做,你不會調用繼承的構造函數。也許你真的應該從TObject派生出來。 Top計算中的+1似乎是虛假的。 –

+0

我這樣做是因爲在運行時放置拆分器,它們不在我想要的位置,即使按照正確的順序創建。我不確定這是否會導致我無法將面板調整爲比客戶端屏幕更大的尺寸。你能最終提供任何例子嗎? – Tom

+0

我不願意在沒有所有細節的情況下進入。我們沒有你的dfm。它也可以顯着減少。 –

回答

0

正如SilverWarior提到的,TSplitter目的是劃分客戶區域,不將相鄰的控件調整爲任意大小。爲了實現你的目標,你需要通過一些NGLN建議的技巧來改變它的行爲。但是如果你這樣做,你可能會遇到一些副作用,因爲其他部分的代碼可能需要ScrollBox的ClientRect

其他選項是簡單地使用鼠標事件來模擬TSplitter的行爲。我稍微改了一下你的代碼,並用TPanel代替。但這只是一個快速入門,您可能需要更多的編碼,例如去除閃爍;)。

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, 
    Controls, Forms, Dialogs, StdCtrls, ExtCtrls; 

type 
    tDataBlock = class(TComponent) 
    private 
    fPanel: TPanel; 
    fLabel: TLabel; 
    fResizingPanel: TPanel; 
    fOwner: TWinControl; 

    IsResizing: Boolean; 
    StartHeight, StartY: Integer; 

    procedure ResizingPanelMouseMove(Sender: TObject; Shift: TShiftState; 
     X, Y: Integer); 
    procedure ResizingPanelMouseDown(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    procedure ResizingPanelMouseUp(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    published 
    property Panel: TPanel read fPanel write fPanel; 
    property Text: TLabel read fLabel write fLabel; 
    property Owner: TWinControl read fOwner write fOwner; 
    public 
    constructor Create(Owner: TWinControl; var t: Integer); 
    end; 

    TForm1 = class(TForm) 
    ScrollBox1: TScrollBox; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    BlockCount: Integer; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    I: Integer; 
    db: tDataBlock; 
    t: Integer; 
begin 
    t := 0; 
    BlockCount := 0; 
    for I := 0 to 3 do 
    begin 
    db := tDataBlock.Create(ScrollBox1, t); 
    Inc(BlockCount); 
    end; 
end; 

{ tDataBlock } 

constructor tDataBlock.Create(Owner: TWinControl; var t: Integer); 
begin 
    fOwner := Owner; 

    fPanel := TPanel.Create(Owner); 
    fPanel.Parent := Owner; 
    fPanel.Height := 150; 
    fPanel.Top := t; 
    fPanel.Align := alTop; 
    fPanel.AlignWithMargins := False; 
    fPanel.Color := clRed; 
    fPanel.ParentBackground := False; 
    fPanel.BorderWidth := 0; 
    fPanel.BorderStyle := bsNone; 
    fPanel.Ctl3D := False; 
    fPanel.AutoSize := False; 
    fPanel.UseDockManager := False; 
    fPanel.Constraints.MinHeight := 50; 
    // fPanel.DoubleBuffered := True; 
    t := fPanel.Top + Panel.Height + 1; 

    fLabel := TLabel.Create(self); 
    fLabel.Parent := fPanel; 
    fLabel.Align := alTop; 
    fLabel.Caption := inttostr(fPanel.Height); 
    fLabel.Font.Size := 10; 

    fResizingPanel := TPanel.Create(Owner); 
    fResizingPanel.Parent := Panel; 
    fResizingPanel.Height := 10; 
    fResizingPanel.Align := alBottom; 
    fResizingPanel.AlignWithMargins := False; 
    fResizingPanel.ParentBackground := False; 
    fResizingPanel.Cursor := crVSplit; 
    fResizingPanel.OnMouseDown := ResizingPanelMouseDown; 
    fResizingPanel.OnMouseMove := ResizingPanelMouseMove; 
    fResizingPanel.OnMouseUp := ResizingPanelMouseUp; 

    t := fResizingPanel.Top + fResizingPanel.Height + 1; 

end; 

procedure tDataBlock.ResizingPanelMouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    IsResizing := True; 
    StartHeight := Panel.Height; 
    StartY := fResizingPanel.ClientOrigin.Y + Y; 
end; 

procedure tDataBlock.ResizingPanelMouseMove(Sender: TObject; Shift: TShiftState; 
    X, Y: Integer); 
begin 
    if IsResizing then 
    Panel.Height := StartHeight + fResizingPanel.ClientOrigin.Y + Y - StartY; 
end; 

procedure tDataBlock.ResizingPanelMouseUp(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    IsResizing := False; 
end; 

end. 
+0

愛你的人!這是完美的!!!!非常感謝!!!! =) – Tom

+1

這裏沒有Mouse.CursorPos的地方 –

+0

@DavidHeffernan爲什麼? – saastn

0

德爾福的默認VCL TSplitter不支持調整超出父客戶端矩形的大小。 (如果父母有滾動條,我會選擇這樣的改變,但是這一點。)原因在於TSplitter.MouseDown,其中私人字段FMaxSize被設置,這取決於父母的ClientHeight

可能的工作只是爲TScrollBox一種解決方案是通過返回其父的不同ClientHeight愚弄TSplitter,如下:

type 
    TScrollBox = class(Vcl.Forms.TScrollBox) 
    protected 
    function GetClientRect: TRect; override; 
    end; 

implementation 

function TScrollBox.GetClientRect: TRect; 
begin 
    Result := inherited GetClientRect; 
    if GetCaptureControl is TSplitter then 
    Result.Bottom := Screen.DesktopHeight; 
end; 
相關問題