Компонент кнопки, влияющий на родительскую панель в Delphi - PullRequest
1 голос
/ 21 октября 2009

Я пишу программу, состоящую из динамически создаваемых панелей, в каждой из которых есть несколько компонентов, в том числе кнопки удаления и добавления панели. Каждая панель отображает число пикселей, в 20 раз превышающее номер панели, друг над другом, OnClick для добавления должен добавить еще одну панель в конец набора, а OnClick для удаления должен уничтожить его родительский элемент, а затем переместить все остальные панели вверх в пространство, которое удаляется. Метод, который я уже попробовал, включал использование массива, но, к сожалению, я получил EAccessViolation при циклическом просмотре массива, в котором я удалил объект в середине.

Извините, если это очевидно или на него уже был дан ответ, но я только начал учить себя ОО в начале этой недели, поэтому я не знаю всех терминологий или есть класс, похожий на массив, который сделает эти вещи для меня.

Ответы [ 2 ]

4 голосов
/ 21 октября 2009

Это может быть лучше, если вы будете осторожно использовать свойство 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 голосов
/ 21 октября 2009

Вы можете использовать свою стратегию массива, если вы используете динамический массив и фактически удаляете элементы при удалении панелей. Кроме того, вы всегда можете проверить, назначен ли элемент, если назначен (массив [I]).

Тем не менее, было бы гораздо лучше заменить решение массива на решение с использованием TComponentList, которое упростит добавление и удаление панелей в списке и предназначено именно для такого типа ситуаций.

...