Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по Базам данных » VisualFoxPro - Статьи »

Обсудить на форуме Обсудить на форуме

Главный (стартовый) файл проекта

Конечной целью разработки приложения является создание одного (или нескольких) EXE-файла. Но это то, что должно получиться в результате. А на этапе его создания мы имеем большую кучу самых разных файлов (формы, запросы, программные модули, классы и т.п.).

Возникает закономерный вопрос, какой файл из этой кучи в готовом файле EXE должен запускаться первым? А как этот файл выделить (пометить, обозначить)?

Вот этот самый файл, который в готовом файле EXE должен запускаться первым и называется главным (стартовым) файлом. О нем и пойдет речь в данном разделе.

Как выделить (пометить, обозначить) главный файл

На этапе создания готового EXE-файла все наши файлы включаются в общий файл проекта (файлы с расширением PJX и PJT). Файл проекта - это средство как-то упорядочить ту кучу файлов, из которой впоследствии будет собран готовый EXE-файл, а, кроме того, это инструмент собственно сборки EXE-файла.

Так вот, в FoxPro главный (стартовый) файл может быть обозначен только и исключительно внутри файла-проекта. Не существует никаких особых ключевых слов или синтаксических конструкций для его выделения в программном коде.

По умолчанию, первый добавленный в проект файл автоматически становиться главным (если это возможно). Такой файл выделяется в проекте жирным шрифтом.

Если Вас не устраивает такой автоматический выбор, то Вы можете в любой момент указать в качестве главного (стартового) файла нужный Вам файл. Для этого щелкните внутри проекта правой клавишей мыши по нужному файлу и в появившемся меню выберите пункт "Set Main". Выбранный файл будет выделен жирным шрифтом, а файл, ранее обозначенный как главный (стартовый) файл, сбросит свое выделение и станет обычным (не главным) файлом.

В пределах одного файла - проекта может быть только один главный (стартовый) файл

В принципе, допустимо вообще не указывать главный (стартовый) файл. Однако из такого проекта невозможно будет создать готового EXE-файла. На этапе компиляции возникнет ошибка с сообщением о том, что Вы не указали главный (стартовый) файл проекта.

Какой тип файла сделать главным

Главным (стартовым) файлом может быть

  • Программный файл (PRG)
  • Форма (SCX)
  • Меню

Ну, по сути, файл меню - это и есть программный файл. Так исторически сложилось. Точнее, разработчики FoxPro пока "не доросли" до коренной переделки идеологии построения меню, как они это сделали с формами, а в 9 версии и с отчетами.

Дело в том, что хотя на этапе проектирования меню - это файлы с расширением MNT, MNX, но после создания макета меню необходимо запустить его генерацию. Результатом генерации меню становятся файлы MPR, MPX. Вот эти-то файлы и есть обычные файлы PRG и FXP, только с измененным расширением.

Следовательно, по сути, выбор стоит между программным файлом и файлом формы.

Так вот, всегда указывайте в качестве главного (стартового) файла программный файл. Более того, это должен быть именно файл PRG и ничто другое.

Причин этому множество. По мере дальнейшего обсуждения Вы увидите, что очень многое из того, что надо сделать в главном (стартовом) файле очень трудно, а иногда и просто невозможно реализовать в форме.

В принципе, в зависимости от конкретной задачи, часть операций в главном (стартовом) файле, которые будут описаны далее, можно и не выполнять. А оставшиеся операции можно "втиснуть" в форму. Но я не советовал бы этого делать. Программы имеют "привычку" разрастаться. А использование в качестве главного (стартового) файла формы сильно сужает возможность модификации.

Идеология построения приложения

Содержимое главного (стартового) файла проекта зависит в первую очередь от конкретной задачи. Например, если целью Вашего проекта является создание COM-сервера, то в главном (стартовом) файле вообще ничего не будет.

В FoxPro существуют следующие идеологии построения приложений:

  • На базе основного окна FoxPro (SCREEN)
  • На базе "As Top-Level" форм

