:: Главная :: База знаний :: Встречи :: Сайт М. Дроздова :: Файловый архив :: Книга по VFP 9 :: Русский Help Online :: OFF-LINE Форум | ||
Лисоводы всех стран, объединяйтесь !!! |
Макроподстановка | |||
---|---|---|---|
Владимир Максимов Автор Сообщений: 14098 Откуда: Москва |
Автор: Максимов В.
Дата: 06.11.2010 Последнее изменение: 21.11.2010 Макроподстановка Формирование параметра команды в случае, если синтаксис FoxPro не предполагает его наличия Использование условных операторов. Ветвление кода Выражение имени. Скобки Формирование имени объекта Функция GetPem() Коллекции объектов Метод SetAll() Формирование значения или выражения для его вычисления Формирование символьных строк Сложение и вычитание символьных строк Функция TextMerge() Текстовые скобки Text…EndText Функция Evaluate() Формирование команды Использование макроподстановки Особенности использования макроподстановки Восстановление исходных настроек среды Настройка SET FILTER Формирование команды Select-SQL Другие команды и функции, связанные с макроподстановкой Макроподстановка нескольких строк кода. Функция ExecScript() Методы системного объекта _VFP Метод _VFP.Eval() Метод _VFP.DoCmd() Метод _VFP.SetVar() МакроподстановкаМакроподстановка – это одна из тех вещей, которые достаточно просто понять на практике, но довольно сложно дать определение «словами». Типичные примеры использования макроподстановки выглядят примерно так
С точки зрения FoxPro в процессе выполнения данных примеров код примет вид
Т.е. в процессе выполнения произойдет замена ссылки (переменной) на собственно значение. Понятно, что значение переменной может формироваться динамически, в зависимости от ряда условий или диалога с пользователем. Причем формироваться не на этапе компиляции программы, а непосредственно в процессе исполнения. Тогда определение макроподстановки можно выразить примерно такими словами
Другими словами, на этапе написания кода заранее неизвестно, какой именно код будет исполняться. Это уточняется в процессе исполнения. За это свойство макроподстановки его очень любят новички, поскольку они всегда склонны писать некие «универсальные» (на все случаи жизни) алгоритмы. Однако опытные программисты относятся к макроподстановкам более сдержано. Как правило, по следующему принципу
Почему, собственно? Пожалуй, здесь подойдет такая аналогия. Представьте себе, что Вы решили купить какую-нибудь «мелочевку», ну, там, салфетки или карандаш. В общем, то, что стоит «копейки». Будете ли Вы расплачиваться крупной купюрой в несколько тысяч? Ну, можно, конечно, только Вы рискуете получить на сдачу мешок железной мелочи, который еще непонятно куда девать. А если все-таки решите пересчитать всю эту мелочь, может оказаться, что Вас обсчитали. Не обязательно по злому умыслу, просто попробуйте точно пересчитать такую гору мелочи. Т.е. макроподстановка, зачастую, это «слишком много». Инструмент, не адекватный поставленной задаче. Нет, она, конечно, задачу решает, но затрачивает на ее решение избыточное количество ресурсов, при этом повышая риск возникновения ошибки. Опытный программист, по возможности, старается платить за «покупку» ровно столько, сколько она стоит, чтобы не ждать сдачи и не заниматься ее пересчетом. Т.е. использовать инструмент, который специально создан для решения конкретной задачи. Данная статья как раз и посвящена тому, какие есть альтернативы макроподстановке, а также что и в каких случаях лучше использовать. Для новичков проблемой является тот факт, что макроподстановка – это универсальный инструмент, ну, как «газовый (разводной) ключ». А ее альтернативы – это довольно большой набор «комплекта ключей». Т.е. альтернативны макроподстановке – это узкоспециализированные инструменты, приспособленные для решения довольно ограниченного круга задач. Новичку проще таскать с собой (изучить) один инструмент, чем несколько. Следует отдавать себе отчет в том, что хотя, как правило, при помощи макроподстановки делается вставка некоего фрагмента команды, но, с точки зрения FoxPro, формируется вся команда целиком. По вполне понятной причине. Заранее просто невозможно сказать, какие именно опции (части) формируемой команды включены в макроподстановку. С другой стороны, альтернативы макроподстановки как раз интерпретируются FoxPro именно как части команд. Некие «параметры». Чтобы как-то структурировать все дальнейшие объяснения, стоит выделить наиболее типичные случаи использования макроподстановки Как правило, макроподстановки используют в следующих случаях
Вот и посмотрим, какие есть альтернативы при решении данных задач Формирование параметра команды в случае, если синтаксис FoxPro не предполагает его наличияВ синтаксисе FoxPro многие команды не предполагают наличие параметра, хотя это часто необходимо. Типичные случаи - это все команды SET, все команды работы с файлами (USE, MODIFY, COPY, APPEND и т.п.) и ряд других случаев. В зависимости от того, о какой команде и каком «параметре» идет речь, существуют различные альтернативы макроподстановке. Использование условных операторов. Ветвление кодаДовольно часто в программном коде возникает необходимость установки или восстановления некоторых глобальных настроек в заранее заданное значение. Однако большинство команд настроек не предусматривают указания параметра. Там просто ставится конкретное значение. Например, ON или OFF. Как же поступить, если надо задать конкретное, заранее известное значение? Команды SET в подавляющем большинстве случаев имеют всего два возможных значения. Как правило, это значения ON или OFF. Поэтому вместо макроподстановки можно использовать оператор IF. Примерно так
Как видите, все просто. Если текущее значение настройки отлично от того, которое нужно, то просто делаете эту настройку без макроподстановки. Выражение имени. СкобкиВо многих случаях требуется сформировать имя чего-либо в качестве «параметра», когда команда FoxPro не предусматривает наличия параметра. Типичные случаи подобных ситуаций – это команды USE, COPY TO, REPLACE. Для данных ситуаций существует, так называемое, «выражение имени». Это обычные круглые скобки. Их использование выглядит следующим образом
Выражение имени (круглые скобки) можно рассматривать как некий усеченный вариант макроподстановки, но такой, который в результате своей работы формирует имя чего-либо. Отсюда и название «выражение имени». Т.е. выражение, формирующее имя. Чем выражение имени лучше «обычной» макроподстановки? Основное преимущество – это более высокая определенность кода. Во-первых, очевидно, что за выражением имени «скрывается» одно значение. Один «параметр» команды. При использовании макроподстановки – это далеко не очевидно. Ведь макроподстановка может включать в себя еще набор каких-либо дополнительных опций команды. Для выражения имени это просто исключено. Во-вторых, очевидно, что за выражением имени «скрывается» именно имя чего-либо, а не какая-либо опция команды. Что, опять же, не очевидно для макроподстановки. Есть еще некоторые дополнительные преимущества использования выражения имени. Но это уже из разряда приятных дополнений.
Подробнее про пробелы в именах можно почитать здесь Как работать с путями доступа и именами файлов, содержащих пробелы Однако следует понимать, что выражение имени можно использовать только в том случае, если формируемый «параметр» состоит только и исключительно из имени. Например,
Здесь «параметром» является выражение «MyField=1», но никак не имя. Поэтому использовать здесь выражение имени просто невозможно. У данной команды нет «параметра» «имя», а применить выражение имени, к части «параметра» (только для имени поля) – невозможно. Формирование имени объектаЗачастую, возникает необходимость сформировать имя объекта, но не для какой-либо команды, а для получения доступа к свойствам и методам нужного объекта. Другими словами, получить ссылку на объект, имя которого будет сформировано динамически. Как правило, речь идет о каких-либо объектах на форме. Например, об определенном столбце Grid или определенном объекте TextBox. Функция GetPem()Данная функция идеальный вариант замены макроподстановки в случае, если Вам надо получить ссылку на какой-либо конкретный (одиночный) объект по его имени.
Однако в случае перебора многих объектов это не очень-то удобно. Но для этого случая есть другие варианты Коллекции объектовДело в том, что каждый объект-контейнер FoxPro содержит в себе две специальные коллекции вложенных объектов. В обязательном порядке будет существовать коллекция с именем «Objects» и еще одна коллекция, имя которой будет зависеть от типа объекта-контейнера: Как следствие, можно организовать перебор объектов в коллекции. Либо просто по номерам, используя цикл FOR…ENDFOR, либо циклом FOR EACH. Например, перебрать все объекты Column в Grid можно следующими способами
Метод SetAll()Довольно часто совсем не нужно знать конкретное имя объекта. Нужно просто установить значение определенного свойства для всех объектов нужного типа в объекте-контейнере. Ну, например, установить для всех объектов TextBox на форме значение ReadOnly=.F. можно следующим способом
Установить для всех объектов Column в Grid свойство DynamicBackColor таким образом, чтобы цвет фона записей чередовался с белого на зеленый
Метод SetAll позволяет просто отказаться от ручного перебора объектов и, как следствие, от необходимости указания имен конкретных объектов. Хотя, конечно, если надо установить значение свойства по принципу «все, кроме», то без перебора все-равно не обойтись. Впрочем, если эти самые «кроме» созданы на базе другого класса, то можно и без перебора. Но это уже детали реализации. Формирование значения или выражения для его вычисленияНаиболее типичный пример данной задачи – это формирования символьной строки с неким сообщением. Как правило, текст этого сообщения формируется из фрагментов, которые могут находиться в разных полях и переменных. Впрочем, бывает необходимо формировать не только текстовые строки. Формирование символьных строкС этой задачей сталкивались практически все. Существует довольно большое количество вариантов ее решения. Строго говоря, как правило, никому в голову не приходит формировать текстовую строку через макроподстановку, просто потому, что есть очевидные и более простые способы. Однако макроподстановка просто невозможна без предварительного формирования символьной строки. Именно поэтому способам формирования символьных строк в данной статье посвящено относительно много места. Как некоему предварительному этапу макроподстановки или ее аналогов. Сложение и вычитание символьных строкСимвольные строки в FoxPro можно складывать и вычитать.
Результат этой операции будет простое «сложение» или конкатенация символьных строк. Т.е. к концу первой строки будет добавлена вторая строка «как есть». В результате получим lcString = “Начало строки окончание строки” Символьные строки можно еще и «вычитать» lcString = “Начало строки ” - “ окончание строки” Результат этой операции будет «сложение» или конкатенация символьных строк, однако все концевые пробелы каждого «слагаемого» будут перенесены в конец итоговой строки. Т.е. в результате получим
Операцией вычитания редко пользуются, поскольку большинство складываемых строк обычно не имеют ведущих пробелов. Как следствие, при выполнении операции вычитания символьных строк начало второй части просто сольется с окончанием первой. Между ними не окажется пробела. Естественно, в качестве слагаемого можно использовать не только символьные константы, но и поля таблиц. Единственное ограничение заключается в том, что значение поля должно быть преобразовано в символьный тип данных. В большинстве случаев с этим с успехом справляется функция TransForm()
Однако есть много других функций для преобразования в символьный тип данных: STR(), DTOC(), TTOC(), CAST() Функция TextMerge()Явное преобразование содержимого поля в символьный тип данных, конечно, хорошо, но удобнее пользоваться для этой цели функцией TextMerge()
Т.е. здесь прямо внутри символьной строки в окружении специальных символов пишется имя поля и функция TextMegre() автоматически преобразовывает его содержимое в символьный тип данных, вставляя этот текст вместо имени поля Текстовые скобки Text…EndTextВ случае если необходимо написать большой текст, занимающий несколько строк, то удобнее пользоваться текстовыми скобками Text…EndText. Все, что находится внутри них, воспринимается как обычный текст, а не программный код
Как видите, нет необходимости в дополнительных кавычках и как-либо формировать перенос строк. Вы пишите текст так, как будто вы его пишите в текстовом редакторе. Ну, а специальные «скобки» в сочетании с опцией TEXTMERGE позволяют вставлять в текст содержимое полей таблицы. Функция Evaluate()Иногда надо не просто сформировать текстовую строку, но вычислить некое значение любого типа. В этом случае лучше использовать функцию Evaluate()
Формирование командыВ большинстве случаев, это как раз та ситуация, когда нет альтернативы использования макроподстановки. В простейшем случае, это выглядит так.
Однако в данном случае следует серьезно подумать о необходимости использования подобной макроподстановки. Слишком уж «не прозрачным» становится код. Совершенно не понятно, что скрывается за макроподстановкой. Может быть, имеет смысл разбить макроподстановку на две части?
На практике, разумеется, в качестве команды выступают боле сложные команды. Обычно это команды Select-SQL. Но об этом чуть ниже. Использование макроподстановкиНесмотря на все приведенные ранее примеры, тем не менее, есть ситуации, когда без макроподстановки просто не обойтись. Не то, чтобы это было в принципе невозможно, просто решение без макроподстановки будет более громоздким. Ниже приведены наиболее типичные случаи, когда макроподстановка оправдана. Разумеется, приведенными примерами далеко не исчерпывается список случаев ее использования. Просто все прочие варианты использования относительно редки. Особенности использования макроподстановкиПрежде чем описывать случаи использования макроподстановки следует остановиться на некоторых особенностях самой команды макроподстановки. Основной особенностью использования макроподстановки является тот факт, что первая точка после символа макроподстановки интерпретируется не как разделитель объектов, а как символ «сложения» того текста, который стоит «внутри» макроподстановки и текста, следующего за символом точки.
Текст ошибки будет звучать примерно так: Объекта «TextBox1ReadOnly» не существует. Как видите, символ первой точки просто «прибавил» к содержимому макроподстановки все то, что следовало за ним. Как же определяется окончание того фрагмента, который должен быть «прибавлен» к содержимому макроподстановки? «Сложение» будет идти до тех пор, пока не встретится еще один символ точки или любой другой символ, означающий окончание опции (фрагмента) команды (пробел, равенство, запятая и т.п.). Как следствие, если необходимо избежать подобного «сложения», то просто ставят две точки подряд
При таком синтаксисе, к содержимому макроподстановки «прибавляется» пустая строка, поскольку после первой точки и до второй – ничего нет. А вторая точка уже служит обычным разделителем имен объектов. Восстановление исходных настроек средыПравилом хорошего тона считается восстановление исходных настроек среды, после того, как с ней закончили работать. Разумеется, дело тут не просто в хороших манерах, а в том, чтобы вернувшись, например, в родительскую форму после работы в дочерней форме не получить ряд проблем из-за изменившихся в дочерней форме настроек среды окружения. Как уже было показано ранее, очень многие настройки среды могут принимать только одно из двух значений и их можно восстановить без макроподстановки простым ветвлением кода. Однако далеко не все. Например, настройку ON ERROR
Здесь просто нет вариантов, поскольку «параметром» для настройки ON ERROR выступает никак не «имя» и не «выражение». В данном случае «параметром» является команда. А для команды нет альтернативы. Аналогичное правило действует и в отношении любых других настроек, если «параметр» настройки нельзя свести к ограниченному набору значений, имени чего-либо или выражению. Нет, разумеется, и здесь есть варианты решения без макроподстановки, но довольно громоздкие. Например, как можно было бы решить вопрос с ON ERROR? Да очень просто. Сделать процедуру, которая бы по содержимому переменной lcOldError выполняла бы соответствующую настройку. Ну, примерно так
Но, Вы представляете себе эту «простыню»? Т.е. сколько строк кода должно быть в подобной процедуре? Это не говоря о том, что процедура ON ERROR может быть контекстно-зависимой, т.е. привязанной к какому-либо объекту, ссылку на который тоже придется передавать в эту процедуру. В общем, мороки много, а толку мало. Макроподстановка в данном случае предпочтительнее во всех смыслах. Настройка SET FILTERВообще-то, настройка SET FILTER не обладает достаточной гибкостью. Как следствие, годится только для довольно простых случаев фильтрации, когда надо «по-быстрому» решить очередную «хотелку» пользователя. Если данная задача впоследствии «обрастет» дополнительными требованиями, то, скорее всего от SET FILTER придется отказаться в пользу запросов. Просто SET FILTER не справится с возросшими требованиями. Тем не менее, в простых случаях SET FILTER может оказаться полезным. Как правило, фильтрация осуществляется на основании некоего значения, введенного в объект на форме. Поэтому условие фильтра обычно выглядит так
И это работает. Более того, при изменении значения TextBox1 даже не надо ничего делать, фильтр изменится автоматически. Однако, тем не менее, подобные конструкции лучше не использовать. В чем здесь подвох? Дело в том, что настройка SET FILTER привязана к рабочей области, а вовсе не к форме. Это значит, что если Вы перейдете в другую форму и обратитесь к той же самой рабочей области, то получите сообщение об ошибке вроде «Объект TextBox1 не существует». Действительно не существует. Ведь Вы же перешли в другую форму. В ту, где подобного объекта нет. Но фильтр-то об этом не знает. Он упорно пытается обратиться по тому «адресу», который ему и указали. Разумеется, это можно обойти, создав глобальную переменную со ссылкой на форму. Но это тот случай, когда лекарство хуже болезни. После этого придется предпринимать ряд усилий по контролю над этой переменной и ее своевременным уничтожением. Значительно проще проблема решается при использовании макроподстановки следующим образом
Другими словами, при помощи макроподстановки заменяем ссылку непосредственно значением, содержащимся в этой переменной. Как следствие, настройка SET FILTER оказывается не зависимой от контекста. Она больше не привязана к объектам формы. Правда, небольшим недостатком данной замены является необходимость повторного назначения фильтра при изменении значения в объекте на форме. Но это даже недостатком можно назвать условно. Смотря, с какой точки зрения на это смотреть. Формирование команды Select-SQLЭто один из наиболее часто встречающихся случаев использования макроподстановки. Выглядит примерно так
Здесь также, по сути, нет альтернативы использованию макроподстановки. Список полей, это, конечно же, список имен, однако выражение имени может быть использовано только для одного имени, а не для списка. Запрос, возвращающий одно поле – достаточно редко встречается. Да и при использовании выражения имени придется дополнительно указывать имя поля в результирующей выборке, иначе оно получит имя вроде «Expr_1», ведь было вычислено выражение. В условии отбора использовать Evaluate() тоже не получится. Почему? Ну, кратко это описать затруднительно. Тут несколько причин. В зависимости от того, какое именно выражение необходимо вычислить. Если Вы попытаетесь использовать Evaluate(), то, скорее всего, ошибки это не вызовет, но вот результат запроса окажется далек от ожидаемого. Если и совпадет, то разве что случайно. Здесь еще раз уместно упомянуть тот факт, что даже один символ макроподстановки с точки зрения FoxPro означает формирование команды целиком. Это значит, что будут задействованы все механизмы оптимизации SQL-запросов. Макроподстановка не отключает оптимизацию. Соответственно, можно формировать не части команды, а всю команду сразу
Подобный способ имеет как преимущества, так и недостатки. Преимуществом является тот факт, что в режиме отладки можно посмотреть на сформированную команду (содержимое символьной переменной lcSelectSQL) и понять в чем ошибка (если есть), просто запустив эту команду в командном окне. Недостатком же является отсутствие «наглядности». Совершенно непонятно, как именно сформирована строка макроподстановки. Из каких «слагаемых» она собрана. Другие команды и функции, связанные с макроподстановкойКроме описанных ранее команд и функций следует упомянуть еще ряд команд и функций. Подробно их описывать нет смысла, поскольку документация по ним достаточно полная. Макроподстановка нескольких строк кода. Функция ExecScript()Одним из ограничений макроподстановки является тот факт, что при помощи нее можно выполнить только одну команду. Если Вам необходимо выполнить несколько команд, то Вы вынуждены будете последовательно выполнять по одной команде. Но как быть, например, с операторами цикла или условия? Ведь они состоят из двух команд? Ну, строго говоря, подобных макроподстановок лучше избегать. Это еще более сложная и не однозначная задача, чем «простая» макроподстановка. Тем не менее, в этих случаях поступают следующим образом. Формируется символьная строка, по сути, содержащая фрагмент файла PRG. Затем этот файл компилируется и выполняется. Сделать это можно буквально. Сохранив символьную строку как файл PRG при помощи функции StrToFile(), откомпилировав его командой Compile, и запустив на исполнение командой Do. После этого надо не забыть удалить временный файл с диска и выгрузить его из памяти. Однако то же самое можно проделать не явно, специальной функцией ExecScript(). Фактически, эта функция берет на себя работу этих трех команд. Формирует файл, компилирует его и выполняет. Также эта функция и убирает за собой. Поскольку, по сути, функция ExecScript() выполняет отдельную процедуру, то следует помнить об области видимости переменных, если Вы собираетесь использовать их внутри данной функции. Еще раз напомню, что для FoxPro данная функция еще более «тяжелая», чем обычная макроподстановка. Поэтому, если речь идет об одиночной команде, то, лучше все-таки использовать обычную макроподстановку. Методы системного объекта _VFPСуществуют ситуации, когда необходимо выполнить макроподстановку, но не как команду, а как функцию. Наиболее часто в этом возникает необходимость внутри отчетов, где использование команд просто невозможно. Разумеется, это можно сделать, создав специальную функцию, в которую в виде параметра передавать строку. А внутри функции уже выполнить команду макроподстановки для данной строки. Но эту задачу можно решить при помощи специальных методов системного объекта _VFP Метод _VFP.Eval()Данный метод – это полный аналог функции Evaluate(). Т.е. результат их работы будет полностью идентичен.
Метод _VFP.DoCmd()Данный метод – это полный аналог макроподстановки для целой команды. Т.е. результат их работы будет полностью идентичен.
Метод _VFP.SetVar()Данный метод это аналог присвоения значения переменной через макроподстановку. Причем макроподстановка используется для имени переменной.
Исправлено 1 раз(а). Последнее : Владимир Максимов, 30.11.10 00:25 |
||
© 2000-2024 Fox Club  |