Как это теперь модно писать - Преамбула
В далеком, теперь уже, 1994 году, в свете развития всяких ООП технологий , в том же Turbo Vision, захотелось и мне в Фоксе придумать нечто такое же, пусть, хоть и отдаленно напоминающее сие новаторства. Собственно все сводилось к возможности получения результата функции из внешнего, по отношению к текущему, модуля. Если разработчики дали возможность использовать конструкции
DO Func1 in Module1 |
То почему-то не дали возможности хотя бы сделать так
Do Func1 in Module1 to myVar |
Хотя и такая конструкция, меня не устраивала. Хотелось сделать модуль отвечающий за поведение определенного вида документа, но как получать результат функции их этого модуля или другого без шаманского передергивания с использованием Set Procedure To, которая тогда позволяла использовать только один общий процедурный модуль. Тогда надо было выносить все мелкие общие функции из одного модуля и раскладывать их на кучу мелких. Это мне тоже не нравилось. Оставалось одно – пропадать.
Надо было как-то заставить эти функции держать в связке стека вызовов FoxPro иначе он никак их не хотел находить.
И вот пришло решение, что вызов функции нужно переадресовать тому модулю откуда он должен быть вызван, но как? Да все оказалось проще простого.
Пишем процедурный модуль MODULE1.PRG с небольшим «довеском» , допустим в нем есть некая функция P1
* MODULE1.PRG parameter m.__ if type('m.__')='C' return eval(m.__) endif Procedure P1 Return 1 |
Далее пишем некий главный файл MAIN.PRG (Привет Владимиру Максимову)
* MAIN.PRG
? MODULE1([P1()])
|
На выходе получаем искомое значение 1 которое вернула функция P1 – Ура, у нас получилось !
Изменяем модуль MAIN.PRG на такой
* MAIN.PRG ? MODULE1([P1()]) Procedure P1 Return 2 |
Проверим, что вернет нам наша «шаманская» функция ? А в результате видим – 1. Значит наша функция в MAIN.PRG не сработала ! И правильно, ибо вызов функции идет в модуле MODULE1.PRG в строке EVAL(m.__) – фокс находит функцию в текущем модуле и перестает ее искать где-то еще и возвращает значение нужной нам функции. Ну пробовать, так пробовать. Еще раз меняем файл MAIN.PRG
* MAIN.PRG ? MODULE1([P2()]) Procedure P2 Return 2 |
Прошу заметить, что зайца в шляпе нет, то есть функции P2 в MODULE1.PRG нет. Смотрим,что вернет функция.
Оказывается возвращает значение – 2. Пробуем штатными средствами FoxPro, пишем
DO P2 in MODULE1 |
И получаем ошибку: Procedure "P2" not found – чего собственно и ждали, но в нашем случае такой ошибки нет и функция вернула, значение из модуля MODULE1 , это что же получается Фокс нас обманывает ? Или все-таки мы его? .
Давайте подумаем, а собственно откуда в MODULE1.PRG взялось значение функции P2 ?
Фокс в модуле MODUL1.PRG пытается найти функцию P2 – не находит и переходит по стеку вызовов на ранние вызовы, и что же, находит ее в модуле MAIN.PRG – соответственно значение этой функции он нам и вернет. Проблема побеждена, и в том же 1994 году за полторы недели на коленке был написан склад с использование псевдо-объектности. Жаль исходники потерял, за давностью лет. Но было здорово и быстро.
Ну вот, а теперь собственно - Амбула.
Был у меня некий проект на VFP6 – размер исполняемого файла 3.5 метра – все в одном. Решил я это дело порезать на куски. Ну общие процедурные модули и дополнительные невизуальные классы вынести в отдельный модуль COMMON.APP – сказано – сделано – исполняемый файл уменьшили на 1 метр, осталось 2.5 – из них картинок около 1.5 метров – на все случаи жизни, так сказать. А чего давай и их выкинем из исполняемого файла – вынесем куда-нибудь в IMAGES.APP и пусть там валяются, все равно этот модуль – ну очень редко будет изменяться. Ладно собираем все картинки в новый IMAGES.APP в проекте им даем атрибут Excluded – собираем главный исполняемый файл, предварительно в нем подключаем модуль IMAGES.APP. А вместо картинок видим крестики, это что же теперь на картинках крест поставить ? Ладно начнем думать. Если так картинки не подключаются, давай старым дедовским шаманским способом – переадресуем подключение картинок в IMAGES.APP
В базовом классе Image дописываем в свойство Picture_Assing следующий код
LPARAMETERS vNewVal *To do: Modify this routine for the Assign method THIS.Picture = m.vNewVal if not empty(this.picture) * Если файл не найдет в исполняемом файле или на диске – переадресуем вызов if not file(this.picture) if file("IMAGES.APP") DO "IMAGES.APP" with (this),'picture',this.picture endif endif endif |
Соответственно меняем главный файл для проекта IMAGES, а как без главного модуля ? Даже пустого – APP не слепить.
Процедура может принимать от 3 параметров
1 – ссылка на объект к которому будем цеплять картинку
2 – имя свойства, в нашем случае PICTURE
3 – собственно имя файла картинки
4 – параметр может использоваться для ListBox или ComboBox для свойства Picture(N) – как N
lparameter m.ObjRef, m.cProperty, m.xValue, m.nIndex if pcount() < 3 MessageBox("Это модуль ресурсов",64,_screen.caption) Return .F. endif if vartype(m.ObjRef)='O' ; and vartype(m.cProperty)='C' ; and PEMStatus(m.ObjRef,m.cProperty,5) if vartype(m.nIndex)='N' if m.cProperty='PICTURE' ObjRef.Picture[m.nIndex]=m.xValue else Return ObjRef.WriteExpression(m.cProperty+'[m.nIndex]',[m.xValue]) endif else Return ObjRef.WriteExpression(m.cProperty,[m.xValue]) endif Return .T. endif Return .F. |
Теперь пересобираем APP для картинок – и главный исполняемый файл – и видим все картинки на месте. Ну вот – наконец-то смогли уменьшить размер главного исполняемого файла еще на 1.5 метра – остался метр «живого» кода – теперь можно вздохнуть спокойно.
Используя «потусторонние связи» с переадресацией вызова, оказывается можно много чего получить в Фоксе
Последние обновление: 2005-01-26 09:11
Опубликовал: Пирожков Вадим