delphi 锚点[akLeft,akRight,akBottom]无法正常工作

vlju58qv  于 2023-06-22  发布在  其他
关注(0)|答案(4)|浏览(100)

我有一个小问题与锚。
我有一个有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位置为负。
有人能帮忙吗?

gtlvzcf8

gtlvzcf81#

两种可能的解决方案:
1.在窗体的OnShow事件中而不是AfterConstruction中将Panel2的高度设置为零,或者
1.将另一个面板与Align=alBottom一起放置在Panel2上。
我不知道为什么第一个解决方案 * 确实 * 起作用,但它肯定有优点,因为在OnCreate(或您使用的AfterConstruction)期间,窗口控制句柄还没有分配。

gwbalxhn

gwbalxhn2#

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

我们需要为Panel2处理OnAlignPosition

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;

就这样

baubqpgj

baubqpgj3#

我有同样的问题11.3和修复它禁用此设置:

Options -> User Interface -> FormDesigner -> Enable VCL Style
nmpmafwu

nmpmafwu4#

锚定控件更喜欢将其锚定位置设置在实际存在的位置。 Delphi 很难在不适合所有控件的空间中安排控件。锚可能会“卡”在错误的位置,相邻对齐的控件可能会意外地交换位置。
当控件所在的面板更改为正大小时,请调整控件的位置,使其位于您希望的位置。只要它们保持可见(即,只要面板没有折叠到零高度),它们的锚将继续将它们保持在正确的位置。

相关问题