Построение приложения на базе основного окна FoxPro (SCREEN) предполагает, что в конечном приложении пользователь будет видеть это основное окно (разумеется, со своим меню и ToolBar) и все формы будут открываться внутри этого основного окна.

Построение приложения на базе "As Top-Level" форм предполагает, что основное окно FoxPro (SCREEN) вообще не будет отображаться в конечном приложении. А в качестве основного окна будет выступать созданное программистом окно со свойством ShowWindow = 2 - "As Top-Level form"

Честно говоря, я не вижу особого смысла в построении приложений на базе "As Top-Level" форм. Ведь даже в таком приложении, так или иначе, необходимо будет создать главную форму. А зачем, когда эта форма и так уже есть (основное окно FoxPro)?

Как элемент интерфейса (например, для ввода пароля при входе в программу) "As Top-Level" формы вполне на своем месте. Но строить все приложение целиком на их основе мне представляется неразумным. Да и программно это несколько сложнее. Впрочем, это тема для отдельного обсуждения.

Дальнейшее описание содержимого главного (стартового) файла будет стротиться исходя из предположения, что создается приложение на базе основного окна FoxPro (SCREEN). Впрочем, даже если Вы строите приложение на базе "As Top-Level" форм содержимое главного (стартового) файла останется практически таким же. Отличия будут в некоторых деталях. По мере описания я буду указывать на эти детали.

Точка останова. Read Events

При создании приложения основным управляющим элементом всего приложения является главное меню. Это значит, что в главной (стартовой) программе необходимо сделать вызов этого меню

DO MainMenu.mpr

Синтаксически все абсолютно правильно. Более того, когда Вы будете запускать главный (стартовый) файл на этапе разработки приложения все будет работать нормально. Но вот после того, как Вы создадите готовый EXE-файл и запустите его, то вместо ожидаемого приложения Вы увидите "странный" эффект.

Окно FoxPro мелькнет на экране и тут же закроется.

Причиной такого "странного" поведения является то, что Вы "забыли" указать FoxPro, в каком месте ему надо остановиться и подождать реакции пользователя. На этапе отладки такой "точкой останова" является ранее открытая среда FoxPro. Но в готовом файле EXE до него никакой среды FoxPro открыто не было! Чтобы создать "точку останова" надо дать специальную команду

READ EVENTS

Т.е. содержимое главного (стартового) файла будет выглядеть так:

DO MainMenu.mpr READ EVENTS

Вот теперь, в готовом файле EXE, когда программа дойдет до команды READ EVENTS, то произойдет остановка в ожидании реакции пользователя.

Имейте в виду, что одновременно, во всем приложении может быть активна только одна команда READ EVENTS. Вызов другой команды READ EVENTS не приведет к ошибке, но эта команда будет просто проигнорирована. Чтобы отменить действие команды READ EVENTS надо дать специальную команду

CLEAR EVENTS

По этой команде будет отменено действие команды READ EVENTS и выполнение перейдет на команду, следующую за командой READ EVENTS. Т.е., если Вы дали команду CLEAR EVENTS в какой-либо процедуре, то все то, что стоит следом за этой командой вообще никогда не будет выполнено.

Так, где же давать команду CLEAR EVENTS? Разумеется, в специальном пункте меню "Выход".

Если Вы создаете приложение на базе "As Top-Level" форм, то команду CLEAR EVENTS надо давать в событии UNLOAD Вашей главной формы.

Итого, получается примерно такая логика:

  • Запускается главный (стартовый) файл
  • Активизируется основное меню
  • По команде READ EVENTS организуется "точка останова" для ожидания действий пользователя
  • Команда CLEAR EVENTS прекращает действие команды READ EVNETS, завершает выполнение главного (стартового) файла, что приводит к закрытию приложения FoxPro.

Аварийное прекращение приложения. Настройка ON ShutDown

