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

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

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

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

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

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

person pnieradko    schedule 16.10.2020    source источник
comment
Используйте класс коллекции   -  person David Heffernan    schedule 16.10.2020


Ответы (1)


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

Используйте 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.
person Remy Lebeau    schedule 16.10.2020
comment
Хорошо, это работает, но как я могу получить выбранную панель, когда я могу ее удалить? У меня есть панель, правка и кнопка для удаления панели с ресурсами. - person pnieradko; 17.10.2020
comment
@pnieradko неясно, чего вы хотите, поскольку вы не показали этого в своем вопросе. Но если, например, Button является дочерним элементом Panel, то просто используйте свойство Button Parent, чтобы найти Panel. - person Remy Lebeau; 17.10.2020
comment
Если у меня напр. 5 панелей с редактированием и кнопкой удаления, и я хочу удалить только одну с помощью кнопки, тогда как я могу удалить только одну панель? Можно ли сделать тег на кнопке? - person pnieradko; 17.10.2020
comment
@pnieradko Опять же, вы не даете понять, есть ли 5 ​​кнопок, по одной на каждой панели, или 1 кнопка на самой форме. Если первое, то я уже ответил на это в своем последнем комментарии. Пожалуйста, отредактируйте свой вопрос, чтобы точно показать код, с которым у вас возникли проблемы. - person Remy Lebeau; 17.10.2020
comment
@pnieradko, тебе не нужен список кнопок. И панель, а не форма, должна быть владельцем кнопки. Тем не менее, просто поместите код, который я уже дал вам ранее, непосредственно в обработчик события OnClick. Отправитель — это кнопка, на которую нажали, просто приведите отправителя к TButton, а затем приведите его владельца к TPanel. Я обновил свой ответ, чтобы показать это. - person Remy Lebeau; 17.10.2020
comment
хорошо, у меня последний вопрос и я ухожу: я хочу создать в панели два выпадающих списка, когда панель будет создана, в первую панель будет добавлен пример: категории чего-либо. Когда первый флажок будет изменен, во втором поле со списком будут отображаться значения категории - подкатегории. я обновил вопрос - person pnieradko; 18.10.2020
comment
@pnieradko это не дискуссионный форум, это сайт вопросов и ответов. Ответ на ваш первоначальный вопрос дан. То, о чем вы спрашиваете сейчас, является совершенно новым вопросом. Пожалуйста, верните этот вопрос к тому, что было раньше, а затем опубликуйте новый вопрос. Кроме того, рассмотрите возможность использования TFrame вместо TPanel. Затем вы можете спроектировать его визуально, как TForm, и выполнять любую логику, которая вам нужна, внутри фрейма, а затем создавать несколько экземпляров фрейма по мере необходимости. - person Remy Lebeau; 18.10.2020