Регистрация пользовательского фрейма - PullRequest
4 голосов
/ 18 мая 2009

В Delphi 2009, в одном из моих проектов у меня есть пользовательский фрейм с некоторыми элементами управления, который я хочу использовать в качестве базового класса для некоторых других элементов управления. Я хочу зарегистрировать этот фрейм как мастер IDE, который будет доступен в списке «Новые элементы». Когда я добавляю свой недавно добавленный элемент (мой пользовательский фрейм) в проект, я ожидаю, что он:

  1. Показать все свойства и события, которые я добавил в пользовательский фрейм в Инспекторе объектов.
  2. Получите вновь созданный кадр из моего пользовательского кадра, а не из TFrame.

Хорошо, чтобы он отображал мои свойства и события в Object Inspector, я регистрирую пользовательский модуль в IDE. Это не работает должным образом для кадров. К счастью, кто-то упомянул об этом в StackOverflow, и на этот вопрос дан ответ:

Отображение дополнительных свойств потомка TFrame в инспекторе объектов

Затем, чтобы он загружал DFM моего пользовательского фрейма, я добавил InitInheritedComponent в конструктор моего пользовательского фрейма. Примерно так:

constructor TMyFrame.Create(AOwner: TComponent); override;
begin
  inerited;
  if (ClassType <> TMyFrame) and not (csDesignInstance in ComponentState) then
  begin
    if not InitInheritedComponent(Self, TMyFrame) then
      raise EResNotFound.CreateFmt('Resource %s not found', [ClassName]);
  end;
end;

Это не работает! Он по-прежнему создает пустую рамку в конструкторе, а не в моей. Если я не регистрирую пользовательский модуль в IDE, он правильно отображает мой фрейм даже без использования InitInheritedComponent, но дополнительные свойства не отображаются в Инспекторе объектов!

если я изменю источник конструктора на этот ( Замена TMyFrame на TFrame ):

constructor TMyFrame.Create(AOwner: TComponent); override;
begin
  inerited;
  if (ClassType <> TFrame) and not (csDesignInstance in ComponentState) then
  begin
    if not InitInheritedComponent(Self, TFrame) then
      raise EResNotFound.CreateFmt('Resource %s not found', [ClassName]);
  end;
end;

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

Итак, мой вопрос: Каково решение для использования мастера Delphi IDE, который создает производный фрейм из пользовательского фрейма (не формы) с помощью DFM и показывает его дополнительные свойства в Инспекторе объектов?

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

Надеюсь, кто-нибудь сможет прояснить мне эту вещь.

Привет

РЕДАКТИРОВАНИЕ:

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

Ответы [ 5 ]

4 голосов
/ 02 июня 2009

Я довольно подробно исследовал использование TFrames (и связанного с ними наследования) в качестве основы для разработки компонентов и мог бы подробно остановиться на том, что нашел, если это было бы полезно, но мне никогда не приходилось использовать RegisterCustomModule - I просто разработайте непосредственно из TFrames, используя обычное наследование кадров, а затем зарегистрируйте получившиеся «окончательные» версии в стандартном модуле регистрации компонентов. Кажется, это позволяет использовать лучшее из обоих миров (визуальная разработка + наследование, а также палитра компонентов + возможности инспектора объектов).

Однако есть ряд небольших хитростей, которые нужно учитывать, например, как вы называете сам TFrame, следя за тем, чтобы в файлах DFM правильно использовались слова «object» или «наследуемые» в первой строке, и, в общем, я нашел, что очень полезно для стабильности сложных деревьев наследования, чтобы создать "базовый фрейм", который наследует от TFrame, но не добавляет НИЧЕГО к нему ... и затем наследует все остальные оттуда. (Это особенно верно при добавлении опубликованных свойств и т. Д.).

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

2 голосов
/ 02 июня 2009

Да, это может быть сделано!

Я сделал именно то, что вы просите в Delphi 2007 и 2009, и могу сказать, что он работает хорошо для обеих версий независимо от уровня обновления. По пути я столкнулся с некоторыми интересными проблемами, но окончательное решение было очень ясным, если я бился головой о стену в течение дня. Подробнее об этом ниже в моем ответе.