До сих пор, речь шла о "штатном" завершении. Т.е. когда пользователь дисциплинированно использует все положенные пункты меню для выхода из приложения. Но ведь пользователь может закрыть приложение, нажав на крестик в правом верхнем углу основного окна FoxPro или, например, через окно "Диспетчер задач Windows" (Ctrl+Shift+Esc).

Если все оставить так, как было описано до сих пор, то после такой попытки пользователя выскочит сообщение об ошибке

Cann't quit Visual FoxPro

Причина такого сообщения в том, что осталась активной команда READ EVENTS. Именно она и вызывает такое сообщение об ошибке в описанной ситуации. Чтобы перехватить описанные события закрытия приложения используется специальная настройка

ON SHUTDOWN

В принципе, можно просто написать

ON SHUTDOWN CLEAR EVENTS

Но, обычно перед закрытием приложения надо выполнить ряд предварительных операций. Каких? Это уже зависит от Вашего приложения. Ну, например, можно спросить пользователя о том, действительно ли он хочет выйти из приложения или это у него "рука дрогнула". В общем случае одной команды недостаточно. Нужен вызов процедуры. Например:

ON SHUTDOWN DO MyExitProcedure

И вот уже в этой процедуре MyExitProcedure и надо дать команду CLEAR EVENTS. Причем эта команда должна быть самой последней, поскольку в момент ее выполнения управление будет передано на команду, следующую за командой READ EVENTS и все то, что написано после CLEAR EVENTS просто не будет выполнено.

Для универсальности, желательно в пункте меню "Выход", вместо простой команды CLEAR EVENTS также сделать вызов этой процедуры. Тогда у Вас будет один общий код, обрабатывающий выход из Вашего приложения при любых ситуациях.

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

Однако я все-таки советовал бы вынести эту процедуру в отдельный одноименный файл PRG или в метод некоего глобального объекта. Причина этой рекомендации в том, что отдельный файл или метод класса проще модифицировать.

Если Вы делаете приложение на базе "As Top-Level" форм, то вызов этой процедуры надо организовать еще и в событии QueryUnload главной формы. Точнее так, в событии QueryUnload главной формы надо перенаправить вызов на собственно метод, организующий закрытие всего приложения.

В результате, содержимое главного (стартового) файла приобретает следующий вид

ON SHUTDOWN DO MyExitProcedure DO MainMenu.mpr READ EVENTS

Надо ли давать команду QUIT для закрытия приложения

В FoxPro существует команда QUIT, которая приводит к немедленному закрытию приложения FoxPro. Правда эта команда также перехватывается настройкой ON SHUTDOWN и также по ней невозможно выйти из приложения, если активна команда READ EVENTS.

Возникает резонный вопрос, а нужна ли эта команда, если приложение FoxPro и так само закроется, когда завершится выполнение главного (стартового) файла?

Ну, лично я считаю, что это команда для ленивых программистов. Т.е. для тех, кому лень отслеживать все открытые в приложении объекты. Как я уже упоминал ранее, закрытие приложения в общем случае - это очень не тривиальная задача.

Ну, например, пользователь редактировал какие-либо данные в форме и нажал на крестик или пункт меню "Выход". Следует ли организовать "штатное" закрытие формы или просто "прихлопнуть" все открытые процессы?

По "правильному" логично спросить пользователя желает ли он сохранить внесенные изменения. Т.е. организовать "штатное" закрытие всех открытых объектов. А команда QUIT просто "прихлопнет" все открытые объекты без каких-либо дополнительных вопросов и все!

Есть и более тонкие моменты. Т.е. по хорошему, в процедуре MyExitProcedure надо организовать "штатное" закрытие всех открытых объектов и после команды READ EVENTS (где собственно и предполагается давать команду QUIT) вообще не должно остаться ничего такого, что следовало бы закрывать именно командой QUIT. Если все-таки что-то осталось, то это явная недоработка разработчика. И эта недоработка может очень сильно "аукнуться" в готовом приложении. Без команды QUIT Вы отловите эту проблему еще на стадии отладки приложения.

