我正试图复制使用拆分器调整大小的操作,就像本问题中描述的那样,由MS SQL Managment Studio完成。
所以我有一个ScrollBox,有很多面板和拆分器对,垂直堆叠在一起。当我想用相应的拆分器放大面板时,它会将可能的增长限制在滚动框中的剩余大小。我无法将拆分器拖动到滚动框的客户端大小之外。
有人能帮我解决这个问题吗?
我尝试放大滚动框的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.
正如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.
Delphi的默认VCL TSplitter
不支持超出父客户端rect大小的大小调整。(如果父级有滚动条,我会选择这样的更改,但除此之外。(原因在于TSplitter.MouseDown
,其中根据父级的ClientHeight
设置了专用字段FMaxSize
。
一个可能只适用于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;