2009-10-21 89 views
1

父面板我寫由動態創建的面板,每個中有幾個組件,包括刪除和添加面板按鈕的程序。每個面板顯示20個像素乘以面板編號的倍數,OnClick for add必須將另一個面板添加到該集合的末尾,而OnClick for delete必須銷燬它的父級,然後將所有其他面板移動到刪除的空間中。我已經嘗試過的方法涉及到使用數組,但不幸的是,當我循環訪問一個數組並在其中間刪除了一個對象時,我得到了EAccessViolation。Button組件影響德爾福

對不起,如果這是顯而易見的,或者之前已經回答過,但本週早些時候我剛開始教自己的OO,所以我不知道所有的術語,或者如果有一個班會爲我做這些事情。

回答

4

你可能會更好過慎重使用align屬性的這樣做。

如果我有三個面板與路線如下所示:

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

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

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

我刪除第二個,然後第三個會自動彈出到它的位置。

只要將所有三個小組另一名家長控制(即,另一面板)中界定什麼是「頂」是指當我們說「是alTop」。

如果你想動畫的效果,那麼你就必須要稍微票友。這是你的目標嗎?如果是這樣,我相信我們可以想出一些東西。

編輯 - 我寫了一些代碼,可能會給你一些想法:

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. 

這裏是爲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

這看起來像我將不得不嘗試的解決方案。 「Align Delphi」的快速谷歌讓我回到這個線程: http://stackoverflow.com/questions/1259849/delphi-how-to-programmatically-adjust-visual-ordering-of-components-with-align 我需要一段時間才能瞭解它們並理解它們。 謝謝。 – BookOfGreg 2009-10-21 13:10:07

+0

僅供參考,您的示例在刪除對象時也會出現EAccessViolation錯誤。 某處是否有某種錯誤?我無法找到一個...... – BookOfGreg 2009-10-21 15:44:53

+0

嗯,當我添加或刪除時,我不會收到任何訪問違規...無論我在其中執行的順序如何。您是否可以爲我提供重現錯誤的確切步驟?每次你刪除一個面板,或者只是最後一個,第一個,還是什麼?謝謝... – JosephStyons 2009-10-21 16:43:35

0

您可以使用陣列策略如果您使用動態數組並在刪除面板時實際刪除元素。或者,您可以隨時檢查該元素是否分配有Assigned(Array [I])。

但是,使用TComponentList替換陣列解決方案會更好,這樣可以更輕鬆地向列表中添加和刪除面板,並且專爲這種類型的情況而設計。