Кроме того, использование команды QUIT может осложнить отладку. Что, каждый раз после запуска главного (стартового) файла заново открывать среду FoxPro? Впрочем, как это обойти, чуть ниже.

Итого, я не рекомендовал бы использовать команду QUIT.

Как скрыть главное окно FoxPro (SCREEN)

В большинстве случаев, вне зависимости от того в какой идеологии Вы разрабатываете свое приложение при загрузке среды FoxPro желательно скрыть главное окно FoxPro (SCREEN). Если Вы разрабатываете приложение в основном окне FoxPro, то потом его можно будет отобразить. Ну, а если приложение на базе "As Top-Level" форм, то отображение его и не нужно.

Можно первой же командой в главном (стартовом) файле дать команду

_SCREEN.Visible = .F.

Окно FoxPro действительно скроется. Однако перед этим успеет все-таки "мелькнуть". Не хорошо.

Чтобы подавить открытие главного окна следует использовать файл конфигурации Config.fpw. Это обычный текстовый файл. В нем должна быть строчка:

SCREEN=OFF

Более подробно о файле конфигурации рассказано в других разделах. Данная статья посвящена только главному (стартовому) файлу.

Чтобы снова отобразить главное окно FoxPro (SCREEN) следует дать команду

_SCREEN.Visible = .T.

Если главное окно FoxPro (SCREEN) и до этой команды было отображено, то от этой команды хуже не будет.

В результате, содержимое главного (стартового) файла приобретает следующий вид

ON SHUTDOWN DO MyExitProcedure
DO MainMenu.mpr
_SCREEN.Visible = .T.
READ EVENTS

Как скрыть системные ToolBar

Когда Вы запускаете свое приложение в режиме отладки, то системное меню заменяется Вашим меню. Но вот системный ToolBar остается "висеть", как ни в чем не бывало.

Строго говоря, на системный ToolBar можно вообще не обращать внимания. Дело в том, что информация о том, какие именно системные ToolBar открыты и где именно они расположены, хранится в так называемом "ресурсном файле". По умолчанию, это файл FoxUser.dbf и связанный с ним файл FoxUser.fpt.

Разумеется, Вы не потащите пользователю этот ресурсный файл. Как следствие, на машине клиента системные ToolBar вообще не появяться. Просто потому, что там не будет ресурсного файла с машины разработчика.

Однако если на этапе отладки Вам все-таки необходимо скрыть системные ToolBar, то это можно сделать набором команд

HIDE WINDOW

Имя того или иного ToolBar можно посмотреть в заголовке самого ToolBar (если он не "приклеен" к меню) или через пункт меню View, подпункт ToolBars

Например, скрыть стандартную панель можно командой

HIDE WINDOW "Standard"

Снова активизировать стандартную панель можно командой

SHOW WINDOW "Standard"

Проверить тот факт, что та или иная панель в настоящий момент активна можно используя команду WEXIST()

IF WEXIST("Standard") = .T.       HIDE WINDOW "Standard" ENDIF

Таким образом, если Вам очень хочется скрыть системные ToolBar в режиме отладки, то несложно написать простые процедуры их закрытия в начале главного (стартового) файла и восстановления после команды CLEAR EVENTS.

Но, повторюсь, особого смысла в готовом приложении это не имеет. Поскольку там их и так не будет.

Настройка среды FoxPro

Ранее я вскользь уже упомянул тот факт, что просто запустить среду FoxPro недостаточно. Надо сделать некоторые предварительные настройки. Хотя бы настройку ON SHUTDOWN.

Дело в том, что среда FoxPro по умолчанию настроена таким образом, чтобы облегчить создание новых и модификацию старых приложений. Т.е. она настроена для удобства разработчика. Но в готовом приложении такая настройка среды FoxPro не просто некорректна. Она может оказаться недопустимой!

