我的锚有一个小问题。
我有一个包含2个面板的表单,Panel1
左对齐,Panel2
位于第一个,未对齐但锚定的顶部和底部。在第二个面板上有两个编辑,它们仅锚定在左侧,右侧和底部。这种设计导致“最小化”滑动效果,从而在调整窗体大小时,编辑在顶部消失。这是有目的的。
在应用程序开始时,第二个面板的初始状态应该是不可见的,因此我使用Panel2.Height := 0
。
但是在调整表单大小或手动设置Panel2.Height := 104
后,编辑不会被拖动到其固定位置,但它们在面板之外仍然不可见。
这是可以帮助可视化它的示例代码:
// unit 1
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TMoveEvent = procedure (Sender: TObject; X, Y: Integer) of object;
TLabeledEdit = class(ExtCtrls.TLabeledEdit)
private
FOnMove: TMoveEvent;
procedure WMMove(var Message: TWMMove); message WM_MOVE;
public
property OnMove: TMoveEvent read FOnMove write FOnMove;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
LabeledEdit1: TLabeledEdit;
LabeledEdit2: TLabeledEdit;
Button1: TButton;
Button2: TButton;
Label1: TLabel;
Label2: TLabel;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
procedure LE1Move(Sender: TObject; X, Y: Integer);
procedure LE2Move(Sender: TObject; X, Y: Integer);
public
procedure AfterConstruction; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
TypInfo;
const
MaxSet = 255; // Largest ordinal value in a Delphi set.
type
TSet = set of 0..MaxSet;
function SetToString(Info: PTypeInfo; const Value; const Separator, Prefix, Suffix: string): String; overload;
var
CompInfo: PTypeInfo;
CompData: PTypeData;
SetValue: TSet absolute Value;
Element: 0..MaxSet;
begin
CompInfo:=GetTypeData(Info)^.CompType^;
CompData:=GetTypeData(CompInfo);
Result:='';
for Element:=CompData.MinValue to CompData.MaxValue do begin
if Element in SetValue then
if Result = '' then
Result := Prefix + GetEnumName(CompInfo, Element)
else
Result := Result + Separator + GetEnumName(CompInfo, Element);
end;
if Result = '' then
Result := Prefix + Suffix
else
Result := Result + Suffix;
end;
function SetToString(Info: PTypeInfo; const Value; const Separator: string): String; overload;
begin
Result:=SetToString(Info, Value, Separator, '[', ']');
end;
function SetToString(Info: PTypeInfo; const Value): String; overload;
begin
Result:=SetToString(Info, Value, ', ');
end;
{ TLabeledEdit }
procedure TLabeledEdit.WMMove(var Message: TWMMove);
begin
inherited;
if Assigned(FOnMove) then
FOnMove(Self, Message.XPos, Message.YPos);
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
LabeledEdit1.OnMove:=LE1Move;
LabeledEdit2.OnMove:=LE2Move;
end;
procedure TForm1.AfterConstruction;
begin
inherited;
Panel2.Height:=0;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Panel2.Height:=0;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Panel2.Height:=104;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage('LE1 Anchors = ' + SetToString(TypeInfo(TAnchors), LabeledEdit1.Anchors));
ShowMessage('LE2 Anchors = ' + SetToString(TypeInfo(TAnchors), LabeledEdit2.Anchors));
end;
procedure TForm1.LE1Move(Sender: TObject; X, Y: Integer);
begin
Label1.Caption:=Format('LE1 pos: %d : %d', [X, Y]);
end;
procedure TForm1.LE2Move(Sender: TObject; X, Y: Integer);
begin
Label2.Caption:=Format('LE2 pos: %d : %d', [X, Y]);
end;
end.
// dfm
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 304
ClientWidth = 643
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 200
Top = 56
Width = 31
Height = 13
Caption = 'Label1'
end
object Label2: TLabel
Left = 200
Top = 96
Width = 31
Height = 13
Caption = 'Label2'
end
object Panel1: TPanel
Left = 0
Top = 0
Width = 185
Height = 304
Align = alLeft
TabOrder = 0
ExplicitLeft = 152
ExplicitTop = 96
ExplicitHeight = 41
DesignSize = (
185
304)
object Panel2: TPanel
Left = 1
Top = 81
Width = 183
Height = 104
Anchors = [akLeft, akTop, akRight, akBottom]
Constraints.MaxHeight = 104
TabOrder = 0
DesignSize = (
183
104)
object LabeledEdit1: TLabeledEdit
Left = 8
Top = 24
Width = 121
Height = 21
Anchors = [akLeft, akRight, akBottom]
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit1'
TabOrder = 0
end
object LabeledEdit2: TLabeledEdit
Left = 48
Top = 72
Width = 121
Height = 21
Anchors = [akLeft, akRight, akBottom]
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit2'
TabOrder = 1
end
end
end
object Button1: TButton
Left = 200
Top = 8
Width = 75
Height = 25
Caption = 'Hide'
TabOrder = 1
OnClick = Button1Click
end
object Button2: TButton
Left = 281
Top = 8
Width = 75
Height = 25
Caption = 'Show'
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 200
Top = 140
Width = 75
Height = 25
Caption = 'Anchors'
TabOrder = 3
OnClick = Button3Click
end
end
如果在创建表单后Panel2.Height
未设置为0,则在调整表单大小时,编辑会上下移动。如果在表单创建时将Panel2.Height
设置为0,则修改会在Panel2
之外保持不可见状态,如果显示Panel2
,则它们将保持不可见,因此Top
位置为负数
有人可以帮忙吗?
答案 0 :(得分:3)
锚定控件更喜欢将锚定位置放在实际存在的位置。 Delphi无法在不适合的空间中安排控件。锚点可以“卡在”错误的位置,相邻的对齐控件可能会意外地相互交换位置。
当控件所在的面板更改为正大小时,请调整控件的位置,以便它们位于您希望的位置。只要它们仍然可见(即,只要面板没有折叠到零高度),它们的锚将继续保持在正确的位置。
答案 1 :(得分:2)
两种可能的解决方案:
Panel2
事件中将OnShow
的高度设置为零,而不是AfterConstruction
或Panel2
上Align=alBottom
。第一个解决方案 工作的原因我不知道,但它肯定有价值,因为在OnCreate
(或AfterConstruction
使用时),窗口化控制句柄尚未分配。
答案 2 :(得分:0)
我找到了解决此问题的方法,但它与锚无关,它更多地与Align = alCustom
...
但如果有人对我如何解决它感兴趣,这里有一些代码来解释它。
// modified form create procedure
procedure TForm1.FormCreate(Sender: TObject);
begin
LabeledEdit1.Align:=alCustom; // go to hell with automation
LabeledEdit1.Anchors:=[akLeft, akRight, akBottom]; // this can be ommited
LabeledEdit2.Align:=alCustom; // go to hell with automation
LabeledEdit2.Anchors:=[akLeft, akRight, akBottom]; // this can be ommited
LabeledEdit1.OnMove:=LE1Move;
LabeledEdit2.OnMove:=LE2Move;
end;
我们需要为OnAlignPosition
处理Panel2
。
type
TUnProtectedWinControl = class(TWinControl);
procedure TForm1.Panel2AlignPosition(Sender: TWinControl; Control: TControl; var NewLeft, NewTop, NewWidth, NewHeight: Integer; var AlignRect: TRect; AlignInfo: TAlignInfo);
begin
if (Sender <> Nil) and (Sender is TWinControl) then begin
if Control.Parent <> Nil then begin
if Control.ExplicitTop > 0 then
NewTop:=Control.Parent.Height - (TUnProtectedWinControl(Sender).FDesignSize.Y - Control.ExplicitTop)
else
NewTop:=Control.Parent.Height + Control.ExplicitTop;
end;
end;
end;
就是这样。