Question

J'écris un programme constitué de panneaux créés de manière dynamique et comportant chacun quelques composants, notamment des boutons supprimer et ajouter des panneaux. Chaque panneau affiche 20 pixels fois le numéro de panneau l'un en dessous de l'autre, OnClick for add doit ajouter un autre panneau à la fin de l'ensemble et OnClick for delete doit détruire son parent, puis déplacer tous les autres panneaux vers le haut dans l'espace qui en est créé. La méthode que j’ai déjà essayée implique l’utilisation d’un tableau, mais malheureusement, j’ai eu EAccessViolation lors de la lecture en boucle d’un tableau dans lequel j’ai supprimé un objet au milieu de celui-ci.

Désolé si cela est évident ou si on y a déjà répondu, mais je viens juste de commencer à me familiariser avec OO plus tôt cette semaine. Je ne connais donc pas toutes les terminologies ni s'il existe une classe, il y a un tableau qui fera ces choses pour moi.

Était-ce utile?

La solution

Vous feriez peut-être mieux de le faire en utilisant soigneusement la propriété Align.

Si j'ai trois panneaux avec des alignements comme indiqué ici:

|-----------------------|
|                       |
|        alTop          |
|                       |
|-----------------------|

|-----------------------|
|                       |
|        alTop          |
|                       |
|-----------------------|

|-----------------------|
|                       |
|        alTop          |
|                       |
|-----------------------|

Et je supprime le second, le troisième apparaîtra automatiquement à sa place.

Il suffit de placer les trois panneaux à l’intérieur d’un autre contrôle parent (un autre panneau) pour définir le champ "top". signifie quand on dit "tout en haut".

Si vous souhaitez animer l'effet, vous devrez être un peu plus sophistiqué. Est-ce votre objectif? Si oui, je suis sûr que nous pouvons trouver quelque chose.

Modifier - J'ai écrit un code qui pourrait vous donner des idées:

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls;

type
  TWhere = (wAtBeginning, wAtEnd);

type
  TfrmMain = class(TForm)
    panCtrl: TPanel;
    panHost: TPanel;
    btnAddPan: TBitBtn;
    btnDelPan: TBitBtn;
    lbAddWhere: TListBox;
    lbDelWhere: TListBox;
    procedure btnAddPanClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btnDelPanClick(Sender: TObject);
  private
    function GetPanel(HostPanel: TPanel; Where: TWhere): TPanel;
    function BottomOfLastPanel(HostPanel: TPanel): integer;
    procedure AddPanel(HostPanel: TPanel; AddWhere: TWhere);
    procedure DelPanel(HostPanel: TPanel; DelWhere: TWhere);
    procedure DelThisPanel(Sender: TObject);
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.AddPanel(HostPanel: TPanel; AddWhere: TWhere);
var
  pnl: TPanel;
  btn: TBitBtn;
begin
  pnl := TPanel.Create(HostPanel);
  with pnl do begin
    case AddWhere of
      wAtBeginning: Top := 0;
      wAtEnd: Top := BottomOfLastPanel(HostPanel);
    end;
    Align := alTop;
    Parent := HostPanel;
    Caption := DateTimeToStr(Now);
  end;

  btn := TBitBtn.Create(pnl);
  with btn do begin
    Parent := pnl;
    Left := 0;
    Top := 0;
    Width := 100;
    Height := 30;
    Align := alLeft;
    Caption := 'Delete this panel';
    OnClick := DelThisPanel;
  end;
end;

function TfrmMain.BottomOfLastPanel(HostPanel: TPanel): integer;
begin
  //scan through all panels contained inside the host panel
  //return the bottom of the lowest one (highest "top" value)
  Result := 0;
  if Assigned(GetPanel(HostPanel,wAtEnd)) then begin
    Result := GetPanel(HostPanel,wAtEnd).Top + GetPanel(HostPanel,wAtEnd).Height;
  end;
end;

procedure TfrmMain.btnAddPanClick(Sender: TObject);
begin
  case lbAddWhere.ItemIndex of
    0: AddPanel(panHost,wAtBeginning);
    1: AddPanel(panHost,wAtEnd);
  end;