Вообще-то, настроек среды FoxPro много. Даже очень много. Однако на практике, для корректной работы готового приложения следует уточнить только несколько настроек. Самое большее - два ... три десятка.

Часть настроек среды FoxPro можно увидеть через пункт меню Tools, подпункт Options. А чтобы получить эти настройки в виде кодов нажмите и удерживайте клавишу "Shift" и левой кнопкой мыши нажмите на кнопку "Ok". В командное окно будет выведены все текущие настройки формы Options. Вы можете их просто скопировать и вставить в главный (стартовый) файл. Разумеется, предварительно просмотрев, что именно из них действительно нужно для успешной работы Вашего приложения.

Сложность в том, что на этапе отладки приложения все-таки нужны несколько другие настройки, чем в готовом приложении.

Например, на этапе отладки хорошо бы иметь возможность прервать выполнение какого-либо процесса по нажатию клавиши "Esc", но в готовом приложении этого допускать ни в коем случае нельзя. Это регулирует настройка SET ESCAPE.

Т.е. получается, что необходимо как-то отличать, в каком режиме было запущено приложение. В режиме отладки или как готовый файл EXE.

Есть несколько вариантов определения режимов работы. Самый простой - это посмотреть значение свойства

_VFP.StartMode

Если это свойство имеет значение 0, то мы находимся в режиме отладки. Т.е. получается что-то вроде:

* Общие настройки вне зависимости от режима работы
IF _VFP.StartMode = 0
   * Настройки только для режима отладки
ELSE
   * Настройки только для готового приложения
ENDIF

Есть и еще одна проблема настроек. Дело в том, что при открытии Private DataSession часть настроек, связанных с работой с данными сбрасываются в значения по умолчанию. Полный список таких настроек Вы можете посмотреть в описании к команде "SET DataSession". Причем для некоторых настроек эти самые значения по умолчанию отличаются в зависимости от того, в какой DataSession мы находимся.

Т.е. получается, что недостаточно просто один раз сделать настройки в главном (стартовом) файле. Нужно еще повторить часть настроек в каждой Private DataSession.

Следовательно, выполнение настроек среды FoxPro надо вынести либо в отдельную процедуру, либо оформить как метод класса. Если как метод класса, то либо как метод некоей базовой формы, на основе которой будут созданы все формы Вашего проекта, либо как метод класса Custom, экземпляр которого будет "бросаться" на нужные формы.

Наконец, еще одна проблема настроек. По завершении работы приложения надо вернуть настройки в то состояние, в котором они были на момент запуска приложения.

На первый взгляд, это кажется абсолютно бессмысленным требованием. Но не надо забывать, что мы отлаживаем наше приложение. Это значит, что есть часть настроек, которые просто обязаны отличаться в зависимости от того, просто мы отлаживаем какую-то форму (процедуру) или запустили приложение в режиме отладки, начиная с главного (стартового) файла.

Например, при отладке триггеров хорошо бы видеть записи помеченные как удаленные. Но в готовом приложении, даже при запуске в режиме отладки, нам видеть эти записи не надо. Это регулирует настройка SET DELETED

Да и в любом случае желательно всегда следовать принципу: намусорил, убери за собой. Для программирования это особенно важно во всех смыслах.

Таким образом, в общем случае, работа с настройками выглядит примерно так:

  • Проверяем текущее состояние настройки
  • Если текущее состояние настройки отличается от нужного нам значения в данном режиме работы в данном месте, то сохраняем старое значение настройки и устанавливаем новое
  • По окончании работы восстанавливаем измененные настройки

Из этой логики следует, что использовать процедуры в принципе можно, но очень уж неудобно. Нужны две отдельные процедуры для установки и для восстановления настроек. А, кроме того, нужно где-то хранить старые настройки.

Более удобным кажется использование классов. Создаются два метода одного и того же класса (возможно больше, ведь для Private DataSession надо установить только часть настроек). А для хранения старых значений настроек можно использовать свойства (Properties) класса.

