Создание, уничтожение и подсчет значений внутри динамических элементов управления в Delphi

#delphi #dynamic-controls

#delphi #динамические элементы управления

Вопрос:

У меня есть вопросы о том, как создавать динамические элементы управления, как уничтожать и как получать значение внутри вновь созданного элемента управления.

Создание и подсчет изменений создание в форме работало корректно, но там, где я создаю изменения в панелях с кнопками для уничтожения выбранной панели (панель [Редактировать, кнопка]), она создается правильно, но подсчет не работает.

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

У меня есть этот код:

 unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TfrmMain = class(TForm)
    btnCreateNewObject: TButton;
    btnCountValues: TButton;
    btnCreateNewPanels: TButton;
    btnAllEditsInPanels: TButton;
    procedure btnCreateNewObjectClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnCountValuesClick(Sender: TObject);
    procedure btnCreateNewPanelsClick(Sender: TObject);
    procedure btnAllEditsInPanelsClick(Sender: TObject);
  private
    dynEdit: TEdit;
    dynPanel: TPanel;
    yposition: integer;
    ypositionpanel: integer;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.btnCountValuesClick(Sender: TObject);
var
  i: integer;
  res: integer;
begin
  res := 0;
  for i := 0 to Self.ControlCount - 1 do
  begin
    if Controls[i] is TEdit then
    begin
      res := res   StrToInt((Controls[i] as TEdit).Text);
    end;
  end;
  ShowMessage(IntToStr(res));
end;

procedure TfrmMain.btnCreateNewObjectClick(Sender: TObject);
begin
  dynEdit := TEdit.Create(Self);
  with dynEdit do
  begin
    Parent := frmMain;
    Width := 80;
    Height := 25;
    Top := yposition;
    Left := 3;
  end;
  yposition := yposition   26
end;

procedure TfrmMain.btnCreateNewPanelsClick(Sender: TObject);
begin
  dynPanel := TPanel.Create(Self);
  with dynPanel do
  begin
    Parent := frmMain;
    Width := 100;
    Height := 40;
    Top := ypositionpanel;
    Left := 120;
    dynEdit := TEdit.Create(Self);
    with dynEdit do
    begin
      Parent := dynPanel;
      Width := 80;
      Height := 25;
      Top := 3;
      Left := 3;
    end;
  end;
  ypositionpanel := ypositionpanel   41;
end;

procedure TfrmMain.btnAllEditsInPanelsClick(Sender: TObject);
var
  i, j: integer;
  res: integer;
begin
  res := 0;
  for i := 0 to Self.ControlCount - 1 do
  begin
    for j := 0 to dynPanel.ControlCount - 1 do
    begin
      if dynPanel.Controls[j] is TEdit then
      begin
        res := res   StrToInt( (Controls[j] as TEdit).Text );
      end;
    end;
  end;
  ShowMessage(IntToStr(res));
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  yposition := 1;
  ypositionpanel := 1;
end;

end.
  
 object frmMain: TfrmMain
  Left = 0
  Top = 0
  Caption = 'frmMain'
  ClientHeight = 500
  ClientWidth = 888
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object btnCreateNewObject: TButton
    Left = 775
    Top = 475
    Width = 113
    Height = 25
    Caption = 'Create new edit'
    TabOrder = 0
    OnClick = btnCreateNewObjectClick
  end
  object btnCountValues: TButton
    Left = 775
    Top = 444
    Width = 113
    Height = 25
    Caption = 'Count all edits'
    TabOrder = 1
    OnClick = btnCountValuesClick
  end
  object btnCreateNewPanels: TButton
    Left = 648
    Top = 475
    Width = 121
    Height = 25
    Caption = 'Create new panels'
    TabOrder = 2
    OnClick = btnCreateNewPanelsClick
  end
  object btnAllEditsInPanels: TButton
    Left = 648
    Top = 444
    Width = 121
    Height = 25
    Caption = 'Count all edits in panels'
    TabOrder = 3
    OnClick = btnAllEditsInPanelsClick
  end
end
  

Комментарии:

1. Используйте класс коллекции

Ответ №1:

Вы выполняете итерацию только через элементы управления редактированием, которые являются прямыми дочерними элементами самой формы или последней созданной панели. Вы не перебираете все панели.

Используйте a TList или другой подходящий контейнер для отслеживания изменений, которые вы создаете динамически, затем вы можете перебирать этот список / контейнер, когда это необходимо. И когда вы будете готовы удалить панель из формы, просто Remove() удалите ее дочерний TEdit элемент из списка, а затем Free() панель, которая освободит TEdit его для вас.

Например:

 unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  System.Generics.Collections;

