efox.gif (1606 bytes)Для разработчиков VFP

Средства и методики для сторонних разработчиков

Инструментальные средства "EvnFox"

EvnFox home

Vallmind home

 

Работа с приложениями на базе EvnFox как с COM объектами

Обычно приложения на основе технологии EvnFox регистрируются как COM-классы при установке. Следующие приложения Vallmind software имеют следующие имена COM-классов:

Система учёта "Events" Events.Events2
Events - Расчёты с населением за газ EvnGas.EvnGas
Арм контролёра. Events - Расчёты с населением за газ EGasTerm.EGasTerm

Следующий фрагмент кода показывает порядок подключения к приложению Events - Расчёты с населением за газ с использованием технологии COM. Опущены строки инициализации переменных и выбран синтаксис общий для VB и FoxPro. Для C просто нужно добавить;

В начале вставить строки объявления переменных _App, _Res

_App = CREATEOBJECT("evngas.evngas")
_App.WorkingPath         = "C:\EvnGas"
- указать исполняемую директорию приложения
_App.Login                 = "sa"
                - указать имя пользователя
_App.Password             = ""
                - указать пароль

_Res = _App.Init_MApp()

Если _Res - нулевой - всё нормально и можно продолжать работу с объектом.

Для работы используются два метода объекта _App:

Так, для быстрого завершения приложения нужно выполнить   _App.DoCmd("Quit") , а для возврата текущей директории: _Dir = _App.Eval("CurDir()")

Некоторые функции и процедуры приложения:

E_IndexKey10() Возвращает ключ в 10 знаков. Используются суффиксы ключей.
E_IndexKey20() Возвращает ключ в 20 знаков. Используется в поле SQL_RECORD. Поле SQL_RECORD присутствует в таблицах базы SQL Server когда важен физический порядок записей. Так как используются технологии, работающие и с DBF и в SQL, то физический порядок - важен. SQL_RECORD - уникальный ключ, совмещающий в себе назначения полей IDENTITY и TIMESTAMP. Он является уникальным ключём в 20 знаков (гораздо короче чем NEWID()) и всегда возвращает возрастающее значение. Также задействуется система суффиксов ключей. Если в таблице есть поле SQL_RECORD, то оно является обязательным для заполнения данной функцией!
   

 

Создание глобальных пользовательских функций на VFP

С помощью пункта меню \Система\Системные средства\VFP функции вызывается средство для создания пользовательских функций на Visual FoxPro. Средство выполнено в виде проводника.

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

IF NOT E_Check_Compile_UDFs()
    RETURN .F.
ENDIF
 

if not 'EACCESS' $ Upper (Set ('ClassLib'))
    Set ClassLib to EAccess Additive
endif
m.oAccess = CreateObject ('E_Access')
if Type ('m.oAccess') <> 'O'
    Return .F.
ENDIF
 

Функция E_Check_Compile_UDFs() проверяет времена изменения текстов функций и при необходимости пересоздаёт из них файл E_UDF_Functions.prg и компилирует его. После чего выполняет SET PROCEDURE TO E_UDF_Functions ADDITIVE
 

Второй фрагмент кода создаёт объект oAccess, который вы можете использовать в функциях для открытия таблиц, регистрации курсоров, генерации и регистрации имён временных файлов и др. Главным удобством использования этого объекта является то, что открывая таблицу (если она в DBF) или создавая и регистрирую курсор, вам не нужно заботиться о их закрытии или удалении. Объект сам сделает это в методе Destroy.

Оба этих действия выполняются программой и вам не нужно их повторять перед выполнением свободного итогового отчёта!

Объект oAccess также создаётся и при печати любой ведомости или генерации книги отчёта из менеджера отчёта. Компилировать и подключить же функции вам нужно самим. Для этого в форме отчёта можно использовать, например, возвращающую пустую строку конструкцию: iif(Empty( E_Check_Compile_UDFs()),'','')

Когда мы создаём или редактируем функцию - используем следующее окно

Функция может быть трёх типов. По умолчанию тип - "для внутреннего использования". Этот тип функций виден только из программы. Если выбрать тип "для пользователя", то функцию можно будет вызывать с помощью пункта системного меню программы \Данные\Выполнить процедуру или вызовом процедуры E_ExecuteUDF из любого места.

Если выбрать тип функции "Запрос", то:

Пример запроса будет ниже.

