Наследование и скрипты
Всем доброе время суток.
Столкнулся с такой проблемой:
Есть отчет-родитель, в нем бэнды поля и т.д. В отчете есть определенные скрипты.
Есть отчет наследник, в нем все это наследуется.
Если в один прекрасный момент изменить хоть 1-н символ в скрипте наследника (напр. переопределить или добавить обработчик события), то после этого любое изменение скрипта предка ни коем образом не отразится в наследнике.
Сия логика мне немного не понятна.
Что посоветуете сделать в данной ситуации?
Столкнулся с такой проблемой:
Есть отчет-родитель, в нем бэнды поля и т.д. В отчете есть определенные скрипты.
Есть отчет наследник, в нем все это наследуется.
Если в один прекрасный момент изменить хоть 1-н символ в скрипте наследника (напр. переопределить или добавить обработчик события), то после этого любое изменение скрипта предка ни коем образом не отразится в наследнике.
Сия логика мне немного не понятна.
Что посоветуете сделать в данной ситуации?
Комментарии
"... Только помните о следующем: если вы поменяли какое-то свойство (к примеру, цвет) у объекта с замком - оно сохранится в данном экземпляре отчета и изменения в базовом отчете его уже не коснутся. Например: в базовом отчете объект был белым, а в наследованном отчете вы поменяли его цвет на красный. Если теперь зайти в базовый отчет и поменять цвет объекта на зеленый, в наследованном отчете он останется красным. Если бы мы не меняли цвет на красный, то изменение цвета в базовом отчете отразилось бы и на наследованном. Это же касается и текста, и размеров\расположения, и любого другого свойства объекта."
Логика основана на том, чтобы изменения в наследованном отчете не затирались потом изменениями в базовом, которые касаются этого же элемента.
Выход из ситуации - после изменений в наследованном отчете сделать его, в свою очередь, базовым и создать его потомков - какие нужны.
Формы в Delphi можно наследовать. И свойства компонентов у наследников можно переназначать. Но ФУНКЦИОНАЛ формы как класса НАСЛЕДУЕТСЯ. И если требуется изменить работу формы в ее базовом классе, то проблем с этим не возникает.
А что мы видим при "наследовании" отчета? Допустим, добавляю в базовый шаблон обработчик какого-нибудь события. В отчете-наследнике у унаследованного объекта унаследовано и название обработчика. Вроде, логично. Но в скрипте его, естественно, нет (потому, что в свое время у наследованного отчета нужно было реализовать свой функционал и скрипт наследника "накрыл" собой скрипт базового отчета). Это понятно, взяться ему там неоткуда. Наследованный отчет молча отрабатывает, игнорируя такую нестыковочку. Никто никогда не узнает, что в базовом отчете поменялся функционал. Да и вызвать что-то типа inherited нельзя - FastScript просто не умеет этого делать. Он процедурно-ориентированный. Хотя доработать его, я думаю можно. Отработать ключевое слово "inherited", пройдясь по пулу всех скриптов отчетов предков.
Господа разработчики, я думаю, что пробел в механизме наследования отчетов очень серьезный. Чем крыть будете?
Ситуация ясна. Буду дописывать данный кусок наследования.
ЗЫ: про документацию знаю и в данном контексте цитата увожаемого stan5 звучит забавно. Если мы говорим об объекте, то мы подразумеваем что под озвученное правило подподяют не только свойства, но и процедуры обработки событий. А на практике получается, что если любой скрипт в отчете поменяли (вне зависимости от принадлежности к определенному объекту) то замещается не конкретная процедура и даже не скрипты по затронотуму объекту а весь "скрипт" отчета. И если в базовом отчете поменяли скрипт совсем другого объекта, то он таки в наследник и не попадет. Т.е. реальность и документация немного расходятся. :-)
...
А, вообще, наследование штука классная. Овнеру данной фичи большой респект ;-)
ТО Uncle AU: в преферанс играете? :-) Как видите реализацию inherited?
Еще вижу, что надо сделать в FS обработку ключевого слова inherited. При его использовании анализируй тот же список, но начиная с родителя. По-моему, это будет самое сложное место.
Вижу, что если обработчик не найден, надо все-таки ругнуться.
Ну и вижу, что дизайнер придется доработать, чтобы показать эти унаследованные скрипты. А при двойном клике в инспекторе на свойстве события попадать в нужный скрипт (найдя все по тому-же алгоритму скрипт с ближайшей реализацией обработчика).
Что-то разработчики ничего не хотят сказать. Ответьте народу, хочется услышать компетентное мнение.
Сказать честно я не представляю себе как это должно работать.
Допустим в скрипте есть inherited, и что должно происходить при его выполнении, вызываться метод предка, какого, откуда, откуда сприпт должен определить наследником чего именно является этот метод ?
Искать функции в списке предков функцию с таким же именем не очень хороший вариант(такой вариант можно сделать с минимальным кол-вом изменений, но это будет скорее как доработка Репорта , а не скрипта).
Тут нужно подходить с другой стороны, и пример далеко искать не нужно, достаточно взглянуть на реализацию rtti в Delphi
Для начала в с скрипте нужно разделить понятия класса и объекта, которые по сути сейчас являются одним и тем же.
Т.е. класс должен содержать таблицу верт. функций и таблицу членов данного класса(имя и тип), а объект должен хранить сами члены класса(значения) и конечно ссылку на класс.
После этого уже будет не сложно добавить возможность описания классов c возможностью наследования в скрипте.
Дизайнер в это случае придется практически полностью переделывать.
Конечно в подобной реализации есть свои "затыки"
Слово inherited лишь означало бы, что вызываемую функцию надо начинать искать со скрипта предка и при необходимости спускаться глубже. Если после inherited стоит имя конкретной функции, то ищем ее. Если стоит ";", то ищем функцию с именем функции контекста и передаем те же параметры. Это уже серьезная доработка FastScript-а и он уже превратиться в объектно-ориентированный. Оно конечно-же хорошо, только, боюсь, что ждать долго придется.
Только простая компиляция скрипта предка ничего не даст, т.к. при загрузки шаблона FR просто копирует объекты из отчета предка в текущий отчет, а скрипт будет ссылаться на объекты отчета из ParentReport.
Как выход добавить поле для хранения скрипта предка, копировать в него текст скрипта и добавлять все наследованные объекты из текущего отчета(все это нужно делать в момент построения отчета).
Обработку Inherited в скрипте в данным случае придется делать через событие, т.к. скрипт и отчет два разных компонента.
А список не нужен потому, что сейчас FR поддерживает только один уровень наследования
Подобная доработка возможно появится в FR5.
Начинаю делать наследование по схеме uncle AU с небольшими своими изменениями. Уж больно не наглядно получается, куда-то кликаем, чего-то открывается ...
Картина, в принципе, ясна, только есть одно но:
При реализации ключевого слова inherited [назовем это пока так :-)] я отойду от основного проекта FR. Т.к. рано или поздно придется переходить на новую версию и мне нужно будет сливать функционал, то хотелось бы решить это малой кровью. т.е. будет 2-а плана: FR реализует требуемый функционал и мне прийдется отключать свои костыли и перехадить на нативный бренч; FR не реализует то что мы тут бурно обсуждаем и собсна сабж. В любом из исходов меня ждут траблы различной степени тяжести :-). Если есть время\желание поделитесь опытом как спроектировать доработки так, чтоб потом жилось спокойно.
...
ЗЫ: В св-ве ParentReport нашел только имя самого отчета .... может не там смотрю.
Я не так выразился правильней было бы сказать : есть некоторые особенности которые в основном проявляются при наследовании нескольких отчетов(хотя оно не работает и при наследовании от одного шаблона ).
Некоторые объекты пишут данные в PropData в бинарном виде (TfrxChartView например), так вот если Вы к примеру хотите сделать отчет с чартом и в одном из потомков поменяли св-во относящиеся к чарту, то все остальные св-ва уже наследоваться не будет.
Аналогичная ситуация и с внутренними компонентами доступа к данным.
Ну и конечно не стоит забывать что поменяв любое св-во в потомке, дочерние отчеты будут наследовать именно его, даже если в базовом отчете выставить аналогичное значение(а потом пробовать его изменить ... и некоторые так делают, а потом пишут вот у меня наследование не работает ).
backorange
Я хотел сказать FParentReportObject
В Вашем случае можно все сделать даже не трогая FS:
- Добавить репорту функцию InheriteCall (к примеру).
- добавить поле FParentScript, создавать его так же как и FParentReportObject
- копировать текст скрипта из FParentReportObject.Script
- при выполнении скрипта (PrepareScript у Tfrxreport) добавить все объекты с флагом Ancestor в FParentScript(делать это придется в цикле, пробежать по всем FParentScript, .т.е. ParentS := FParentScript; while ParentS <> nil do begin ParentS := FParentReportObject.FParentScript; .. итд ).
- в Report.InheriteCall вызывать функцию с таким же именем (или добавить параметр в которой указывать имя функции) из FParentScript.
Конечно дизайнер придется переделывать, лучшем вариантом тут будет сделать редактор скрипта на вкладках, которые будут открываться по мере необходимости.
И скорость выполнения таких отчетов оставляет желать лучшего.