Итог

Приведенная выше информация является той базой, от которой можно отталкиваться при создании собственных прикладных модулей. В этом разделе мы только дадим некоторые общие рекомендации по их программированию. Эти рекомендации не обязательны для исполнения, однако они продиктованы соображениями «здравого смысла» к голосу которого грех не прислушаться.

Понятно, что можно писать прикладные модули и в 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

Вам осталось только обобщить этот частный случай на все многообразие жизни, и можно считать, что выход найден.