Имя пользовательской функции всегда будет начинаться с EUDF_ . Вам нужно только дописать окончание. С заполнением описания и группы думаю проблем не должно быть.

Две страницы с фрагментами кода. На странице "Код функции(запроса)- непосредственно текст функции. Среда отладки - инициализация данных и открытие таблиц для отладки. Выполняется только при нажатии кнопки с лисой и красным треугольником здесь. Справа над каждым текстом расположена кнопка с маленькой лисой и синим кодом . Щёлкните её для редактирования кода функции. Текст будет загружен в окно редактора Visual FoxPro

В примере приведен текст для отчёта МЕЖРЕГИОНГАЗА, в котором открываются нужные таблицы и выбирается список всех ГРО, для которых ведутутся расчёты за газ непосредственно с населением. Вы можете использовать любой код VFP. Но для создания кода с использованием уровня апроксимации доступа к данным среды EvnFox предлагается использование специальных функций для доступа к данным (если вы конечно хотите, чтобы код работал и с DBF и с SQL). Так открывать таблицы предлагается с помощью метода Use объекта oAccess, делать запрос с помощью функций E_SQL и E_GetTableSource как показано в примере. При этом одним из параметров в функцию E_SQL передаётся ссылка на объект oAccess, для того, чтобы он зарегистрировал курсор, имя которого в данном примере _gdc.

Для сохранения кода нажмите CTRL+W . Для отказа - просто закройте окно. После сохранения кода программа для проверки откомпилирует код функции. Если при компиляции будут обнаружены ошибки - их перечень будет показан в дополнительном окне.

В базу же созданная или изменённая функция попадёт только когда вы щёлкните "Сохранить".

Можно редактировать код функции прямо из проводника не вызывая диалогового окна со свойствами функции. Для этого просто щёлкните кнопку над списком функций в правой части проводника "VFP функции". Код функции будет открыт  редакторе VFP в окне разработки компонентов, где его можно править одновременно с другими компонентами VFP не в диалоговом режиме.

Пример запроса:


* Создаём курсор для перечисления и описания значений, которые нужно запросить у пользователя
*
SELECT 0
CREATE CURSOR _input (NAME C(100),TYPE C(1),LENGHT N(3),DECIMAL N(2),CAPTION C(100),SHORT C(15),CHILD_TAB C(30),CLASS M)

