2

I'm writing a panel control that allows the user to mimimize the panel and to hide the components on this panel. A single THidePanel seems to work as expected, but not when I put two of them on a form separated by a splitter. The first panel is aligned alLeft; the second panel alClient:

screen dump

When the second panel's button is clicked, it does not react to minimize or maximize. Here is all of my code. Why doesn't it work?

const
  BoarderSize = 20;

type

TButtonPosition = (topleft, topright, buttomleft, buttomright);

///
/// a panel with a smaller panel inside  and a button on the side
///
THidePanel = class(TPanel)
private
{ Private-Deklarationen }
  ///
  /// a smaller working panel
  WorkingPanel: TPanel;
  FLargeHight: Integer;
  FLargeWidth: Integer;
  FActivateButton: TButton;
  FExpandState: Boolean;
  FButtonPosition: TButtonPosition;
  FOnActivateBtnClick: TNotifyEvent;
  procedure SetButtonPosition(const Value: TButtonPosition);
protected
{ Protected-Deklarationen }
public
{ Public-Deklarationen }
  constructor create(aOwner: TComponent); override;
  procedure WMSize(var Msg: TWMSize); message WM_SIZE;
  procedure HideComponents;
  procedure H_ActivateButtonClick(Sender: TObject);
  procedure SetState(astate: Boolean);
  procedure free;
  destructor destroy; override;
published
{ Published-Deklarationen }
  property OnActivateButtonClick: TNotifyEvent read FOnActivateBtnClick
    write FOnActivateBtnClick;
  property ButtonPosition: TButtonPosition read FButtonPosition
    write SetButtonPosition;
end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [THidePanel]);
end;

{ THidePanel }

constructor THidePanel.create(aOwner: TComponent);
begin
  inherited;
  WorkingPanel := TPanel.create(self);
  WorkingPanel.Caption := 'V01';
  FActivateButton := TButton.create(self);
  FActivateButton.Parent := self;
  FActivateButton.Caption := '<';
  FActivateButton.OnClick := H_ActivateButtonClick;
  FActivateButton.Width := BoarderSize;
  FActivateButton.Height := BoarderSize;
  WorkingPanel.Caption := '';
  FLargeWidth := self.Width;
  SetButtonPosition(topright);
end;

destructor THidePanel.destroy;
begin
  inherited;
end;

procedure THidePanel.free;
begin
  inherited;
  WorkingPanel.free;
  FActivateButton.free;
end;

procedure THidePanel.HideComponents;
var
  i: Integer;
begin
  for i := 0 to WorkingPanel.ControlCount - 1 do
    WorkingPanel.Controls[i].Visible := False;
end;

procedure THidePanel.WMSize(var Msg: TWMSize);
begin
   ///  set inner panel size
   WorkingPanel.Top := self.Top + BoarderSize;
   WorkingPanel.Left := self.Left + BoarderSize;
   WorkingPanel.Width := self.Width - 2 * BoarderSize;
   WorkingPanel.Height := self.Height - 2 * BoarderSize;

   ///  move button
  SetButtonPosition(FButtonPosition);
end;

procedure THidePanel.H_ActivateButtonClick(Sender: TObject);
begin
  /// button is clicked!
  ///
  FExpandState := not FExpandState;
  SetState( FExpandState );

  ///
  if (Assigned(FOnActivateBtnClick)) then
    FOnActivateBtnClick(self);
end;

procedure THidePanel.SetButtonPosition(const Value: TButtonPosition);
begin
  FButtonPosition := Value;

  case FButtonPosition of
    topleft:
    begin
      FActivateButton.Left := 0;
      FActivateButton.Top := 0;
    end;

  topright:
  begin
    FActivateButton.Left := self.Width - BoarderSize;
    FActivateButton.Top := 0;
  end;

  buttomleft:
  begin
    FActivateButton.Left := 0;
    FActivateButton.Top := self.ClientWidth - BoarderSize;
  end;

  buttomright:
  begin
    FActivateButton.Top := self.ClientWidth - BoarderSize;
    FActivateButton.Left := self.Width - BoarderSize;
  end;

  else
  /// never go here

  end;
end;

procedure THidePanel.SetState(astate: Boolean);
begin
  if astate then
  begin
    /// ...
    FActivateButton.Caption := '>';
    self.Width :=  BoarderSize;
  end
  else
  begin
    /// ...
    FActivateButton.Caption := '<';
   self.Width := FLargeWidth;
  end;
end;
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Franz
  • 1,883
  • 26
  • 47
  • In case you don't mind borrowing from an already made component, then take a look at [NLDSideBar](http://stackoverflow.com/a/7266319/757830). – NGLN Apr 09 '13 at 22:01

2 Answers2

7

When Control's Anchors set to alClient, you can not change the size .
Set second panel align to alLeft or alRight . if you want fill form with this control, set AutoSize of form True or manually set max size of your control on resize it .

MohsenB
  • 1,669
  • 18
  • 29