type
  TfrmMain = class(TForm)
    btnCreateNewObject: TButton;
    btnCountValues: TButton;
    btnCreateNewPanels: TButton;
    btnAllEditsInPanels: TButton;
    procedure btnCreateNewObjectClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnCountValuesClick(Sender: TObject);
    procedure btnCreateNewPanelsClick(Sender: TObject);
    procedure btnAllEditsInPanelsClick(Sender: TObject);
    procedure DestroyPanel(Sender: TObject);
  private
    { Private declarations }
    AllEdits: TList<TEdit>;
    yposition: integer;
    ypositionpanel: integer;
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.btnCountValuesClick(Sender: TObject);
var
  i, res: integer;
  dynEdit: TEdit;
begin
  res := 0;
  for i := 0 to AllEdits.Count - 1 do
  begin
    dynEdit := AllEdits[i];
    if dynEdit.Parent = Self then
      res := res   StrToInt(dynEdit.Text);
  end;
  ShowMessage(IntToStr(res));
end;

procedure TfrmMain.btnCreateNewObjectClick(Sender: TObject);
var
  dynEdit: TEdit;
begin
  dynEdit := TEdit.Create(Self);
  try
    with dynEdit do
    begin
      Parent := Self;
      Width := 80;
      Height := 25;
      Top := yposition;
      Left := 3;
    end;
    AllEdits.Add(dynEdit);
  except
    dynEdit.Free;
    raise;
  end;
  yposition := yposition   26
end;

procedure TfrmMain.btnCreateNewPanelsClick(Sender: TObject);
var
  dynPanel: TPanel;
  dynEdit: TEdit;
  dynButton: TButton;
begin
  dynPanel := TPanel.Create(Self);
  try
    with dynPanel do
    begin
      Parent := Self;
      Width := 200;
      Height := 40;
      Top := ypositionpanel;
      Left := 120;
    end;
    dynEdit := TEdit.Create(dynPanel);
    with dynEdit do
    begin
      Parent := dynPanel;
      Width := 80;
      Height := 25;
      Top := 3;
      Left := 3;
    end;
    dynButton := TButton.Create(dynPanel);
    with dynButton do
    begin
      Parent := dynPanel;
      Width := 100;
      Height := 25;
      Top := 3;
      Left := 100;
      Caption := 'Destroy this pnl';
      onClick := DestroyPanel;
    end;
    AllEdits.Add(dynEdit);
  except
    dynPanel.Free;
    raise;
  end;
  ypositionpanel := ypositionpanel   41;
end;

procedure TfrmMain.DestroyPanel(Sender: TObject);
var
  dynPanel: TPanel;
  dynEdit: TEdit;
begin
  dynPanel := TPanel(TButton(Sender).Owner);
  dynEdit := TEdit(dynPanel.Controls[0]);
  AllEdits.Remove(dynEdit);
  dynPanel.Free;
end;

procedure TfrmMain.btnAllEditsInPanelsClick(Sender: TObject);
var
  i, res: integer;
  dynEdit: TEdit;
begin
  res := 0;
  for i := 0 to AllEdits.Count - 1 do
  begin
    dynEdit := AllEdits[i];
    if dynEdit.Parent <> Self then
      res := res   StrToInt(dynEdit.Text);
  end;
  ShowMessage(IntToStr(res));
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  yposition := 1;
  ypositionpanel := 1;
  AllEdits := TList<TEdit>.Create;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  AllEdits.Free;
end;

end.
  

Комментарии:

1. Хорошо, это работает, но как я могу получить выбранную панель, когда я могу удалить? У меня есть панель, редактирование и кнопка для удаления панели с ресурсами.

2. @pnieradko непонятно, чего вы хотите, поскольку вы не показали этого в своем вопросе. Но если кнопка является дочерним элементом панели, например, тогда просто используйте свойство кнопки Parent , чтобы найти панель.

3. Если у меня есть, например, 5 панелей с кнопками редактирования и удаления, и я хочу удалить только одну с помощью кнопки, то как я могу удалить только одну панель? Могу ли я сделать тег в кнопке?

4. @pnieradko Опять же, вы не разъясняете, есть ли 5 кнопок, по одной на каждой панели, или 1 кнопка на самой форме. Если первое, то я уже ответил на это в своем последнем комментарии. Пожалуйста, отредактируйте свой вопрос, чтобы точно показать код, с которым у вас возникли проблемы.

5. @pnieradko вам не нужен список кнопок. И владельцем Кнопки должна быть Панель, а не Форма. Тем не менее, просто поместите код, который я уже дал вам ранее, непосредственно в обработчик события OnClick. Отправитель — это нажатая кнопка, просто введите отправителя в TButton, а затем введите его владельца в TPanel. Я обновил свой ответ, чтобы показать это.