Domanda

Sto scrivendo un programma composto da pannelli creati dinamicamente in cui ognuno ha alcuni componenti, tra cui un pulsante Elimina e Aggiungi pulsanti. Ogni pannello visualizza 20 pixel volte il numero del pannello uno sotto l'altro, OnClick per l'aggiunta deve aggiungere un altro pannello alla fine del set e OnClick per l'eliminazione deve distruggere il suo genitore e quindi spostare tutti gli altri pannelli nello spazio che elimina. Il metodo che ho già provato riguardava l'uso di un array, ma sfortunatamente ho ottenuto EAccessViolation durante il looping di un array in cui ho eliminato un oggetto nel mezzo di esso.

Mi dispiace se questo è ovvio o è stato risposto in precedenza, ma ho appena iniziato a insegnarmi OO all'inizio di questa settimana, quindi non conosco tutte le terminologie o se esiste una classe come un array che farà queste cose per me.

È stato utile?

Soluzione

Potrebbe essere meglio farlo facendo un uso attento della proprietà Allinea.

Se ho tre pannelli con allineamenti come indicato qui:

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

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

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

E io elimino il secondo, quindi il terzo apparirà automaticamente al suo posto.

Posiziona tutti e tre i pannelli all'interno di un altro controllo genitore (ovvero un altro pannello) per definire cosa "in alto" significa quando diciamo " alTop " ;.

Se vuoi animare l'effetto, dovrai essere leggermente più elaborato. Questo è il tuo obiettivo? In tal caso, sono sicuro che possiamo inventare qualcosa.

Modifica: ho scritto un codice che potrebbe darti alcune idee:

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.

Ed ecco il codice per 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

Altri suggerimenti

È possibile utilizzare la strategia dell'array se si utilizza un array dinamico e si eliminano effettivamente gli elementi quando si rimuovono i pannelli. In alternativa, puoi sempre verificare se l'elemento è assegnato se Assegnato (Array [I]).

Tuttavia, sarebbe molto meglio sostituire la soluzione dell'array con una soluzione che utilizza TComponentList che faciliterà l'aggiunta e l'eliminazione dei pannelli nell'elenco ed è progettata proprio per questo tipo di situazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top