Приведенная выше информация является той базой, от которой
можно отталкиваться при создании собственных прикладных модулей. В этом разделе
мы только дадим некоторые общие рекомендации по их программированию. Эти
рекомендации не обязательны для исполнения, однако они продиктованы
соображениями «здравого смысла» к голосу которого грех не прислушаться.
Понятно, что можно писать прикладные модули и в Word и в Excel. Однако это далеко не всегда
оправдано. Как минимум неудобство состоит в том, что для выполнения такого
модуля и просмотра результатов его работы вам придется без конца переключаться
между задачами.
В идеале хорошо было бы запускать прикладные модули прямо из
«О!Пиума». Там предусмотрена такая возможность, но для этого требуется, чтобы
прикладные модули были откомпилированы в EXE файл. Visual Basic for Application,
который используется в Word
и Excel, не позволяет
этого сделать. Для получения EXE
файлов удобнее использовать Microsoft Visual Basic
(далее VB) или другие
языки программирования, поддерживающие «автоматизацию» и позволяющие получать EXE файл. Использование VB имеет некоторые
особенности, о которых мы поговорим дальше. Пока предположим, что нам удалось
получить EXE файл. Для
того, чтобы он стал доступен для запуска из «О!Пиума», его следует положить в
особое место на диске. В системном каталоге Windows находится файл OPIUM.INI.
В секции «[Location]» этого файла есть параметр «PlugIn». Значение этого
параметра указывает на каталог, который является корневым для системы запуска
прикладных модулей «О!Пиума» (Ctrl+R). В этом каталоге можно
размещать исполняемые файлы прикладных модулей. Кроме того, там могут быть
созданы подкаталоги для группировки прикладных модулей по темам. «О!Пиум»
отображает имена каталогов, как раскрывающиеся узлы дерева, а имена файлов без
расширений как доступные для запуска прикладные модули. Отсюда следует, что и
каталогам и EXE файлам
правильнее давать «длинные» осмысленные имена на родном языке. В этом случае
дерево задач будет выглядеть «по–людськи».
Мы, обычно при настройке системы, размещаем прикладные модули в специальном
каталоге на сервере, который затем подключаем как сетевой диск к каждому
рабочему месту. Это обеспечивает единообразный вид дерева задач с каждой машины
и упрощает инсталляцию и обновление списка доступных прикладных модулей. Однако
такой подход имеет свои «подводные камни». Один и тот же прикладной модуль
может быть запущен на разных рабочих местах в одно и тоже время. Никакого
криминала в этом нет до тех пор, пока не найдется модуль, который создает в
процессе работы какой-нибудь свой временный рабочий файл в своем каталоге
запуска. Понятно, что рано или поздно к этому файлу попытается обратиться
каждый запущенный экземпляр приложения. Конфликт неизбежен. Помните об этом при
создании временных файлов или файлов настроек из прикладного модуля. А
вообще–то если вы имеете какие–то соображения в пользу другой стратегии
размещения управляющих модулей, используйте параметр «PlugIn» из OPIUM.INI по своему усмотрению.
Теперь вернемся к VB. Я Вам не скажу ничего нового, если Вы знакомы с
программированием в VB.
Однако если этот документ является Вашим первым учебником по Basic, то я все–таки остановлюсь на
отличиях VBA и VB. Если Вы помните, в главе
посвященной обработке событий мы, для тестирования событий, прежде чем
скопировать код примера в редактор VBA, создавали в нем форму. Но еще раньше, когда мы тестировали
другие функции, мы никакой формы не создавали. На самом деле это иллюзия. Windows–приложение не может выполняться
без окна. Просто тогда в качестве «формы» неявно использовалось окно Excel. В VB никакого такого неявного Excel нет. Поэтому сразу, как
только Вы создаете новый проект, Вы автоматически создаете форму. Именно эта
форма и будет «прицелом» для всяких сообщений (в том числе и системных) и
вместилищем кода для обработки некоторых из них. Другое дело, что Вы можете,
внеся некоторые изменения в свойства («properties»), заставить ее быть невидимой и не отображаться в «Task Bar». Но форма все равно
есть. Текст программы, которая будет работать в этом окне, сплошь состоит из
функций обработки событий. Самое первое событие, которое возникает при запуске
такого приложения — это загрузка формы («Load»). Помещайте в функцию–обработчик этого события код для получения
указателя на opium и другую инициализацию. Напишите функцию, которая
выполняет освобождение указателей, памяти, сохранение параметров, если это
предусмотрено, и другие действия предшествующие завершению программы. Завершите
эту функцию оператором «End».
Создайте обработчик события формы «(Deactivate)» и вызывайте эту функцию
оттуда. Также создайте обработчик события opium «(BeforeClose)»
и оттуда вызывайте эту же функцию. Теперь мы получили «скелет» прикладного
модуля, который ничего «прикладного» не делает, но корректно запускается и
завершается. Дальнейшая Ваша работа сведется к добавлению в форму новых
управляющих элементов, например кнопки «Вычислить» и написанию для события «Click» от этой кнопки
обработчика, который будет читать исходные данные, выполнять вычисления и
записывать результат. Но удобнее написать отдельную функцию для вычислений и
просто вызывать ее из обработчика кнопки. Удобство состоит в том, что вы
сможете вызывать эту же функцию и из обработчиков других событий, которые по
вашему замыслу должны приводить к повторным вычислениям (например, уведомление
об изменении исходных данных). Не бойтесь лишний раз начитывать исходные
данные. Это практически не влияет на скорость работы.
И теперь в отношении событий, которые уведомляют об изменении
исходных данных. Остерегайтесь «зацикливания». Допустим, вы написали модуль,
который отображает значение отсчетов по «АК» в виде таблицы чисел и позволяет
редактировать их. С одной стороны, как только значения в Вашей таблице
изменились, Вам нужно записать «свежий» массив отсчетов по «АК». С другой
стороны, если кто-то еще кроме Вашей программы изменил значение отсчетов по
«АК», вам необходимо отразить эти изменения в таблице. Для того чтобы узнать об
изменениях данных используйте событие ModifyedPLS от opium.
В обработчике этого события проанализируйте имя измененного набора пластов.
Напомню, что имя приходит Вам в качестве параметра. Если это имя равно «АК», то
внесите изменения в таблицу. Вроде все правильно, но… Как только изменится
значение какого-то пласта в Вашей таблице, Вы тут же попытаетесь отобразить это
изменение на экране. Для этого Вы запишите измененный набор пластов и попросите
«О!Пиум» перерисовать экран. До этого момента все было хорошо, но как только
«О!Пиум» запишет новый набор пластов «АК», он тут же пошлет всем, в том числе и
Вашей программе, уведомление о том, что отсчеты по «АК» изменились. Ваша
программа изменит данные в таблице и попытается отобразить это изменение на экране. Для этого Вы запишите
измененный набор пластов и попросите «О!Пиум» перерисовать экран. До этого
момента все было хорошо… «Ctrl+Alt+Delete».
Как бороться? Во–первых, при проектировании программы
старайтесь избегать столь неприятных мест в принципе. Если же постановка задачи
такова, что без этого не обойтись — поступайте так:
На внешнем уровне (перед самой телом первой процедуры)
опишите переменную–флаг:
Dim SaveEnable As Boolean
В процедуре инициализации (обычно это Form_Load()) поместите
строку:
SaveEnable=True
В начало функции,
которая выполняет обновление таблицы при изменении данных (скорее всего это
обработчик opium_ModifyedCRV()), вставьте:
If SaveEnable=False Then
SaveEnable=True
Exit Sub ‘если флаг сброшен то
ничего не надо делать
End If
Теперь в тело функции, которая обновляет экран «О!Пиума» при
изменении в таблице, перед вызовом записи (например, opium.PLSPut “АК”, dataAK)
вставьте:
SaveEnable=False
Вам осталось только обобщить этот частный случай на все многообразие жизни, и можно считать, что выход найден.