Доброго времени суток дорогие читатели блога, а особенно любителям MapWindow GIS. В данной статье я хотел бы рассмотреть возможность выделения объектов на слое, а также получение информации о данном объекте. Мы уже рассматривали тему в MapWindow GIS 4.7, как можно выделять мышью объекты, но в отличие от версии MapWindow GIS 4.8 там есть свои нюансы и мне пришлось немного поковыряться, чтобы понять принцип выделения в новой версии объектов.
В принципе ничего сложного нет, как оказалось, а выделение объектов в новой версии MapWindow GIS смотрится очень эффективно, а тем более мы добавим получение информации о данных объектах.
Для начала создайте какой-нибудь проект MapWindow GIS, чтобы можно было в него загружать Shape-файлы. Я возьму свой готовый проект, и буду демонстрировать работы именно на нем. Итак, при загрузке Shape-файлов и дальнейшем отображении их в TMap, необходимо активировать свойства TMap – SendMouseMove. Я активирую именно данное свойства, так как я буду выделять объекты, проходя по ней мыши, то есть буду выводить мышью по TMap и каждый объект будет выделять, а затем можно будет нажать левой кнопкой мыши по выделенному объекту и получить информацию о нем. Информацию будем выводить с помощью новой формы, а можно и в виде простого сообщения.
Итак, проект у Вас готов, активируем свойства TMap – SendMouseMove, его лучшего всего делать после загрузки Shape-файла, но это, как я уже говорил выше. У меня это выглядит следующим образом:
procedure TForm1.Action1Execute(Sender: TObject);
var
h,i:integer;
shp:IShapefile;
TN:TTreeNode;
s,s1:Pchar;
str:string;
begin
if OpenDialog1.Execute then
begin
FName:=OpenDialog1.FileName;
ShapeLayer[count].shp:=CoShapefile.Create;
ShapeLayer[count].sname:=FName;
ShapeLayer[count].shp.Open(ShapeLayer[count].sname,nil);
ShapeLayer[count].nshp:=0;
ShapeLayer[count].handle:=Map1.AddLayer(ShapeLayer[count].shp,True);
StatusBar1.Panels[0].Text:='Количество слоев: '+IntToStr(Map1.NumLayers);
Map1.SendMouseMove:=True;
Map1.SendMouseDown:=True;
TN:=TreeView1.Items.Add(nil,ExtractFileName(ShapeLayer[count].sname));
for i:=0 to ShapeLayer[count].shp.NumShapes-1 do
begin
TreeView1.Items.AddChild(TN,ShapeLayer[count].shp.CellValue[1,i]);
end;
Map1.ZoomToMaxExtents;
TreeView1.Selected:=TN;
inc(count);
end;
end;
Из данного кода можно увидеть, что у меня сначала происходит открытие Shape-файлов, а также последующего его отображение в компоненте TMap, а затем я уже активирую данные свойства. Да еще лучше всего включить свойство ShowRedrawTime, чтобы смотреть за какой промежуток времени у нас перерисовывается данные на слое.
Map1.ShowRedrawTime:=True;
Все, у нас почти, что все готово для того, чтобы начать выделять с помощью мыши, когда мы перемещаемся по слою. Для этих целей нам необходимо выделить компонент TMap и открыть вкладку События в инспекторе объектов и найти там событие OnMouseMove. Далее на данное событие нам необходимо написать следующий код:
procedure TForm1.Map1MouseMove(ASender: TObject; Button, Shift: Smallint;
x, y: Integer);
var
projx,projy:double;
ShID:OleVariant;
ext:Extents;
i,j,count:integer;
array_of_word:array of integer;
begin
count:=TreeView1.Selected.Index;
Map1.PixelToProj(x,y,projx,projy);
ext:=CoExtents.Create;
ext.SetBounds(projx,projy,0.0,projx,projy,0.0);
ShapeLayer[count].shp.SelectNone;
ShapeLayer[count].shp.SelectionTransparency:=127;
ShapeLayer[count].shp.SelectionColor:=clRed;
if ShapeLayer[count].shp.SelectShapes(ext,0.0,INTERSECTION,ShID)=True then
begin
j:=VarArrayHighBound(ShID, VarArrayDimCount(ShID));
if j=1 then
begin
for i:=1 to j do
begin
ShapeLayer[count].shp.ShapeSelected[ShID[i]]:=True;
ShpID:=Integer(ShID[i]);
end;
end;
if j=0 then
begin
for i:=0 to j do
begin
ShapeLayer[count].shp.ShapeSelected[ShID[i]]:=True;
ShpID:=Integer(ShID[i]);
end;
end;
end;
Map1.Redraw;
end;
Если данный пример сравнивать с примером, который мы делали в версии 4.7, то можно с уверенностью говорить, что тут есть свои нюансы. Давайте разберем немного код по порядку.
Сперва мы снимаем выделения на нашем слое, если они имеются, если их нет, все равно ничего страшного, это мы делаем с помощью свойства SelectNone. Далее мы устанавливаем прозрачность выделения, это делается с помощью свойства SelectionTransparency, я установил значение 127, то есть максимальное, соответственно у меня прозрачности не будет никакой. Ну и на последок мы выставляем цвет нашего выделения, это делается с помощью свойства SelectionColor, как видно из кода программы, то он у меня установлен в красный.
Далее идет строчка кода:
if ShapeLayer[count].shp.SelectShapes(ext,0.0,INTERSECTION,ShID)=True then
С помощью данного кода мы узнаем – попадаем ли мы мышью в какой-нибудь объект на слое, если попали, то записываем данные о данном объекте в массив ShID. С помощью кода:
J:=VarArrayHighBound(ShID, VarArrayDimCount(ShID));
Мы определяем границы нашего массива (верхнюю границу). Тут я заметил, что при разных границах массива необходимо начинать цикл выделения по-разному, поэтому и сделал два условия: когда j=1 и когда j=0. В зависимости от того, чему равняется j, мы начинаем цикл либо с 1, либо с 0. Ну и с помощью ShapeSelected мы выделяем область, нам необходимо данное свойство установить в True. В конце обязательно нам необходимо перерисовать TMap, это делается с помощью процедуры Redraw и если у Вас будет включено свойство ShowRedrawTime, то Вы увидите, за сколько времени у Вас перерисовались данные. Вот что у меня получилось на самом деле:
То есть когда подводим мышью к какой-нибудь области слоя, то он выделяется (выделяется тот, на котором установлен указатель мыши). Вот и все, теперь нам необходимо получить данные о выделенном нашем слое.Для этих целей, я создал новую форму и разместил на ней компонент TListView, в нем я буду отображать список полей, а также данные поля (для конкретного объекта слоя). Для получения списка полей, я использую компонент TDBF, Вы же можете использовать тот, который Вам будет удобен. Далее переходим к нашему компоненту TMap. Нам теперь необходимо задействовать событие OnMouseDown. Поэтому выделяем компонент TMap и во вкладке события инспектора объектов находим данное событие и пишем следующий код:
procedure TForm1.Map1MouseDown(ASender: TObject; Button, Shift: Smallint;
x, y: Integer);
var
xx,yy:double;
begin
if Action12.Checked=True then
begin
if Button=SmallInt(mbright) then
begin
count_s_info:=TreeView1.Selected.Index;
InfoShape.ShowModal;
end;
end;
end;
Тут все очень просто, мы просто определяем, чтобы было нажатие мыши и если оно произошло, то мы вызываем нашу форму, на которой будем отображать данные об объекте слоя. Давайте вернемся не надолго к событию OnMouseMove и вспомним нашу переменную ShID. Так вот, давайте ее объявим в спецификаторе доступа publiс типа OleVariant. Это мы делаем, чтобы она была доступна в другим модулях, нам не надо объявлять больше никаких переменных для того, чтобы получить идентификатор (номер) объекта на нашем слое.
Далее на событие OnShow нашей формы, на которой мы будем отображать данные объекта я написал следующий код:
procedure TInfoShape.FormShow(Sender: TObject);
var
i:integer;
DB:TDBF;
TableName,sID:WideString;
begin
Caption:='Данные слоя '+IntToStr(Form1.ShpID);
Flag:=False;
for i:=0 to Form1.St.Count-1 do
begin
sID:=Form1.St.Strings[i];
if StrToInt(sID)=Form1.ShpID then
begin
CheckBox1.Checked:=True;
Flag:=True;
end;
end;
if Flag=False then
CheckBox1.Checked:=False;
ListView1.Clear;
DB:=TDBF.Create(Form3);
TableName:=Form1.ShapeLayer[Form1.count_s_info].sname;
Delete(TableName,Length(TableName)-3,4);
TableName:=TableName+'.dbf';
DB.TableName:=TableName;
DB.Open;
for i:=1 to DB.FieldCount do
begin
ListView1.Items.Add.Caption:=DB.GetFieldName(i);
ListView1.Items.Item[i-1].SubItems.Add(Form1.ShapeLayer[Form1.count_s_info].shp.CellValue[i-1,Form1.ShpID]);
end;
end;
Все просто тут, отображаем в заголовке формы номер объекта, на который мы получаем данные, затем определяем имя таблицы (DBF-файла), из которого нам необходимо будет вытаскивать данные и в цикле я получаю их в самом конце обработчика.
Вот и все, вот что получается в итоге:
Неплохо, правда ли. Теперь с данным слоем можно делать все, что Вы захотите, раскрашивать, скрывать, ставить метку, удалять и так далее. Я Вам показал, как можно выделять данные на слое с помощью перемещения мыши, а на основе данного примера Вы можете сделать выделение именно определенной области с помощью специального курсора выделения.Исходных кодов, я никаких не прикладываю, а только лишь оставляю ссылку на полный проект MapWindow GIS в Delphi, Вы же можете посмотреть, как это все реализовано и ждать следующей серии постов. Удачи Вам!
Также можно посмотреть список статей, доступных по MapWindow GIS</