Тогда остается уточнить, использовать ли класс Custom или класс на базе Form?

По большому счету - это абсолютно одинаковые варианты. Следует только помнить, что методы класса Custom можно запустить не ранее события Init этого класса. Но в любом случае методы собственно формы или любых ее объектов еще не существуют на момент выполнения события BeforOpenTables в DataEnvironment формы. Т.е. автоматическое открытие таблиц, включенных в DataEnvironment формы, произойдет с использованием настроек по умолчанию.

Но в большинстве случаев, это не столь уж и принципиально. Дело в том, что критичными (принципиально важными) в момент открытия таблиц являются следующие настройки:

SET DELETED
SET EXCLUSIVE
SET MULTILOCKS

Все остальные настройки вполне можно сделать уже после открытия таблиц. Они влияют уже собственно на работу с открытыми таблицами, а не на их открытие.

Настройка SET DELETED принципиально важна, если в DataEnvironment включено Local View, поскольку просто нет другого способа отсечь записи, помеченные как удаленные, чтобы они не попали в Local View. Но обычно Local View включают в DataEnvironment с опцией NoDataOnLoad=.T. и наполняют данными в Init-формы. Т.е. когда настройка SET DELETED уже сделана в наших методах

Настройка SET EXCLUSIVE имеет разное значение по умолчанию для Default и Private DataSession. В Private DataSession она имеет значение OFF, что собственно и надо. А в Default DataSession используется ранее сделанная в той же DataSession настройка. Если же для отдельных таблиц принципиально важно открыть их в режиме Exclusive, то используйте одноименное свойство курсора в DataEnvironment - формы.

Настройка SET MULTILOCKS нужна, если делается настройка режима буферизации непосредственно в свойствах курсора в DataEnvironment - формы. Но в этом случае FoxPro сам делает нужную настройку. Т.е. опять же нет необходимости в ручной предварительной настройке.

Возвращаясь к содержимому нашего главного (стартового) файла получаем, что его содержимое уже выглядит примерно так:

* Подключаю библиотеку классов, содержащую ряд полезных классов общего назначения
LOCAL loSetting, llIsClass
IF "MyClass.VCX" $ SET("ClassLib")
      llIsClass = .T.
ELSE
      llIsClass = .F.
      SET CLASSLIB TO MyClass ADDITIVE
ENDIF

* Класс, устанавливающий глобальные настройки среды (находится в MyClass.VCX)
loSetting = CREATEOBJECT("Setting")

ON SHUTDOWN DO MyExitProcedure
PUSH MENU _MSYSMENU
DO MainMenu.mpr
_SCREEN.Visible = .T.
READ EVENTS

********* Восстановление исходных настроек
ON SHUTDOWN
POP MENU _MSYSMENU
IF m.llIsClass=.F.
      RELEASE CLASSLIB MyClass
ENDIF

Здесь я предполагаю, что в библиотеке классов MyClass.VCX есть класс "Setting" в событии Init, которого происходит установка нужных настроек, а в событии Destroy восстановление исходных настроек. Т.е. удаление переменной m.loSetting означает автоматическое восстановление исходных настроек.

Еще использованы дополнительные команды PUSH MENU и POP MENU, которые сохраняют и восстанавливают системное меню FoxPro.

Обратите внимание на то, что переменные объявляются как LOCAL. Дело в том, что если не объявить переменные, то по умолчанию они получат область видимости PRIVATE. А для переменных главного (стартового) файла это равнозначно объявлению их как PUBLIC, поскольку они будут видны во всех вызванных формах и процедурах.

Как видите, главный (стартовый) файл начинает разрастаться. С этим надо что-то делать. Чем больше листинг программы (код одного метода или процедуры), тем сложнее такой код отлаживать и модифицировать.


Может пригодится:


Автор: Владимир Максимов
Прочитано: 12923
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (0)

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру