Более глубокая интеграция приложений Visual FoxPro и ГИС MapInfo Professional.

Новости

В статье рассмотрены особенности механизма взаимодействия приложения Visual FoxPro с пространственными данными в среде MapInfo Professional.

После размещения статьи «Создание ГИС на Visual FoxPro средствами MapInfo Professional», мне часто приходилось отвечать на вопросы о возможности более тесной интеграции приложений Visual FoxPro c ГИС MapInfo Professional и связанных с этим особенностях реализации COM модели MapInfo Professional. По этому, прежде всего – приношу извинения тем коллегам, на вопросы которых отвечал с опозданием, излишне кратко, или не отвечал вовсе.

Не смотря на то что, в принципе, среда MapInfo Professional содержит всё необходимое для организации связи геопространственных данных с семантическими данными как во внутреннем формате MapInfo, так и во внешних БД, на практике оказывается, что возможностей MapInfo для построения эффективного рабочего места бывает не всегда достаточно. А, принимая во внимание, непревзойденную продуктивность VFP в работе с данными, решение использовать для разработки Visual FoxPro было бы оптимальным выбором!

Первое что, как правило, требуется при разработке информационной системы с географической составляющей – это показать «ГДЕ». То есть, [Москва, Красная площадь, д.1] – это где? При этом, во-первых, в окне карты должно произойти перемещение видимой части окна, так чтобы объект [Москва, Красная площадь, д.1] находился в области отображения окна карты. Во-вторых, масштаб отображения должен быть подобран таким образом, чтобы объект был, различим в окне карты, видимыми должно оказаться достаточное количество соседних объектов, составляющих окружение искомого объекта.

Второе – при выборе объекта на карте, необходимо представить информацию, из БД имеющую отношение к выделенному на карте объекту.

Надо заметить, что второе требование невозможно выполнить располагая только MapInfo Professional. Потребуется среда программирования MapBasic, где необходимо написать и откомпилировать процедуру вызова переопределения системного события [SelChangedHandler], например такую:

Declare Sub SelChangedHandler

call SelChangedHandler()

Sub SelChangedHandler
If SelectionInfo(3) > 0 Then
Run Menu Command ID 1001
End If
End Sub

Здесь находится уже откомпилированная, готовая к выполнению в среде MapInfo Professional, программа: [hook_selection.mbx]. В этой процедуре каждый раз при срабатывании события [SelChangedHandler] выполняется команда, назначенная кнопке с идентификатором [1001].

Важно! В среде MapInfo Professional не могут выполняться программы, откомпилированные в среде MapBasic с большим номером версии, чем MapInfo Professional. Файл [hook_selection.mbx] создан в среде MapBasic 9.5, которую можно скачать на сайте www.mapinfo.com: www.mapinfo.com.

Теперь рассмотрим код класса на Visual FoxPro, реализующий интересующие нас возможности.

*!*
*!* организация связи приложения VFP и карты MapInfo
*!*
*!*
*!* организация связи приложения VFP и карты MapInfo
*!*
*!* пример использования:

*!* Public oForm As Form
*!* m.oForm=Createobject([demo_form],[C:\callback_map\map01.tab])
*!* m.oForm.Show()
*!*
Define Class demo_form As Form
Top=0
Left=0
Height=200
Width=450
ShowWindow=2
DoCreate=.T.
BorderStyle=2
Caption=[DEMO: callback and managment by map from MapInfo]
MaxButton=.F.
MinButton=.F.
Name=[Form1]
cMap=[]
Enabled_ChangedHandler=[ON]

Add Object list1 As ListBox With ;
Height=150,;
Left=1,;
Top=1,;
Width=450,;
Name=[List1]

Add Object command1 As CommandButton With ;
Top=171,;
Left=360,;
Height=25,;
Width=85,;
Caption=[Закрыть],;
Name=[Command1]

Procedure Init(cMap As Character) As VOID
This.cMap=m.cMap
Public pomi As Object
Try
m.poMI=Getobject(,[MapInfo.Application])
Catch
m.poMI=Createobject([MapInfo.Application])
Endtry
If Type([m.poMI.Name])#[C]
Messagebox([Ошибка при попытке обратиться к «MapInfo.Application»],;
16+4096,[Внимание],15000)
Return .F.
Endif
m.poMI.Visible=.T.
m.poMI.SetCallback(This)
m.poMI.Do([Alter ButtonPad ID 4 ]+;
[Add PushButton Calling OLE «DEMO_ChangedHandler» ID 1001])
m.poMI.Do([Run application «C:\callback_map\hook_selection.mbx»])
m.poMI.Do([Open Table «]+This.cMap+;
[» Interactive Map From «]+Juststem(This.cMap)+[«])
Endproc && Init

