Конференция "Начинающим" » Как зарегистрировать TFormClass имея string "TForm2" [D7, WinXP]
 
  • веловня (08.03.17 14:43) [0]
    Привет!
    Есть вопрос:
    В проекте имеется 2 формы, Form1: TForm1 и Form2: TForm2.
    Form1 - auto-create, Form2 - available.
    Как создать Form2 в коде Form1, не регистрируя заранее класс TForm2?
    Т.е. у меня в рантайме имеется на входе string "TForm2", и мне надо в рантайме зарегистрировать формкласс TForm2 имея только эту строку. Форма такая в проекте конечно есть.
    Честно пытался найти, не нашел варианта регистрации TFormClass.
    Нужно мне это для автоматического создания тех форм, которые были открыты в предыдущем сеансе.
  • Игорь Шевченко © (08.03.17 19:28) [1]
    FindClass не предлагать ?
  • Юрий Зотов © (08.03.17 22:44) [2]
    Найти класс по его строковому имени можно лишь тогда, когда он УЖЕ зарегистрирован. Поэтому предлагаю:

    1. При запуске программа регистрирует TForm2, TForm3 и т.д. Для этого нужно только прописать их юниты в uses, больше ничего не требуется.

    2. Далее программа откуда-то из своих настроек читает строковые имена классов ('TForm2', 'TForm3' и т.д.).

    3. А далее - FindClass.
  • Юрий Зотов © (08.03.17 22:48) [3]
    Не уверен, но смутно помню, что классы используемых  в проекте форм, вроде бы, регистрируются  автоматически, без нашего участия. Если это так, то первый пункт - лишний.
  • веловня (09.03.17 00:02) [4]
    В uses конечно Form2 прописана.
    Но, строка:
    TFormClass(FindClass('TForm2')).create(application);
    вызывает ошибку:
    Class TForm2 not found.
  • веловня (09.03.17 00:05) [5]
    Я много искал на эту тему, и самое близкое решение - это регистрация классов:
    RegisterClass(TForm2);
    Но у меня нет класса, у меня есть только строка 'TForm2'.
  • веловня (09.03.17 00:13) [6]
    Т.е. строка:
    Form2:=TForm2.create(application);
    работает.
    Вместо неё в том же месте строка:
    TFormClass(FindClass('TForm2')).create(application);
    не работает.
  • sniknik © (09.03.17 00:20) [7]
    > без нашего участия.
    и также без нашего участия оптимизатор вырежет все что не упоминается в коде... в строках само собой не объекты туда не смотрит.
    ну, возможно.

    > вызывает ошибку:
    > Class TForm2 not found.
    оптимизатор отключи.

    а вообще блаж какая то. почему просто не написать -
    if строка = 'TForm2' then
     TForm2.Create;
    и вообще как работать с неизвестным классом? если у всех общие методы то просто классика ООП, а если нет, ну вот вызываешь ты Create, а он у класса перекрыт и та еще параметры нужны, или вообще другой конструктор определен.
  • веловня (09.03.17 00:34) [8]
    Вот я сделал демо проект:
    http://mail.stavropol-consulting.ru/01.zip
  • веловня (09.03.17 00:43) [9]
    > sniknik

    Это не просто блажь.
    Мне нужно будет добавлять в исходниках:
    if строка = 'TForm2' then TForm2.Create;
    для каждой формы.
    Это ересь пред догматом автоматизации.
  • веловня (09.03.17 00:51) [10]
    Отключение оптимизатора кстати не помогает.
  • Германн © (09.03.17 02:26) [11]

    > веловня   (09.03.17 00:43) [9]
    >
    > > sniknik
    >
    > Это не просто блажь.
    > Мне нужно будет добавлять в исходниках:
    > if строка = 'TForm2' then TForm2.Create;
    > для каждой формы.

    Блажь это или не блажь может быть понятно только после описания задачи.
    А пока сам вопрос блажь. Зачем приспичило
    TFormClass(FindClass('TForm2')).create(application);
    В стандартном приложении написанном на Дельфи нет нужды в таком извращении.
  • Юрий Зотов © (09.03.17 05:16) [12]
    1. Автор хочет, чтобы при старте приложения автоматически восстанавливались все формы, которые были открыты при завершении предыдущего сеанса. Нормальное желание, а никакое не извращение.

    2. Для этого он при закрытии сеанса сохраняет нужную информацию в настройках программы (конечно, в строковом виде - а в каком еще?). Тоже вполне нормальный способ, а никакое не извращение.

    3. Возник вопрос с поиском класса при запуске программы. Все верно, он и должен был возникнуть. См. [2] и код ниже.

    4. Для восстановления состояния программы мало создать все ранее открытые формы. Надеюсь, автор это понимает.

    5. А формы создаются очень просто (см. [2]).

    uses
     Unit2;

    procedure TForm1.FormCreate(Sender: TObject);
    var
     C: TFormClass;
     F: TForm;
    begin
     RegisterClass(TForm2);
     // ... Здесь читаем настройки, а в них - строку 'TForm2'
     C := TFormClass(FindClass('TForm2'));
     F := C.Create(Application);
     F.Show
    end;
  • sniknik © (09.03.17 08:30) [13]
    > Это ересь пред догматом автоматизации.
    с чего это? по тому что тут озвучено "ТЗ", самое то.

    > 1. Автор хочет, чтобы при старте приложения автоматически восстанавливались все формы, которые были открыты при завершении предыдущего сеанса. Нормальное желание, а никакое не извращение.
    у многих так, у меня тоже есть, и ничего подобного не требовалось.

    > 5. А формы создаются очень просто (см. [2]).
    так создать то вроде и не проблема, проблема сделать
    RegisterClass(TForm2);
    без TForm2, только с 'TForm2', т.к. до этого одно просто строка, другое просто описание типа в исходниках, и без этого в скомпилированные обьекты - к использованию в рантайме не попадает.
  • rrrrr © (09.03.17 08:32) [14]
    Я много искал на эту тему, и самое близкое решение - это регистрация классов:

    для этого решения нужно предварительно найти ссылку на класс.
    но когда ты ее получил, ты просто сразу можешь вызвать конструктор без всякой регистрации. тем более что все уже давно зарегистрировано, так как все твои оба класса живут в одном exe.
  • icWasya © (09.03.17 09:40) [15]
    >проблема сделать
    >RegisterClass(TForm2);
    >без TForm2, только с 'TForm2', т.к. до этого одно просто строка,
    После того, как сделаете RegisterClass(TForm2), будет работать FindClass('TForm2').
    Где это сделать - лучше всего в каждом юните, где у Вас описан класс формы, например, TForm2,добавить в самом конце

    initialization
    RegisterClass(TForm2);

  • sniknik © (09.03.17 10:16) [16]
    icWasya ©   (09.03.17 09:40) [15]
    чтобы продать что нибудь не нужное нужно сначала купить что нибудь не нужное, а у "нас"/автора денег нет. © простоквашино.
    т.е. так, как ему, пишет нужно -
    initialization
    RegisterClass(FindClass('TForm2'));


    не работает. ;)
  • ухты © (09.03.17 14:41) [17]
    так как автор хочет то надо регистрировать все что может восстанавливаться, регистрировать как в [15] например
    но согласен с тем что это всё не автоматизация а ерунда )) ифов хватает за глаза
  • ухты © (09.03.17 14:57) [18]
    или ртти использовать, только в д7 все ли как надо отработает уже не в курсе
  • Юрий Зотов © (09.03.17 16:31) [19]
    [15] - хорошее решение.

    > ифов хватает за глаза

    В проекте появилось 10 новых форм. Будем наращивать в IF еще 10 этажей?

    Или используем [15] в сочетании с [12] - и все произойдет автоматически.
  • ухты © (09.03.17 16:37) [20]

    > В проекте появилось 10 новых форм. Будем наращивать в IF
    > еще 10 этажей?
    >
    > Или используем [15] в сочетании с [12] - и все произойдет
    > автоматически.
    а сама регистрация пропишется конечно не руками, .. работы по большому счету столько же, знай себе копируй да правиь названия )
  • Юрий Зотов © (09.03.17 16:49) [21]
    Только для восстановления состояния одного создания форм мало. Как минимум, надо еще восстановить состояние всех компонентов. Это можно сделать так.

    1. При завершении программы пишем все формы в потоки (WriteComponent). Потоки можно хранить, например, в файлах (это будут аналоги DFM).

    2. При запуске программы создаем формы через CreateNew (а не Create) и заполняем их из ранее сохраненных потоков (ReadComponent).

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

    Но еще надо придумать механизм сохранения и восстановления объектов и переменных, не являющихся членами классов. А также придумать механизм сохранения и восстановления объектов, не являющихся потомками TPersistent. И вот две эти задачки могут оказаться гораздо сложнее.
  • Юрий Зотов © (09.03.17 16:53) [22]
    > ухты ©   (09.03.17 16:37) [20]

    Что ж, если к небоскребам Вы относитесь спокойно, то дело Ваше.
  • веловня (09.03.17 20:11) [23]
    Я кусок старого кода переписываю. У меня и так там набралось несколько десятков
    if string='tform2' then tform2.create и т.д.
    Теперь я просто столкнулся с невозможностью зарегистрировать этот класс из строки в рантайме, и никак не могу отказаться от этой идеи.
    А без этого опять нужно помнить, что надо к новой форме добавить очередной if и т.д.
    Опять же по [12] и [15] надо будет не добавлять еще один RegisterClass() в родительскую форму;
    Некрасиво. Неужели нет решения?
  • ухты © (09.03.17 21:31) [24]
    Если бы была возможность регистрации из строки, то в самой такой регистрации особого смысла не было бы, сразу получаешь тип и вперед. Вам не хочется делать регистрацию потому что писать, ифы нет  потому что тоже писать, как же тогда быть..)
    Посмотрите на ртти, может прокатит.
  • Юрий Зотов © (09.03.17 22:20) [25]
    > веловня   (09.03.17 20:11) [23]

    > по [12] и [15] надо будет не добавлять еще один
    > RegisterClass() в родительскую форму


    В том-то и кайф, что в главную форму ничего добавлять или убавлять никогда не придется (кроме uses, конечно). Как сказано в [15], RegisterClass пишется в каждой TForm2 (в секции initialiization), а в главной форме ОДИН раз пишется что-то вроде этого:

    uses
     Unit2;

    procedure TForm1.FormCreate(Sender: TObject);
    var
     ClassNames: TStringList;
     i: integer;  
     C: TFormClass;
     F: TForm;
    begin
     ClassNames := TStringList.Create;
     try  
       // ... Здесь читаем настройки и заполняем ClassNames  
       for i := 0 to ClassNames.Count - 1 do
       begin
         C := TFormClass(GetClass(ClassNames[i]));
         if C = nil then
           continue;
         F := C.Create(Application);
         F.Show
       end
     finally
       ClassNames.Free
     end
    end;


    И этот код никогда не меняется (кроме uses). Добавили в проект новую форму - все автоматом работает (причем, если у новой формы нет регистрации,  то все работает, как обычно). Убрали из проекта форму - тоже все автоматом работает как надо.
  • Юрий Зотов © (09.03.17 22:40) [26]
    Кстати, насчет uses я погорячился - при таком коде uses просто не нужен и его надо убрать. То есть, код в главной форме вообще никогда не меняется - ни при добавлении форм в проект, ни при удалении форм из проекта.

    В отличие от суперIF'ов.
  • Германн © (10.03.17 02:09) [27]

    > Юрий Зотов ©   (09.03.17 05:16) [12]
    >
    > 1. Автор хочет, чтобы при старте приложения автоматически
    > восстанавливались все формы, которые были открыты при завершении
    > предыдущего сеанса. Нормальное желание, а никакое не извращение.
    >
    >
    > 2. Для этого он при закрытии сеанса сохраняет нужную информацию
    > в настройках программы (конечно, в строковом виде - а в
    > каком еще?). Тоже вполне нормальный способ, а никакое не
    > извращение.
    >

    Согласен. В таком варианте это не блажь.
  • sniknik © (10.03.17 08:41) [28]
    > В отличие от суперIF'ов.
    в отличие от них, у вас логика разнесена в 2 места, обработчик и зависимые от него регистрации в каждом модуле, которые "автоматом" дельфей делаться не будут. с точки зрения поддержки очень не хорошо, вот понадобится добавить формочку лет через пять, уже в забытом, почти умершем но кем то еще используемом проекте... - проблема на ровном месте. не говоря уже о том что добавлять можете не вы... хотя это будет уже не проблема, а показатель вашей незаменимости. да.

    если же переносить регистрацию к месту использования, то и там будет что то типа ифов, + а то и дополнение в виде проверки на разовость, чтобы не дублировать регистрации.
    если уж так то почему бы просто не поставить у форм (родителя) невидимость, и пусть все создается/генерится автоматом, и только днлать видимыми необходимые формы... ?

    > Согласен. В таком варианте это не блажь.
    блажь, блажь... у меня сделан тако вариант, и ничего подобного не требовалось, вообще к именам классов привязки нет, просто в общем родителе написал сохранение данных формы, а при старте, по имени форм (не по классу) если запись есть создаю форму - восстанавливаю параметры (это тоже в методе формы).
  • веловня (10.03.17 10:13) [29]
    Мне тоже кажется что если от IFов не избавиться, то лучше их в одной куче держать.
  • sniknik © (10.03.17 10:26) [30]
    напиши что то подобное такому, да пользуйся, проблем меньше ИМХО будет.
    добавлять легко, ничего в каждом модуле лишнего не нужно, как дельфя сгенерит так и пойдет
    procedure TFormMain.ShowForm(const ClassName: string);

     function FindClass(const ClassName: string): TPersistentClass;
     begin
       if ClassName = 'TForm1' then result:= TForm1 else
       if ClassName = 'TForm2' then result:= TForm2 else
       raise EClassNotFound.CreateFmt('Class %s not found', [ClassName]);
     end;

    begin
     with TFormClass(FindClass(ClassName)).Create(Application) do
       try
         ShowModal;
       finally
         Free;
       end;
    end;

  • ухты © (10.03.17 11:34) [31]
    не нравятся ифы (хотя что в них плохого), сделать словарик, потом по имени сразу получать то что требуется
    только и тут придется руками в него заносить, куда ни крути приходится что то писать
  • Eraser © (10.03.17 14:21) [32]

    > Юрий Зотов ©   (09.03.17 16:49) [21]


    > При завершении программы пишем все формы в потоки (WriteComponent)

    а потом новый билд, с каким-нибудь удаленным компонентом, который присутствовал ранее, будет радостно вылетать в трубу при запуске, с не до конца понятными последствиями для продолжения работы приложения.

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

    автору лучше найти готовый велосипед для сохранения настроек GUI, серьезный фреймворки вроде devexp предлагают такие велосипеды.

    что касается сабжа - у автора что там сотня форм в проекте, которые нужно восстанавливать при старте?
  • Eraser © (10.03.17 14:25) [33]

    > WriteComponent

    им бы сделать встроенную сериализацию (по желанию, любых объектов) на базе того же JSON - цены бы не было. но увы.
  • Игорь Шевченко © (10.03.17 15:50) [34]
    Eraser ©   (10.03.17 14:21) [32]


    > а потом новый билд, с каким-нибудь удаленным компонентом,
    >  который присутствовал ранее, будет радостно вылетать в
    > трубу при запуске, с не до конца понятными последствиями
    > для продолжения работы приложения.


    Обычно для этого в сохраненную конфигурацию прописывают ее версию и ничего не вылетает.
  • Eraser © (10.03.17 18:19) [35]

    > Игорь Шевченко ©   (10.03.17 15:50) [34]

    хорошо бы, чтобы новая версия понимала настройки от предыдущей версии.
  • Игорь Шевченко © (10.03.17 22:24) [36]
    Eraser ©   (10.03.17 18:19) [35]


    > хорошо бы, чтобы новая версия понимала настройки от предыдущей
    > версии.


    По-моему, мы уже далеко отходим от темы. Речь идет о сохранении "рабочего пространства", насколько я понимаю, поэтому для разных версий то самое пространство может быть совсем разным. Как например, десктоп у Delphi 7 и 2007.
  • Германн © (11.03.17 02:33) [37]

    > sniknik ©   (10.03.17 08:41) [28]
    >
    > > Согласен. В таком варианте это не блажь.
    > блажь, блажь... у меня сделан тако вариант, и ничего подобного
    > не требовалось, вообще к именам классов привязки нет, просто
    > в общем родителе написал сохранение данных формы, а при
    > старте, по имени форм (не по классу) если запись есть создаю
    > форму - восстанавливаю параметры (это тоже в методе формы).

    Как сформулировал Юра более общую задачу - это не блажь. Как ты решил свою задачу - это другое.
    Но автор вопроса до сих пор не обнародовал свою задачу. Если не считать
  • Германн © (11.03.17 02:34) [38]

    > веловня   (09.03.17 20:11) [23]
    >
    > Я кусок старого кода переписываю.

    веловня   (09.03.17 20:11) [23]

    Я кусок старого кода переписываю.
  • Eraser © (12.03.17 07:02) [39]

    > Игорь Шевченко ©   (10.03.17 22:24) [36]

    да нет, как раз, это по теме. чтобы метод сохранения настроек через Read/WriteComponent дал сбой, достаточно удалить хотя бы одно published свойство. в версии 5.4445.123 оно может присутствовать, а в версии 5.4445.124 какую-нибудь кнопку нужно будет убрать и старые настройки станут бесполезны. если выпускать релизы раз в 2 года может быть ничего страшного и нет, но, зачастую, релизы раз в месяц бывают.
  • веловня (12.03.17 21:56) [40]
    Ну почему же, задачу я обнародовал: регистрация типа формы из строки.
    Очень старый проект. Две сотни форм. Сейчас четверть из них могут авто-открываться. Столкнулся с вопросом регистрации из строки и очень удивился отсутствию решения. А так сделал бы и забыл.
  • sniknik © (12.03.17 23:02) [41]
    > Ну почему же, задачу я обнародовал: регистрация типа формы из строки.
    многие путают задачу и путь решения.

    > Сейчас четверть из них могут авто-открываться. Столкнулся с вопросом регистрации из строки и очень удивился отсутствию решения.
    вот странно, проект очень старый не работающий (раз решения нет), нафига его переписывать? или таки работающий?

    > А так сделал бы и забыл.
    смысл? не делай и забудь. но скажи что сделал...
  • веловня (12.03.17 23:35) [42]
    обычно я так и делаю. просто иногда, когда понижается промиля, я воспринимаю задачу как вызов.
 
Конференция "Начинающим" » Как зарегистрировать TFormClass имея string "TForm2" [D7, WinXP]
Есть новые Нет новых   [118232   +26][b:0][p:0.002]