Как обратиться к компонентам, созданным во время выполнения, а не в конструкторе форм? - PullRequest
8 голосов
/ 17 декабря 2011

У меня маленькая проблема.Я пытаюсь создать в Delphi7 список компонентов во время выполнения и изменить их размер с помощью события формы .OnResize, но бесполезно ... Я не могу понять, как это сделать.code:

procedure TForm1.Button1Click(Sender: TObject);
var
  //ExtCtrls
  panel: TPanel;
  memo: TMemo;
  splitter: TSplitter;
  list: TListBox;
begin
  panel := TPanel.Create(Self);
  list := TListBox.Create(Self);
  splitter := TSplitter.Create(Self);
  memo := TMemo.Create(Self);

  with panel do
  begin
    Parent := Form1;
    BevelOuter := bvNone;
    Top := 12;
    Left := 12;
    Height := Form1.Clientheight - 24;
    Width := Form1.Clientwidth - 24;
  end;

  with list do
  begin
    Parent := panel;
    Align := alClient;
    Top := 0;
    Height := panel.Height;
  end;

  with splitter do
  begin
    Parent := panel;
    Top := 0;
    Width := 12;
    Align := alLeft;
  end;

  with memo do
  begin
    Parent := panel;
    Top := 0;
    Left := 0;
    Width := round(panel.Width / 4) * 3;
    Height := panel.Height;
    Align := alLeft;
  end;
end;

Нужно ли как-то регистрировать их имена, чтобы использовать их в событии формы?Или, может быть, создать класс и включить их?

Любая помощь очень ценится!Заранее спасибо.

Ответы [ 3 ]

9 голосов
/ 18 декабря 2011

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

type
  TForm1 = class(TForm)
    procedure FormResize(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FPanel: TPanel;
    FMemo: TMemo;
    FSplitter: TSplitter;
    FList: TListBox;
  end;

Тогда ваш обработчик событий FormResize может ссылаться на них.

procedure TForm1.FormResize(Sender: TObject);
begin
  if Assigned(FPanel) then
  begin
    ...
  end;
end;

Не забудьте удалить локальные переменные из Button1Click и использовать вместо них поля.

procedure TForm1.Button1Click(Sender: TObject);
begin
  FPanel := TPanel.Create(Self);
  ...
end;
4 голосов
/ 18 декабря 2011

Несмотря на то, что ответ Дэвида также очень правильный, я подумал, что уделю минутку и углублюсь в некоторые детали.Судя по всему, вы, кажется, очень плохо знакомы с Delphi.У новичков есть очень распространенная проблема, на которую Дэвид не указал в своем ответе, касающийся создания и освобождения этих объектов.Каждый раз, когда вы вызываете «Создать» в классе, в какой-то момент, когда вы закончите с ним, вы также должны «освободить» этот класс.Неспособность освободить что-либо приведет к утечке памяти, и никто не хочет этого.Освобождение так же просто, как создание - пока вы не зайдете в тему ведения списка объектов (который вам сейчас не нужен).

Допустим, вы хотите создать текстовое поле (TEdit) контролировать и поместить его в центр вашей формы.Теперь, во-первых, Delphi IDE позволяет вам просто удалить эти элементы управления в вашей форме, просто убедившись, что вы знаете.Вам не обязательно создавать / освобождать их самостоятельно, если нет какого-то особого сценария.Но делать это опасно.В этом примере мы предполагаем, что этот элемент управления TEdit будет существовать в течение всего времени вашего приложения.

Сначала вам нужно объявить переменную где-то для этого элемента управления.Наиболее разумное место для этого находится внутри класса, где он будет использоваться (в данном случае, ваша форма, которую мы назовем Form1).При работе с переменными (иначе называемыми «Полями») в вашей форме убедитесь, что вы не ставите ничего выше раздела private.Все, что выше private, предназначено для автоматически сгенерированного кода Delphi для всего, что было удалено (и визуально) в вашей форме.В противном случае все созданные вручную вещи должны быть либо под private, либо под public.Область public была бы хорошим местом для вашего контроля ...

type
  TForm1 = class(TForm)
  private

  public
    MyEdit: TEdit;
  end;

Теперь, когда она объявлена, мы должны создать (и освободить) ее.Хорошей практикой является то, что каждый раз, когда вы что-то создаете, вы сразу же помещаете код, чтобы также освободить его, прежде чем продолжить работу.Создайте обработчик событий для событий OnCreate и OnDestroy вашей формы ...

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyEdit:= TMyEdit.Create(nil);
  MyEdit.Parent:= Self;
  MyEdit.Left:= (ClientWidth div 2) - (Width div 2);
  MyEdit.Top:= (ClientHeight div 2) - (Height div 2);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if assigned(MyEdit) then MyEdit.Free;
end;

Если этот объект не создан (до создания или после уничтожения), вы получите «Нарушение прав доступа»при попытке использовать это.Это происходит потому, что ваше приложение пытается получить доступ к области памяти компьютера, которая не выделена или не соответствует типу, который вы хотели получить.

Что ж, это основы для исправления вашего сценария.Однако еще одна вещь, чтобы показать вам.Предположим, вам нужно просто создать объект на короткое время на время процедуры.Для этого есть другой подход.В приведенном выше коде вы объявили свою переменную непосредственно в процедуре.Этот пример покажет вам, когда это необходимо сделать ...

procedure TForm1.Button1Click(Sender: TObject);
var
  MyObject: TMyObject;
begin
  MyObject:= TMyObject.Create;
  try
    MyObject.DoSomething;
    Caption:= MyObject.GetSomething;
  finally
    MyObject.Free;
  end;
end;

Видите ли, пока MyObject будет использоваться только в одном вызове этой процедуры, вы можете объявить егоВот.Но если ожидается, что объект останется в памяти после того, как эта процедура закончена и завершена, то все становится сложнее.Опять же, в вашем случае, придерживайтесь этого в классе, пока вы не познакомитесь с динамически создаваемыми объектами.

В заключение, как уже упоминалось выше, у вас есть возможность разместить TEditконтролируйте прямо в вашей форме во время разработки без написания собственного кода.Если вы делаете это, вам нужно помнить НЕ, чтобы попытаться создать или освободить их.Это также тот случай, когда Delphi автоматически помещает код над разделом private - это когда есть что-то, с чем вы не должны играть.

2 голосов
/ 19 декабря 2011

Я не думаю, что имею право «комментировать», поэтому я формулирую это как «ответ». Если вы хотите изменить размер компонентов времени выполнения, когда их родительский размер изменится, внимательно посмотрите на свойство Anchors. Это может сэкономить вам много работы.

...