我正在编写一个程序,该程序由动态创建的面板组成,每个面板都包含一些组件,包括删除和添加面板按钮。每个面板显示的面板编号相差20倍像素,OnClick for add必须将另一个面板添加到集合的末尾,OnClick for delete必须销毁其父级,然后将所有其他面板移动到删除的空间中。我已经尝试过使用数组的方法,但不幸的是,当我在数组中循环删除了一个对象时,我得到了EAccessViolation。
很抱歉,如果这是显而易见的或之前已经得到解答,但我本周早些时候刚刚开始自学OO,所以我不知道所有的术语,或者是否有一个类谎言一个数组,它将为我做这些事情。
答案 0 :(得分: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
答案 1 :(得分:0)
如果使用动态数组并在删除面板时实际删除元素,则可以使用数组策略。或者,您始终可以检查元素是否已分配if Assigned(Array [I])。
但是,使用TComponentList替换阵列解决方案会更好,这样可以更容易地将列表添加到列表中,并且仅适用于此类情况。