end;

procedure TfrmMain.btnDelPanClick(Sender: TObject);
begin
  case lbDelWhere.ItemIndex of
    0: DelPanel(panHost,wAtBeginning);
    1: DelPanel(panHost,wAtEnd);
  end;
end;

procedure TfrmMain.DelPanel(HostPanel: TPanel; DelWhere: TWhere);
var
  pnlToDelete: TPanel;
begin
  case DelWhere of
    wAtBeginning: pnlToDelete := GetPanel(HostPanel,wAtBeginning);
    wAtEnd: pnlToDelete := GetPanel(HostPanel,wAtEnd);
  end;
  if Assigned(pnlToDelete) then begin
    FreeAndNil(pnlToDelete);
  end;
end;

procedure TfrmMain.DelThisPanel(Sender: TObject);
var
  parentPnl: TPanel;
begin
  //delete the parent panel of this button
  if Sender is TBitBtn then begin
    if (Sender as TBitBtn).Parent is TPanel then begin
      parentPnl := (Sender as TBitBtn).Parent as TPanel;
      parentPnl.Parent := nil;
      FreeAndNil(parentPnl);
    end;
  end;
end;

procedure TfrmMain.FormShow(Sender: TObject);
begin
  lbAddWhere.ItemIndex := 1;
  lbDelWhere.ItemIndex := 1;
end;

function TfrmMain.GetPanel(HostPanel: TPanel; Where: TWhere): TPanel;
var
  i: integer;
begin
  Result := nil;
  for i := 0 to panHost.ControlCount - 1 do begin
    if panHost.Controls[i] is TPanel then begin
      Result := (panHost.Controls[i] as TPanel);
      if Where = wAtBeginning then begin
        Break;
      end;
    end;
  end;
end;

end.

Et voici le code du DFM:

object frmMain: TfrmMain
  Left = 0
  Top = 0
  Caption = 'Add / Delete Panel Demo'
  ClientHeight = 520
  ClientWidth = 637
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnShow = FormShow
  PixelsPerInch = 96
  TextHeight = 13
  object panCtrl: TPanel
    Left = 0
    Top = 0
    Width = 305
    Height = 520
    Align = alLeft
    TabOrder = 0
    object btnAddPan: TBitBtn
      Left = 8
      Top = 8
      Width = 125
      Height = 75
      Caption = 'Add panel'
      TabOrder = 0
      OnClick = btnAddPanClick
    end
    object btnDelPan: TBitBtn
      Left = 8
      Top = 89
      Width = 125
      Height = 75
      Caption = 'Remove panel'
      TabOrder = 1
      OnClick = btnDelPanClick
    end
    object lbAddWhere: TListBox
      Left = 139
      Top = 8
      Width = 150
      Height = 75
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -13
      Font.Name = 'Tahoma'
      Font.Style = []
      ItemHeight = 16
      Items.Strings = (
        'Add to the top'
        'Add to the bottom')
      ParentFont = False
      TabOrder = 2
    end
    object lbDelWhere: TListBox
      Left = 139
      Top = 89
      Width = 150
      Height = 75
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -13
      Font.Name = 'Tahoma'
      Font.Style = []
      ItemHeight = 16
      Items.Strings = (
        'Delete from the top'
        'Delete from the bottom')
      ParentFont = False
      TabOrder = 3
    end
  end
  object panHost: TPanel
    Left = 305
    Top = 0
    Width = 332
    Height = 520
    Align = alClient
    TabOrder = 1
    ExplicitLeft = 392
    ExplicitTop = 264
    ExplicitWidth = 185
    ExplicitHeight = 41
  end
end

Autres conseils

Vous pouvez utiliser votre stratégie de tableau si vous utilisez un tableau dynamique et supprimez les éléments au fur et à mesure que vous supprimez les panneaux. Sinon, vous pouvez toujours vérifier si l'élément est affecté avec si Assigned (Array [I]).

Toutefois, vous feriez bien mieux de remplacer votre solution de tableau par une solution utilisant TComponentList, ce qui facilitera l’ajout et la suppression de panneaux à la liste et est conçue pour ce type de situation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top