2009-10-21 9 views
1

J'écris un programme constitué de panneaux créés dynamiquement qui contiennent chacun quelques composants, y compris des boutons Supprimer et Ajouter un panneau. Chaque panneau affiche 20 pixels fois le numéro de panneau sous l'autre, OnClick pour ajouter doit ajouter un autre panneau à la fin de l'ensemble et OnClick pour supprimer doit détruire son parent, puis déplacer tous les autres panneaux dans l'espace supprimé. La méthode que j'ai déjà essayée impliquait l'utilisation d'un tableau mais malheureusement j'ai eu EAccessViolation lors d'une boucle dans un tableau où j'ai supprimé un objet au milieu de celui-ci. Désolé si cela est évident ou a déjà été répondu auparavant, mais je viens de commencer à enseigner moi-même OO plus tôt cette semaine, donc je ne connais pas toutes les terminologies ou s'il y a un tableau de classe qui fera ces choses pour moi.Composant de bouton affectant le panneau parent dans Delphi

Répondre

4

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 supprimer le second, puis le troisième sautera automatiquement sa place. Il suffit de placer les trois panneaux à l'intérieur d'un autre contrôle parent (c'est-à-dire, un autre panneau) pour définir ce que «top» signifie lorsque nous disons «alTop».

Si vous voulez animer l'effet, vous devrez être légèrement plus fantaisiste. Est-ce votre objectif? Si oui, je suis sûr que nous pouvons trouver quelque chose.

Edition - J'ai écrit un code qui peut vous donner quelques 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 pour le 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 
+0

Cela ressemble à une solution que je vais devoir expérimenter. Un rapide google pour "Align Delphi" m'a renvoyé à ce fil: http://stackoverflow.com/questions/1259849/delphi-how-to-programmatically-adjust-ordinary-ordering-of-components-with-align Il me faudra un moment pour les parcourir et les comprendre aussi. Merci. – BookOfGreg

+0

FYI, votre exemple donne également une erreur EAccessViolation lorsque vous supprimez un objet. Y a-t-il une sorte d'erreur quelque part? Je ne peux pas en trouver un ... – BookOfGreg

+0

Hmm Je ne reçois aucune violation d'accès quand j'ajoute ou supprime ... indépendamment de l'ordre dans lequel je le fais. Pouvez-vous me donner les étapes exactes pour reproduire l'erreur? Est-ce à chaque fois que vous supprimez un panneau, ou seulement le dernier, le premier, ou quoi? Merci... – JosephStyons

0

Vous pouvez utiliser votre stratégie de tableau si vous utilisez un tableau dynamique et supprimez réellement les éléments lorsque vous supprimez des panneaux. Alternativement, vous pouvez toujours vérifier si l'élément est assigné avec si assigné (tableau [I]). Cependant, il serait préférable de remplacer votre solution de tableau par une solution utilisant TComponentList, ce qui facilitera l'ajout et la suppression de panneaux dans la liste et est conçu pour ce type de situation.

Questions connexes