Я поместил свой пользовательский фрейм в пакет времени выполнения, на который ссылается пакет моего компонента designtime. Это было необходимо, чтобы разрешить использование фрейма в приложениях, использующих пакеты времени выполнения, а также чтобы этот же фрейм мог использоваться в других пакетах пользовательских компонентов. Пакет designtime также содержал специальный модуль-эксперт для добавления фрейма в галерею Файл -> Новый -> Другие ... -> «Новые элементы» и для создания пользовательского кода модуля по умолчанию. Эта более поздняя часть была в основном полезной для экономии времени кодирования во время фактического использования и была королевской болью, чтобы получить право. Я записал это на график обучения, так как не смог найти полный пример, соответствующий моей ситуации.

Код от времени разработки ДПК:

requires
  DesignIDE,
  FramePageListD11R,
...
contains
  FramePageListPkgReg in 'FramePageListPkgReg.pas',

И из FramePageListPkgReg

implementation

{$R FramePageListIcons.res}

procedure Register;
  begin
    ...
    RegisterCustomModule(TBaseDisplayFrame, TCustomModule);
    RegisterPackageWizard(TDisplayFrameModuleExpert.Create);
  end;

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

object BaseDisplayFrame: TBaseDisplayFrame
  Left = 0
  Top = 0
  Width = 500
  Height = 300
  HorzScrollBar.Smooth = True
  HorzScrollBar.Style = ssHotTrack
  HorzScrollBar.Tracking = True
  VertScrollBar.Smooth = True
  VertScrollBar.Style = ssHotTrack
  VertScrollBar.Tracking = True
  TabOrder = 0
end

TBaseDisplayFrame = class(TFrame, IDisplayFrameEvent)
private
  FOnPageShow : TDisplayFrameEvent;
  FOnPageHide : TDisplayFrameEvent;
  ...
published
  ...
  property OnPageShow: TDisplayFrameEvent read FOnPageShow write FOnPageShow;
  property OnPageHide: TDisplayFrameEvent read FOnPageHide write FOnPageHide;
end;

Что касается загрузки DFM, мне не нужно было никакого специального кодирования. Я обнаружил, что в Delphi IDE есть ошибка, которая препятствует включению формы в пакет. Я не помню все детали, но проблема была легко решена путем ручного редактирования сгенерированного кода DPK. Вот соответствующая часть ДПК для справки. Я подозреваю, что это ваша главная проблема. Обратите пристальное внимание на часть комментария, так как это важно для включения DFM в пакет.

contains
  BaseDisplayFrameModule in 'BaseDisplayFrameModule.pas' {BaseDisplayFrame: TFrame};

Как только все заработает, вы можете как обычно создавать кадры, а затем изменять файл PAS и DFM для наследования от кадров. Как отметил Джамо, не забудьте заменить «объект» на «унаследованный» в первой строке в DFM. Единственное, что я видел, это то, что имя обработчиков событий в унаследованном фрейме не соответствует типичным соглашениям о присвоении имен Delphi, а скорее происходит от базового класса фреймов. Это чисто косметическое средство, и я не нашел время, чтобы выяснить, есть ли какое-то легкое решение.

Удачи!

1 голос
/ 02 июня 2009

Учитывая вашу реальную цель, вы рассматривали возможность использования встроенных форм вместо этого? Я играл с тем, что вы пытаетесь сделать, используя AppControls TacEmbeddedForm в сочетании с Greatis Form Designer (теперь также доступен в несколько иной форме как TMS Scripter Studio ), с положительными результатами. Пока еще ничего не закончено, но выглядит как многообещающий маршрут для предоставления некоторых функций настройки времени выполнения, которые вы ищете.

1 голос
/ 01 июня 2009

Подозреваю, что это может быть исправлено с помощью Обновление 3 , так как у меня нет проблем с тем, что вы описываете. Я только что создал потомок TFrame, добавил два свойства (логическое и событие), добавил панель и т. Д. Создал новый пакет с указанным зарегистрированным фреймом, установленный пакет, добавил путь к пути поиска.

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

Если это не сработало, я нашел обходной путь, указанный в QC 5230

0 голосов
/ 02 июня 2009

С моей точки зрения, фреймы могут быть чрезвычайно полезным инструментом для разработчика Delphi. Однако я настоятельно рекомендую динамически размещать фреймы на формах (или на других фреймах) (например, из кода, а не из дизайнера форм). Кадры на формах помещаются в инфо DFM, и если вы случайно переместите некоторые кнопки в такой статически размещенный фрейм, Delphi поместит информацию об изменении в формы DFM. Более поздние изменения положения этой кнопки на текущем кадре иногда не будут перенесены в размещенный кадр.

...