Альтернатива явному вызову метода Loaded для динамически создаваемых экземпляров компонента VCL в Delphi 6? - PullRequest
4 голосов
/ 25 февраля 2012

У меня есть несколько пользовательских компонентов VCL, которые выполняют важные задачи в своем переопределении метода TComponent Loaded ().Это создает неудобства при динамическом создании экземпляров, поскольку метод Loaded () не вызывается глобальным загрузчиком Delphi во время выполнения, как это происходит с компонентами, которые были размещены в формах / фреймах во время разработки.Я также должен разместить переопределение Loaded в разделе public объявления класса, чтобы любой код, который создает экземпляр компонента, мог вызывать его.Наконец, я должен не забыть вызывать Loaded () для динамически создаваемых экземпляров, или незаметные ошибки будут проникать в приложение, и эта проблема уже несколько раз меня кусала.

Есть ли лучшее решение или подход к этому?

1 Ответ

3 голосов
/ 25 февраля 2012

Если вам нужно вызвать Loaded в вашем коде, вы делаете это неправильно. Если вы зависите от стороннего контроля, то я бы установил контроль этого человека. См. Ниже, как.

Позвольте мне привести гипотетический пример: предположим, у меня было 5 опубликованных свойств, которые, после того как все они загружены, могут генерировать сложную кривую или, что еще лучше, генерировать фрактал, что занимает много времени.

Во время разработки я хочу предварительно просмотреть эту кривую, как только она будет загружена, но я не хочу, чтобы кривая 5 раз пересчитывалась во время потоковой передачи DFM, потому что у каждого параметра P1 до P5 (тип Double) есть метод SetP1, который вызывает защищенный метод с именем Changed и перестраивает мою кривую. Вместо этого у меня есть метод SetP1 return, если csDesigning или csLoading находятся в состояниях компонента, и затем я вызываю Changed один раз из Loaded. Ясно, что во всех случаях я не могу полагаться только на методы установки свойств, чтобы вызывать все изменения. Поэтому мне нужно, чтобы Loaded попросил меня выполнить мое первое поколение некоторой дорогостоящей работы, которую я хочу выполнить 1 раз точно, а не N раз, где N - это число DFM-свойств, которые были бы загружены с процедурами набора методов, которые вызвал метод с именем Changed или что-то в этом роде.

В вашем случае во время выполнения вы не должны полагаться на то, что Loaded вызывается вообще. Вместо этого вы должны иметь метод вызова свойства, установленный Changed. Если вам нужен какой-то способ изменить несколько свойств одновременно, а затем сделать какую-то дорогую вещь только один раз, то реализуйте вызов метода типа TMyComponent.BeginUpdate / TMyComponent.EndUpdate и избегайте дополнительной работы.

Я не могу вспомнить ни одного полезного места, где выполнение чего-либо из Loaded имеет какой-либо смысл, за исключением случаев, подобных приведенным выше, которые должны быть специфичны для времени разработки и использования классов на основе DFM. Я ожидал бы, что правильно разработанный TComponent или TControl должным образом инициализируют себя, просто создаваясь в коде и устанавливая его свойства.

Так что для моего гипотетического компонента TMyFractal я бы сделал это при создании его в коде без использования загрузки DFM или при вызове Loaded:

  cs := TMyFractal.Create(Self);
  cs.Parent := Self; {Parent to a form}
  cs.Align := alClient;
  cs.BeginUpdate;
  cs.P1 := 1.03;  // does NOT trigger Regenerate
  cs.P2 := 2.3;
  cs.P3 := 2.4;
  cs.P4 := 2.5;
  cs.EndUpdate; // triggers expensive Regenerate method .
  cs.Show; 

  // later someone wants to tweak only one parameter and I don't want to make them
  // call regenerate:
  cs.P5 := 3.0; // Each param change regenerates the whole curve when not loading or in a beginupdate block.

В моем методе TMyFractal.Change я бы вызывал дорогой метод RegenerateCurve один раз, каждый раз, когда любой коэффициент P1-P4 изменяется во время выполнения, после начальной настройки и один раз точно, когда компонент передается из DFM, где Loaded является используется только для того, чтобы справиться с тем фактом, что я вряд ли могу ожидать, что в моем элементе управления будет указана дата начала / окончания, как я делал бы в приведенном выше коде.

...