Delphi:滑动(动画)面板

12

是否有Delphi的滑动(动画)面板组件?

例如,可以在Raize Components中找到(带有“热点”或隐藏/显示按钮的左侧面板)。

我需要的不是可调整大小的面板,而是可以从左侧平滑水平滑动的面板+带有隐藏/显示按钮(如果没有该按钮也没关系)。

谢谢!


3
这篇文章或许会有帮助:http://delphi.about.com/od/delphi-tips-2011/qt/hide-slide-fade-away-controls-delphi-form.htm。 - johnny
在这里查看FoldingPanel v1.3:http://www.torry.net/authorsmore.php?id=2386 我用了好几年了。还有一个漂亮的chevron位图。 - Gabriel
5个回答

23

尝试使用NLDSideBar,这是我编写的一个容器组件,可以折叠并沿其父容器的左侧或右侧对齐。

接口:

property Align: TSideBarAlign default alLeft;
property AutoHide: Boolean default False;
property Hint: String;
property MinWidth: Integer default DefWidth;
property OnAutoHideChanged: TNotifyEvent;
property OnHide: TNotifyEvent;
property PinButtonDownHint: String;
property PinButtonUpHint: String;
property PinButtonVisible: Boolean default True;
property Resizable: Boolean default True;
property SideButtonWidth: Integer default DefSideButtonWidth;
property Caption;
property Color default clBtnFace;
property Font;
property ParentColor default False;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property TabOrder;
property TabStop;

NLDSideBar

或者使用这个旧版本(动画效果)。可免费使用、修改。

很抱歉我自夸了一下,但我认为这是回答问题的方法。


13
只要你公开你的参与情况,自我推广是可以被接受的,无需为此道歉。 - Marjan Venema
6
我会一直点赞免费开源项目的自我推广! - Warren P
1
如果自我推广并完美回答了问题,我会一直点赞。 - Gabriel
你似乎从未更新过它,除了Delphi 7之外 :-) 我在xe2中尝试了一下,在右侧放置了两个面板 - 行为比较令人失望...猜测你总是只有一个侧面板 :-) - Arioch 'The
1
@Arioch'The 谢谢!这是一个bug。在UpdatePlacement的每个块结尾添加BringToFront - NGLN
同一侧折叠面板的多个按钮是否可以放在一行中,就像选项卡一样? - Arioch 'The

11
我们最终建立了自己的控件。 我们找不到适合我们所需的功能。 事实证明并不难。 我相信有些情况我们处理得不正确,但是到目前为止对我们来说运作良好。
以下代码使用cxGroupBox,因为我们需要与我们应用程序的其余部分相匹配的外观。 这可以更换为常规GroupBox。
我们在两个地方使用它。 在一个案例中,我们在标准Delphi Flow Panel内放置了多个这样的面板(我不确定添加了哪个版本)。 当我们的DynPanel折叠时,所有内容会自动向上移动并填充空间。
在另一种情况下,我们有一个窗口,它被分成主要部分和工具箱。 两者由标准拆分器分开。 主窗口设置为与客户端对齐。 当我们的面板折叠或展开时,拆分器会自动移动和扩展主要部分。
我们从未完全弄清楚“容器”控件的工作方式,因此您将添加到面板的项目可能会移动到通常不会预期在组框中的范围之外。 但是这不会给我们带来任何重大问题,因此我们只是将其留下。 这也没有考虑与按钮大小相关的DPI更改。 标题会变得更大,但按钮不会。

unit DynPanel;

interface

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

const
  DEFAULTBUTTONWIDTH = 16;
  DEFAULTWIDTH  = 161;
  DEFAULTHEIGHT = 81;
  cButtonPadding = 8;
  cCollapsePadding = 3;
  cCaptionPadding = '       ';
  cCollapsedSize = DEFAULTBUTTONWIDTH + cCollapsePadding;
  cAutoCollapseSize = DEFAULTBUTTONWIDTH + cButtonPadding;

type
  TCollapseDirection = (cdUp, cdRight, cdLeft);

  TMinDemension = cAutoCollapseSize..High(Integer);

  TDynPanel = class(TPanel)
  private
    FGroupBox: TcxGroupBox;
    FButtonPanel: TPanel;
    FButtonImage: TImage;

    FExpand: Boolean;
    FOldHeight: Integer;
    FOldWidth: Integer;
    FCollapseDirection: TCollapseDirection;
    FOrigGroupBoxCaption: String;
    FAutoCollapseHeight: TMinDemension;
    FAutoCollapseWidth: TMinDemension;

    FButtonPadding: integer;
    FCollapsePadding: integer;
    FCollapsedSize: integer;

    procedure SetExpand(Value: Boolean);
    procedure SetGroupBoxCaption(Value: string);
    procedure ButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
    procedure EnableControls(Value: Boolean);
    procedure SetCollapseDirection(Value: TCollapseDirection);
    procedure ConfigurePanel;
    procedure SetMinHeight(Value: TMinDemension);
    procedure SetMinWidth(Value: TMinDemension);
    procedure UpdateImage();

  protected
    procedure Resize; override;
    procedure ChangeScale(M, D: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    property OldHeight: Integer read FOldHeight write FOldHeight;
    property OldWidth: Integer read FOldWidth write FOldWidth;
    property GroupBox: TcxGroupBox read FGroupBox;
  published
    property Caption: string read FOrigGroupBoxCaption write SetGroupBoxCaption;
    property Expand: Boolean read FExpand write SetExpand;
    property BevelOuter default bvNone;
    property CollapseDirection: TCollapseDirection read FCollapseDirection write SetCollapseDirection default cdUp;
    property AutoCollapseHeight: TMinDemension read FAutoCollapseHeight write SetMinHeight default cAutoCollapseSize;
    property AutoCollapseWidth: TMinDemension read FAutoCollapseWidth write SetMinWidth default cAutoCollapseSize;
  end;

procedure Register;

implementation

{$R 'ButtonImages\ButtonImages.res' 'ButtonImages\ButtonImages.rc'}

uses cxEdit;

procedure Register;
begin
  RegisterComponents('AgWare', [TDynPanel]);
end;


{ TDynPanel }

{
  TDynPanel.Create
  ---------------------------------------------------------------------------
}
constructor TDynPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  Self.ControlStyle := ControlStyle - [csSetCaption];

  Self.Width := DEFAULTWIDTH;
  Self.Height := DEFAULTHEIGHT;
  BevelOuter := bvNone;

  FExpand := True;
  FOldHeight := Self.Height;
  FOldWidth := Self.Width;
  FOrigGroupBoxCaption := 'AgDynPanel';
  FCollapseDirection := cdUp;
  FAutoCollapseHeight := cAutoCollapseSize;
  FAutoCollapseWidth := cAutoCollapseSize;

  FGroupBox := TcxGroupBox.Create(Self);
  FGroupBox.Parent := Self;
  FGroupBox.Align := alClient;
  FGroupBox.Alignment := alTopLeft;

  FButtonPanel := TPanel.Create(Self);
  FButtonPanel.Parent := Self;
  FButtonPanel.Top := 0;
  FButtonPanel.Width := DEFAULTBUTTONWIDTH;
  FButtonPanel.Height := DEFAULTBUTTONWIDTH;
  FButtonPanel.Left := Width - DEFAULTBUTTONWIDTH - FButtonPadding;
  FButtonPanel.OnMouseDown := ButtonMouseDown;

  FButtonImage := TImage.Create(Self);
  FButtonImage.Parent := FButtonPanel;
  FButtonImage.Align := alClient;
  FButtonImage.Stretch := false;
  FButtonImage.Center := true;
  FButtonImage.OnMouseDown := ButtonMouseDown;

  UpdateImage;

  // The click should also work for the entire top of the group box.
  FGroupBox.OnMouseDown := ButtonMouseDown;

  FGroupBox.Caption := FOrigGroupBoxCaption;
  FGroupBox.Style.Font.Style := FGroupBox.Style.Font.Style + [fsBold];

  FButtonPadding := cButtonPadding;
  FCollapsePadding := cCollapsePadding;
  FCollapsedSize := cCollapsedSize;

end;

{
  TDynPanel.SetGroupBoxCaption
  ---------------------------------------------------------------------------
}
procedure TDynPanel.SetGroupBoxCaption(Value: String);
begin
  FOrigGroupBoxCaption := Value;
  ConfigurePanel;
end;

{
  TDynPanel.SetMinHeight
  ---------------------------------------------------------------------------
}
procedure TDynPanel.SetMinHeight(Value: TMinDemension);
begin
  if Value = FAutoCollapseHeight then
    Exit; // >>----->

  FAutoCollapseHeight := Value;

  if Showing then
    Resize;
end;

{
  TDynPanel.SetMinWidth
  ---------------------------------------------------------------------------
}
procedure TDynPanel.SetMinWidth(Value: TMinDemension);
begin
  if Value = FAutoCollapseWidth then
    Exit; // >>----->

  FAutoCollapseWidth := Value;

  if Showing then
    Resize;
end;

{
  TDynPanel.ButtonMouseDown
  ---------------------------------------------------------------------------
}
procedure TDynPanel.ButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button  mbLeft then
    Exit; // >>----->

  if ((FExpand = True) and (Y  FCollapsePadding)) or
     ((FExpand = False) and (FCollapseDirection = cdLeft) and (X >----->

  FExpand := Value;

  //ConfigurePanel;

  //--------------------------------------------------------------------------
  // Set the group box size
  //--------------------------------------------------------------------------
  //
  // I chose to do the resizing of the control here rather than in
  // ConfigurePanel because if you do it there the SetBounds will call ReSize
  // which will call ConfigurePanel again so that you would need to keep track
  // of a boolean variable to determine if you are making recursive calls into
  // ConfigurePanel. That is one reason. Another is that when the dfm values
  // are streamed in and the properties get set you will resize the control
  // before the actual Height and Width properties are set. This will cause
  // bogus default values to be stored for FOldHeight and FOldWidth and when
  // the control is displayed the dimensions will be wrong. If you size the
  // control here then, on creation, Resize will not get called and the
  // FOldHeight and FOldWidth values will not get saved off until
  // CMShowingChanged will explicitly call ReSize after the dimensions are
  // properly set. If you move this code into ConfigurePanel then when the
  // caption is streamed in and set from the dfm then ConfigurePanel would get
  // called, we would SetBounds there and then Resize would fire storing off the
  // default invalid values for the FOld variables as mentioned above.
  // Hope this makes sense. Leave the SetBounds calls here and make your life
  // easier. :)
  //--------------------------------------------------------------------------

  // Changing to Expanded
  if FExpand = True then
  begin
    // Up
    if FCollapseDirection = cdUp then
      SetBounds(Left, Top, Width, FOldHeight)
    // Right
    else if FCollapseDirection = cdRight then
      SetBounds((Left + Width) - FOldWidth, Top, FOldWidth, Height)
    // Left
    else if FCollapseDirection = cdLeft then
      SetBounds(Left, Top, FOldWidth, Height);
  end
  // Changing to Collapsed
  else
  begin
    // Up
    if FCollapseDirection = cdUp then
    begin
      // Reset the AutoCollapseHeight just to make sure we don't try to
      // recollapse on resize.
      if FAutoCollapseHeight  FGroupBox) and
       (Self.Controls[i]  FButtonPanel) then
    begin
      Self.Controls[i].Enabled := Value;
      Self.Controls[i].Visible := Value;
    end;
  end;
end;

{
  TDynPanel.CMShowingChanged
  ---------------------------------------------------------------------------
}
procedure TDynPanel.CMShowingChanged(var Message: TMessage);
begin
  inherited;
  if Showing then
    Resize;
end;

{
  TDynPanel.Resize
  ---------------------------------------------------------------------------
}
procedure TDynPanel.Resize;
begin

  if FExpand = True then
  begin
    if (FCollapseDirection = cdUp) and (Height  FAutoCollapseHeight then
      begin
        FOldHeight := Height;
        Expand := True;
      end
      else
        Height := FCollapsedSize;
    end
    else if (FCollapseDirection = cdLeft) or (FCollapseDirection = cdRight) then
    begin
      if (Width > FAutoCollapseWidth) then
      begin
        FOldWidth := Width;
        Expand := True;
      end
      else
        Width := FCollapsedSize;
    end;
  end;

  ConfigurePanel;

end;


{
  TDynPanel.ChangeScale
  ---------------------------------------------------------------------------
}
procedure TDynPanel.ChangeScale(M, D: Integer);
begin

  FAutoCollapseHeight := MulDiv(FAutoCollapseHeight, M, D);
  FAutoCollapseWidth := MulDiv(FAutoCollapseWidth, M, D);

  FButtonPadding := MulDiv(FButtonPadding, M, D);
  FCollapsePadding := MulDiv(FCollapsePadding, M, D);
  FCollapsedSize := MulDiv(FCollapsedSize, M, D);


  FOldHeight := MulDiv(FOldHeight, M, D);
  FOldWidth := MulDiv(FOldWidth, M, D);

  // inherited will cause resize to be called.  I need to update
  // my internal values before that happens, otherwise I will resize based
  // on the old values.
  inherited;

end;

{
  TDynPanel.SetCollapseDirection
  ---------------------------------------------------------------------------
}
procedure TDynPanel.SetCollapseDirection(Value: TCollapseDirection);
begin
  if Value = FCollapseDirection then
    Exit; // >>----->

  FCollapseDirection := Value;

  ConfigurePanel;
end;

{
  TDynPanel.ConfigurePanel
  ---------------------------------------------------------------------------
}
procedure TDynPanel.ConfigurePanel;
begin
  //--------------------------------------------------------------------------
  // Set the group box style, caption alignment, caption, button position, and
  // button image
  //--------------------------------------------------------------------------

  // Changing to Expanded
  if FExpand = True then
  begin
    FGroupBox.Style.Color := clWhite;
    // Up
    if FCollapseDirection = cdUp then
    begin
      FGroupBox.Alignment := alTopLeft;
      FGroupBox.Caption := FOrigGroupBoxCaption;
      FButtonPanel.Top := 0;
      FButtonPanel.Left := Width - FButtonPanel.Width - FButtonPadding;
    end
    // Right
    else if FCollapseDirection = cdRight then
    begin
      FGroupBox.Alignment := alTopLeft;
      FGroupBox.Caption := '       ' + FOrigGroupBoxCaption;
      FButtonPanel.Top := 0;
      FButtonPanel.Left := FButtonPadding;
    end
    // Left
    else if FCollapseDirection = cdLeft then
    begin
      FGroupBox.Alignment := alTopLeft;
      FGroupBox.Caption := FOrigGroupBoxCaption;
      FButtonPanel.Top := 0;
      FButtonPanel.Left := Width - FButtonPanel.Width - FButtonPadding;
    end;
  end
  // Changing to Collapsed
  else
  begin
    FGroupBox.Style.Color := clGradientActiveCaption;
    // Up
    if FCollapseDirection = cdUp then
    begin
      FGroupBox.Alignment := alTopLeft;
      FGroupBox.Caption := FOrigGroupBoxCaption;
      FButtonPanel.Top := 0;
      FButtonPanel.Left := Width - FButtonPanel.Width - FButtonPadding;
    end
    // Right
    else if FCollapseDirection = cdRight then
    begin
      FGroupBox.Alignment := alRightTop;
      FGroupBox.Caption := '       ' + FOrigGroupBoxCaption;
      FButtonPanel.Top := FButtonPadding;
      FButtonPanel.Left := FCollapsePadding;
    end
    // Left
    else if FCollapseDirection = cdLeft then
    begin
      FGroupBox.Alignment := alLeftTop;
      FGroupBox.Caption := FOrigGroupBoxCaption + '       ';
      FButtonPanel.Top := FButtonPadding;
      FButtonPanel.Left := 0;
    end;
  end;

  UpdateImage;
  // Now draw the button and invalidate Self
  Self.Invalidate;
end;

{
  TDynPanel.UpdateImage
  ---------------------------------------------------------------------------
}
procedure TDynPanel.UpdateImage();
begin
  case FCollapseDirection of
    cdUp:
      begin
        if FExpand = true then
          FButtonImage.Picture.Bitmap.LoadFromResourceName(HInstance, 'ButtonImageUp')
        else
          FButtonImage.Picture.Bitmap.LoadFromResourceName(HInstance, 'ButtonImageDown');
      end;
    cdLeft:
      begin
        if FExpand = true then
          FButtonImage.Picture.Bitmap.LoadFromResourceName(HInstance, 'ButtonImageLeft')
        else
          FButtonImage.Picture.Bitmap.LoadFromResourceName(HInstance, 'ButtonImageRight');
      end;
    cdRight:
      begin
        if FExpand = true then
          FButtonImage.Picture.Bitmap.LoadFromResourceName(HInstance, 'ButtonImageRight')
        else
          FButtonImage.Picture.Bitmap.LoadFromResourceName(HInstance, 'ButtonImageLeft');
      end;
  end;

end;

end.

靠近左侧
左侧打开 左侧关闭

靠近顶部
顶部打开


顶部关闭


看起来不错。但是你没有指定许可证 :-)它是否考虑了同时拥有两个或三个侧边栏并排的选项? - Arioch 'The
@Arioch' 我原以为这段代码已经被默认的StackOverflow CC许可证所覆盖。如果您需要与我不同的许可证,您可以使用"unlicense" http://unlicense.org。我还没有尝试过将多个项目并排放置。我们使用垂直流面板进行堆叠。我们的主编辑屏幕上有10个以上的这些控件,它们被堆叠在一个流面板中,然后再放入一个滚动框中。 - Mark Elder
CC也有许多“版本”。 “我认为该代码受默认的StackOverflow CC许可证保护”-好吧,你可能会这样认为,但是任何试图使用它的人都会面临“宁愿安全也不必遗憾”的问题。 尽管由于时间不足,我可能会坚持使用TCategoryPnel,尽管它不满足我所有的愿望,但我对任何非病毒式FLOSS许可证都没有问题。 - Arioch 'The

5
新版的Delphi将包括这种类型的滑动面板(通过集成FireMonkey,之前是vgScene / dxScene)。您只需单击高度或位置属性,选项将允许为其创建动画,具有各种选项(插值类型、持续时间等)。enter image description here

3
如果OP使用Firemonkey,这将是一个不错的答案。但在VCL应用程序中很难使用FMX控件 :-) - Jerry Dodge
我同意JD的观点。在这里提到Firemonkey没有帮助。 - Gabriel

5
自2009年以来,有一个名为TCategoryPanelGroup的控件,您可以向其中添加TCategoryPanel。
enter image description here

谢谢!“我不需要一个可调整大小的面板,而是需要一个可以水平滑动的面板。” - maxfax
这个不可调整大小...但是,它只能垂直 ;o( - Whiler

3

FoldingPanel
请查看FoldingPanel v1.3:http://www.torry.net/authorsmore.php?id=2386。 我已经使用了好几年了。
它还附带漂亮的chevron位图。
小问题:它不支持复合控件(如TLabeledEdit)。
优点:该组件作为单个PAS文件提供(易于安装到Palette中)。虽然它是针对Delphi 5的,但我已经在XE7上安装并且没有出现问题(这表明了质量)。
免费软件

TSplitView
如果您有新版本的Delphi(例如Tokyo),则可以使用TSplitView。 注意:缺少Align属性。一开始可能会觉得它只能与左侧对齐。但事实并非如此。它没有Align属性,而是有一个Placement属性(有两个值:svpRight / svpLeft)。
注意:它存在一些与控件大小/位置相关的小故障。
注意:它远远不如FoldingPanel完整。你仍然需要编写一些代码来实现某种chevron来折叠/展开面板。
https://www.youtube.com/watch?v=3hUG8o7PpCU
免费软件(如果您有Delphi Tokyo)。

TCategoryPanelGroup
还可以查看TCategoryPanelGroup。它可能有效,也可能无效,取决于您需要什么。
免费软件(如果您有Delphi XE7)


你与我们分享了一个不错的选项。 - user30478

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接