Procedure DEMO_changedhandler(lcParam As Character) As VOID
If Thisform.Enabled_ChangedHandler=[ON] And ;
Val(m.poMI.Eval([SelectionInfo(3)]))>0

Local lc_MI_query As Character
m.lc_MI_query=m.poMI.Eval([SelectionInfo(2)])
Local lcValueFromMap As Character
m.lcValueFromMap=m.poMI.Eval(m.lc_MI_query+[.txt])
Thisform.list1.AddItem(m.lcValueFromMap)
Thisform.list1.Value=Thisform.list1.ListCount
Endif
Endproc && demo_changedhandler

Procedure Destroy
If Type([m.poMI.Name])=[C]
m.poMI.Do([Alter ButtonPad ID 4 Show])
m.poMI.Do([Alter ButtonPad ID 4 Remove ID 1001])
m.poMI.Do([Close All Interactive])
Endif
m.poMI=Null
Release pomi
Endproc && Destroy

Procedure list1.Click
Thisform.Enabled_ChangedHandler=[OFF]
m.poMI.Do([select obj from Map01 where txt=»]+;
This.ListItem(This.Value)+[» into _tmp])
m.poMI.Do(;
[set map center ]+;
[(CentroidX(_tmp.obj),]+;
[CentroidY(_tmp.obj))]+Chr(13)+Chr(10)+;
[zoom Distance( ]+;
[ObjectGeography(_tmp.obj,1),]+;
[ObjectGeography(_tmp.obj,2),]+;
[ObjectGeography(_tmp.obj,3),]+;
[ObjectGeography(_tmp.obj,4),»m»)*8 Units «m»])
Thisform.Enabled_ChangedHandler=[ON]
Endproc && list1.Click

Procedure command1.Click
Thisform.Release
Endproc && command1.Click

Enddefine && demo_form

Здесь, в методе [Init] реализовано переопределение системного события MapInfo [SelChangedHandler] – срабатывающего каждый раз, когда происходит смена выделенного объекта на карте. Для этого в метод [SetCallback] COM экземпляра MapInfo передаётся ссылка на объект, содержащий метод [DEMO_ChangedHandler], т.е. наша форма. Следующая команда: [Alter ButtonPad…] создаёт кнопку в панели инструментов «Команды», связывает её с вызовом метода [DEMO_ChangedHandler], назначает идентификатор кнопки [1001]. После чего в среде MapInfo запускается программа [hook_selection.mbx], которая и будет при срабатывании системного события [SelChangedHandler] выполнять команду, назначенную кнопке c идентификатором [1001]. Затем, командой [Open Table…], открывается карта.

Это обеспечивает выполнение второго требования, т.е. – при выборе объекта на карте, представить информацию, из БД имеющую отношение к выделенному на карте объекту. Осталось только написать код метода [DEMO_ChangedHandler]. В рассматриваемом классе, метод [DEMO_ChangedHandler] добавляет в ListBox на форме атрибут выбранного на карте объекта (поле [txt]).

Надо признать, что механизм переопределения событий MapInfo – является яркой особенностью этого, во всех отношениях замечательного продукта.

Первое требование – показать «ГДЕ», реализовано в событии [List1.Click]. Здесь, командой [select obj from Map01 …] выбираем искомый объект на карте. Затем последовательным выполнением команд [set map center…] и [zoom…] устанавливаем центр окна отображения карты по координатам центроида выбранного объекта и назначаем размер фрагмента, показанного в окне карты большим в 8 раз прямоугольника описанного вокруг выделенного объекта.

Обратите внимание, что с целью избежать срабатывания системного события [SelChangedHandler], при программном выборе объекта на карте, событие [List1.Click] начинается с установки значения [OFF] флага [Enabled_ChangedHandler], который проверяется в методе [DEMO_ChangedHandler], и заканчивается возвращением флага [Enabled_ChangedHandler] в значение [ON].