0

Like MohsenB already explained (+1ed), you cannot change the size of a control with Align = alClient. But since you are making this a component, I would choose to change the Align setting of the component temporarily, instead of dealing with this in the designer code: i.e. make it a feature of the component to be able to set its Align property to alClient and let it behave accordingly when situation requires.

I think you are looking for the following enhancements:

unit Unit2;

interface

uses
  Messages, Classes, Controls, StdCtrls, ExtCtrls;

const
  BorderSize = 20;

type
  TButtonPosition = (bpTopLeft, bpTopRight, bpBottomLeft, bpBottomRight);

  THidePanel = class(TPanel)
  private
    FActivateButton: TButton;
    FButtonPosition: TButtonPosition;
    FExpandState: Boolean;
    FOldAlign: TAlign;
    FOldWidth: Integer;
    FOnActivateBtnClick: TNotifyEvent;
    FWorkingPanel: TPanel;
    procedure ActivateButtonClick(Sender: TObject);
    procedure SetButtonPosition(Value: TButtonPosition);
  protected
    function CanResize(var NewWidth, NewHeight: Integer): Boolean; override;
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure SetState(AState: Boolean);
  published
    property ButtonPosition: TButtonPosition read FButtonPosition
      write SetButtonPosition default bpTopRight;
    property OnActivateButtonClick: TNotifyEvent read FOnActivateBtnClick
      write FOnActivateBtnClick;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [THidePanel]);
end;

{ THidePanel }

constructor THidePanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FWorkingPanel := TPanel.Create(Self);
  FWorkingPanel.Caption := '';
  FWorkingPanel.SetBounds(BorderSize, BorderSize, Width - 2 * BorderSize,
    Height - 2 * BorderSize);
  FWorkingPanel.Anchors := [akLeft, akTop, akRight, akBottom];
  FWorkingPanel.Parent := Self;
  FActivateButton := TButton.Create(Self);
  FActivateButton.Caption := '<';
  FActivateButton.OnClick := ActivateButtonClick;
  FActivateButton.Width := BorderSize;
  FActivateButton.Height := BorderSize;
  FActivateButton.Parent := Self;
  SetButtonPosition(bpTopRight);
end;

procedure THidePanel.ActivateButtonClick(Sender: TObject);
begin
  FExpandState := not FExpandState;
  SetState(FExpandState);
  if Assigned(FOnActivateBtnClick) then
    FOnActivateBtnClick(Self);
end;

procedure THidePanel.SetButtonPosition(Value: TButtonPosition);
begin
  if FButtonPosition <> Value then
  begin
    FButtonPosition := Value;
    case FButtonPosition of
      bpTopLeft:
        begin
          FActivateButton.Left := 0;
          FActivateButton.Top := 0;
          FActivateButton.Anchors := [akLeft, akTop];
        end;
      bpTopRight:
        begin
          FActivateButton.Left := Width - BorderSize;
          FActivateButton.Top := 0;
          FActivateButton.Anchors := [akRight, akTop];
        end;
      bpBottomLeft:
        begin
          FActivateButton.Left := 0;
          FActivateButton.Top := ClientWidth - BorderSize;
          FActivateButton.Anchors := [akLeft, akBottom];
        end;
      bpBottomRight:
        begin
          FActivateButton.Top := ClientWidth - BorderSize;
          FActivateButton.Left := Width - BorderSize;
          FActivateButton.Anchors := [akRight, akBottom];
        end;
    end;
  end;
end;

procedure THidePanel.SetState(AState: Boolean);
begin
  if AState then
  begin
    FActivateButton.Caption := '>';
    FOldAlign := Align;
    if FOldAlign = alClient then
      Align := alLeft;
    Width :=  BorderSize;
  end
  else
  begin
    FActivateButton.Caption := '<';
    if FOldAlign = alClient then
      Align := FOldAlign
    else
      Width := FOldWidth;
  end;
end;

procedure THidePanel.Resize;
begin
  if not FExpandState then
    FOldWidth := Width;
  inherited Resize;
end;

function THidePanel.CanResize(var NewWidth, NewHeight: Integer): Boolean;
begin
  Result := inherited CanResize(NewWidth, NewHeight);
  if FExpandState then
    NewWidth := BorderSize;
end;

end.

Testing code:

unit Unit1;

interface

uses
  Controls, Forms, Unit2, ExtCtrls;

type
  TForm1 = class(TForm)
    procedure FormClick(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormClick(Sender: TObject);
begin
  with THidePanel.Create(Self) do
  begin
    Align := alLeft;
    Parent := Self;
  end;
  with TSplitter.Create(Self) do
  begin
    Left := 200;
    Parent := Self;
  end;
  with THidePanel.Create(Self) do
  begin
    Align := alClient;
    Parent := Self;
  end;
end;

end.
Community
  • 1
  • 1
NGLN
  • 43,011
  • 8
  • 105
  • 200