*
Заполняем курсор описанием значений-параметров запроса для ввода пользователем
*
INSERT INTO _input (NAME,TYPE,LENGHT,DECIMAL,CAPTION,SHORT,CHILD_TAB,CLASS) ;
VALUES ('FROM_DATE','T',8,0,'
Дата с','Дата с','','')
INSERT INTO _input (NAME,TYPE,LENGHT,DECIMAL,CAPTION,SHORT,CHILD_TAB,CLASS) ;
VALUES ('TO_DATE','T',8,0,'
Дата по','Дата по','','')
INSERT INTO _input (NAME,TYPE,LENGHT,DECIMAL,CAPTION,SHORT,CHILD_TAB,CLASS) ;
VALUES ('JUST_DEPARTMENT','L',1,0,'
Только подразделение','Только родразделение','','')
INSERT INTO _input (NAME,TYPE,LENGHT,DECIMAL,CAPTION,SHORT,CHILD_TAB,CLASS) ;
VALUES ('Department','C',10,0,'
Подразделение','Подразделение','depments','')

*
Обязательно объявляем переменные памяти в соответствии с перечисленными в поле NAME курсора выше
*
именами и присваиваем начальные значения

*
m.From_Date
      = DTOT(DATE() - DAY(DATE()) + 1)
m.To_Date
        = DATETIME()
m.Just_Department = .F.
m.Department
     = ''

*
Вызываем диалог для ввода пользователем нужных для запроса параметров
*

m.Ok = .F.
=MApp.DoCmd([DO FORM EInput WITH '
Документы за интервал дат','_input','DocDateQuery' TO m.Ok],SET('Datasession'))
IF NOT m.Ok
    RETURN .F.
ENDIF

SELECT _input
USE

*
Открываем нужные таблицы и делаем запрос
*
IF
 NOT oAccess.Use('doc_head') OR ;
    NOT E_SQL(E_GetTableSource('doc_head'),[Select * From ..doc_head Where ACTL_DATE>=~m.From_Date and  ACTL_DATE<=~m.To_Date ] + IIF(EMPTY(m.Just_Department),[],;

        [ AND DP_IDENT=~m.Department]),'queryresult')
    RETURN .F.
ENDIF

*
В случае запроса к одной таблице, описанной в словаре данных, просто вызываем форму ChoiceRo, которая
*
задействует словарь для для формирования таблицы с результатом запроса

*
SELECT queryresult
=MApp.DoCmd([Do Form ChoiceRo With 'queryresult',,'doc_head','Found documents','
Найдены документы' to m.Ok],SET('Datasession'))


Так как формы, находящиеся в EXE, не видны извне, то вызываем их с помощью метода DoCmd объекта приложения MApp.

Для доступа к данным с использованием уровня апроксимации не используем напрямую команды VFP или TSQL, а задействуем процедуры технологии прямого доступа (E_Locate, E_Scatter, E_Gather, ...) и технологии запросов (E_SQL, ...) среды EvnFox.

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

* Открываем нужные таблицы и делаем запрос данных из doc_head и doc_item, связанных по POINTER
* При этом расшифровываем участника операции doc_head.PART_IDENT из списка соронних лиц company
* и позиции документов из номенклатурного списка позиций finitems
*
IF
 NOT oAccess.Use('doc_head') OR ;
    NOT oAccess.Use('doc_item') OR ;
    NOT oAccess.Use('company') OR ;
    NOT oAccess.Use('finitems') OR ;
    NOT E_SQL(E_GetTableSource('doc_head'),[Select a.*,NVL(c.NAME,'                              ' as CM_NAME,]+;
        [ Nvl(d.NAME,'                              ' as FI_NAME,c.SIM as ISUM From ..doc_head a Join ..doc_item b ]+;
        [ On a.POINTER=b.POINTER Left Outer Join ..company c On a.PART_IDENT=c.IDENT ] +;
        [ Left Outer Join ..finitems d.On b.IDENT=d.IDENT Where ACTL_DATE>=~m.From_Date and  ACTL_DATE<=~m.To_Date ]+;
         IIF(EMPTY(m.Just_Department),[],;
        [ AND DP_IDENT=~m.Department]),'queryresult')
    RETURN .F.
ENDIF

*
Здесь в форму ChoiceRo передаём второй параметр с перечислением столбцов таблицы в формате:
* ИМЯ1#Класс1#Бидлиотека1#Заголовок1;ИМЯ2#Класс2#Бидлиотека2#Заголовок2;...
*
SELECT queryresult
=MApp.DoCmd([Do Form ChoiceRo With 'queryresult',[DOCM_CODE###
Номер документа;ACTL_DATE###Дата документа;CM_NAME###Участник операции;FI_NAME###Позиция;ISUM###Сумма позиции],'doc_head','Found documents','Найдены документы',,,,'doc_hi_ci' to m.Ok],SET('Datasession'))

Обязательно в форму ChoiceRo девятым параметром передаём уникальную для запроса строку - ключ сохранения размеров окна, столбцов, сортировки таблицы. В примере это 'doc_hi_ci'.

В случае выбора пользователем строки форма должна установить значение переменной m.Ok в .T. !!!

Далее на закладке "Результат запроса" перечисляем таблицы и ключевые поля для вызова запроса из объектов-ссылок. Например если указать

То данный запрос можно вызывать для поиска подразделения или стороннего лица, например, из заголовка документа. При проведении мышкой над кнопкой   элемента-ссылки "Стор.лицо" будет появляться жёлтое меню, в котором можно выбрать пункт "Подготовленный...", и появится перечень запросов, в результатах которых указана ссылка на company

 

Создание свободных итоговых отчётов

Обычно в меню "Отчёты" приложения имеется пункт "Свободные итоговые отчёты". Когда вы вызываете список форм для редактирования - также ищите форму "Свободный итоговый отчёт".

Отчёт создаётся в Excel. Выберите в списке форм "Свободный итоговый отчёт" и создайте для него глобальную копию. Вызовите её для редактирования. Бланк отчёта будет пустым.

Когда вы вызвали для редактирования форму Excel - в программе будет "висеть" диалоговое окно:

Первая кнопка в форме позволяет загрузить в редактор VFP текст из текущеё ячейки листа Excel, который был вызван из базы данных и используется как форма отчёта.

Рассмотрим следующий пример:

Есть следующие таблицы:

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

Создаём глобальную форму отчёта и размечаем её средствами Excel следующим образом:

Непосредственно область самого отчёт а ограничена A1:D10. О чём мы и делаем первую запись в служебных полях. Служебные поля могут быть описаны в ячейках с первой по 300-ю. Начинается описание в первом столбце. Так прежде всего мы должны указать (строка 14):

Area=A1:D10

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

Header=A1:D3

Далее нам понадобятся пару переменных для того, чтобы определить интервал дат за который нужно выбрать данные. Объявление переменной отчёта осуществляется с помощью синтаксиса Var=имя . Так в нашем примере понадобятся переменные m.From_Date и m.To_Date . В строках A15 и A16 мы их только объявляем. Присваивать значения будем в коде ячеек заголовка. Если текст ячейки начинается со слова FUNCTION, то программа будет интерпретировать всё остальное как строки кода на VFP. Так в ячейке A1 В мы вызываем диалог для указания интервала дат. Для этого используем форму DateInt. Но так как у нас нет текста формы, то мы должны вызвать её из EXE файла. Потому передаём код для вызова формы как макростроку в метод DoCmd объекта MApp . Форма сохраняет интервал дат в переменные From_Date и To_Date.

FUNCTION
m._Ok = .F.
= MApp.DoCmd([Do Form DateInt to m.Ok)]
IF NOT m._Ok
    m.Terminater_Report = .T.
ENDIF
RETURN TTOC(DATETIME())
 

Этот код будет возвращать строку с текущими датой и временем для печати в начале отчёта

Продолжим служебные поля под областью отчёта. Дальше с помощью конструкции Details описываем все области строк отчёта. Эти области могут быть вложенными. Если одна область вложена в другую, то на каждой строки внешней области будет выполняться запрос для внутренней и добавлены строки для внутренней области.

Так в нашем примере самую внешнюю область мы определяем только для для того, чтобы подбить итоги. В первом столбце строки области определения указываем: Details=A2:D9 . Во втором столбце указываем уровень вложенности областей. 1 - самая внешняя. В третьем столбце можем написать любой код на VFP, но он должен делать запрос для выбора строк области или создавать курсор. В четвёртом столбце обязательно нужно указать имя алиаса курсора или запроса со строками области, который создаёт или выбирает код в третьем столбце. В нашем примере код в третьем столбце выглядит:

SELECT 0
CREATE CURSOR _bln1
(F C(1))
APPEND BLANK

Cоздаём фиктивный курсор _bln1 с одной строкой. В четвёртом столбце указываем _bln1.  В пятом столбце E при необходимости указываем область итогов за областью отчёта. В нашем случае B10:D10 . В области итогов можно использовать следующий синтаксис:

{SUM_DET    - просуммировать в столбце области отчёта все строки кроме формул;

{SUM_TOT    - просуммировать в столбце области отчёта все строки с формулами.

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

Во второй вложенной области отчёта нужно перечислить все типы организаций. Указываем в первом столбце 20 строки Details=A4:D6 . Во втором столбце указываем уровень вложенности 2 . Код VFP в третьей строке выглядит типа:

IF NOT oAccess.Use('companys') OR ;
    NOT oAccess.Use('ginvoices') OR ;
    NOT oAccess.Use('winvoices') OR ;
    NOT oAccess.Use('goods') OR ;
    NOT oAccess.Use('servaices') OR ;
    NOT E_SQL(E_GetTableSource('conpanys'),[Select Distinct TYPE From ..companys Order By Type],'_ctp',,,,m.oAccess)
    m.Terminate_Report = .T.
    RETURN .F.
ENDIF
 

Вначале открываем все нужные таблицы путём вызова метода Use объекта oAccess. Далее делаем запрос с помощью функции E_SQL . Первым аргументом нужно указать имя источника данных, где запрос нужно выполнить. Лучше всего для этого применить функцию E_GetTableSource, в которую в свою очередь передаётся имя одной из таблиц, из которой выбираются данные. Вторым аргументов в E_SQL передаётся непосредственно текст самого запроса. Чтобы писать запросы, которые могут работать и с данными в SQL и с данными в DBF нужно изучить:

Здесь видим использование следующих правил:

С определением двух остальных Details в примере предлагаю разобраться самим. Выражения кода запросов для них будут выглядеть приблизительно так:

IF NOT E_SQL(E_GetTableSource('ginvoices'),[Select b.GROUP,SUM(a.SUM) From ..ginvoices a Join ..goods b On a.GOOD=b.CODE Join ..companys c On a.COMPANY=c.CODE Where c.TYPE=?(_ctp.TYPE) and a.DATE>=~m.From_Date and a.DATE<=~m.To_Date Group By b.GROUP Order By b.GROUP],'_ggrp',,,,m.oAccess)
    m.Terminate_Report = .T.
    RETURN .F.
ENDIF
 

и

IF NOT E_SQL(E_GetTableSource('winvoices'),[Select b.GROUP,SUM(a.SUM) From ..winvoices a Join ..services b On a.SERVICE=b.SERVICE Join ..companys c On a.COMPANY=c.CODE Where c.TYPE=?(_ctp.TYPE) and a.DATE>=~m.From_Date and a.DATE<=~m.To_Date  Group By b.GROUP Order By b.GROUP],'_wgrp',,,,m.oAccess)
    m.Terminate_Report = .T.
    RETURN .F.
ENDIF
 

Для завершения работы отчёта в ближайший удобный момент присвойте m.Terminate_Report = .T.

Предлагается не писать большие тексты процедур и функций непосредственно в самом листе Excel. Во первых это будет выглядеть не совсем приятно. Во вторых - если вы захотите создать из такой формы ещё несколько вариантов, а потом вам понадобится вносить изменения в текст большой функции - вы замучаетесь это делать во всех формах. Создайте пользовательскую функцию и вызываёте её в отчёте!

В ячейках всего отчёта также можно использовать код VFP двумя способами:

Окно разработки компонентов VFP

Предназначено для асинхронной работы с копиями отчётных форм или другими разрабатываемыми компонентами VFP и одновременно с несколькими. Когда мы вызываем для редактирования копию отчётной формы или код функции VFP, то они будут загружены в основное окно редактирования компонентов VFP, которое может быть открыто только одно. Окна редактирования компонентов VFP могут быть открыты одновременно с другими окнами программ и они не мешают друг другу. В одном окне редактирования компонентов VFP могут быть открыто одновременно несколько редакторов кода, отчётов, форм, ..., которые так же не мешают друг другу. После закрытия окна и сохранения соответствующего компонента он будет автоматически сохранён в соответствующем источнике данных или базе. Выглядит окно редактирования компонентов приблизительно так:

Разработка проектов (библиотеки классов; формы; формы отчётов; меню; формы отчётов Excel, Word, HTML)

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

Для работы с пректами используем пункт системного меню \Система\Системные средства\VFP проект... Появится список проектов, в который вы можете добавлять новые проекты. После выбора проекта из списка появится отдельное и индивидуальное для пректа окно разработки VFP компонентов, в котором будет присутствовать окно проекта.

В окне проекта можно создавать новые, добавлять существующие, редактировать следующие компоненты:

После закрытия любого компонента он будет автоматически сохранён в базе и станет сразу доступен всем пользователям. Для выполнения проекта из системного меню создайте в нём функцию для пользователя.

! Каждое приложение может предлагать для использования свой набор готовых классов, иконок и других объектов. Перед открытием проекта или перед вызовом функции пользователем такие объекты будут скопированы из приложения в поддиректорию DEVBASE рабочей директории приложения. Вы можете использовать их. Но при использовании пользователем старых версий приложения могут возникнуть конфликты с объектами, которые созданы вами на базе таких классов. Потому придётся более тщательно следить за версиями приложений у клиентов.

К сожалению редактировать формы и меню вы не сможете без установленного на компьютере полного VFP9 ! Для создания и редактирования форм и меню нужно запустить приложение из под VFP9 командами:

Set Default to исполняемая директория приложения

Do имя приложения

Отладка компонентов VFP

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

Set Default to исполняемая директория приложения

Do имя приложения

Чтобы остановить программу в нужной точке для отладки можно:

Если вам удалось остановить процедуру(функцию) или метод для отладки, то появится окно отладки VFP, в котором можно:

Кроме окна отладки станет доступным и окно COMMAND, где можно выполнить любую команду VFP.

Полезно будет из окна COMMAND командой SET вызвать окно для просмотра рабочих областей с открытыми таблицами и самих таблиц.


См. в интернет:    Долина разума    Система учета "Events"     Рассчеты с населением за газ    Предприниматель     Инструментальные средства "EvnFox"    www.vallmind.ru    EasySQL4Fox    ECalcPad    VMZipper    Святая трезвость    Трезвая Россия