2

我对锚有一个小问题。

我有一个带有 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位置为负。

有人可以帮忙吗?

4

3 回答 3

3

锚定控件更喜欢将其锚定位置放在实际存在的位置。Delphi 无法在不完全适合的空间中安排控件。锚点可能会“卡”在错误的位置,相邻对齐的控件可能会意外地相互交换位置。

当控件所在的面板变为正尺寸时,请调整控件的位置,使它们位于您想要的位置。只要它们保持可见(即,只要面板没有折叠到零高度),它们的锚点就会继续将它们保持在正确的位置。

于 2013-02-26T16:41:06.420 回答
2

两种可能的解决方案:

  1. 在表单的事件Panel2中将 ' 的高度设置为零,而不是在 中,或OnShowAfterConstruction
  2. Panel2用放置另一个面板Align=alBottom

我不知道为什么第一个解决方案确实OnCreate有效,但它肯定有优点,因为在(或AfterConstruction在您使用时),窗口控制句柄尚未分配。

于 2013-02-27T18:10:35.863 回答
1

我找到了解决这个问题的方法,但它与锚无关,它更多地与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;

就是这样。

于 2013-02-28T06:38:04.153 回答