Работа с MapWindow GIS. Выделение отдельных областей слоя и получение данных областей

9 минут на чтение

Доброго времени суток дорогие читатели блога, а особенно любителям MapWindow GIS. В данной статье я хотел бы рассмотреть возможность выделения объектов на слое, а также получение информации о данном объекте. Мы уже рассматривали тему в MapWindow GIS 4.7, как можно выделять мышью объекты, но в отличие от версии MapWindow GIS 4.8 там есть свои нюансы и мне пришлось немного поковыряться, чтобы понять принцип выделения в новой версии объектов.

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

Для начала создайте какой-нибудь проект MapWindow GIS, чтобы можно было в него загружать Shape-файлы. Я возьму свой готовый проект, и буду демонстрировать работы именно на нем. Итак, при загрузке Shape-файлов и дальнейшем отображении их в TMap, необходимо активировать свойства TMapSendMouseMove. Я активирую именно данное свойства, так как я буду выделять объекты, проходя по ней мыши, то есть буду выводить мышью по TMap и каждый объект будет выделять, а затем можно будет нажать левой кнопкой мыши по выделенному объекту и получить информацию о нем. Информацию будем выводить с помощью новой формы, а можно и в виде простого сообщения.

Итак, проект у Вас готов, активируем свойства TMapSendMouseMove, его лучшего всего делать после загрузки 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</

Facebook Vk Ok Twitter LinkedIn Telegram

Похожие записи:

Здравствуйте все, на этот раз статья по MapWindow GIS в Delphi готовилась долго, просто времени не так уж и много, да и в принципе уже многое с MapWindow GIS разобрали, так что, приходится, что-то новое поискать и рассмотреть. В этой статье, мы рассмотрим, как...
Ну что, любитель MapWindow GIS, пора возвращаться к нашей теме. Давненько мы ничего интересного не рассматривали. Долго искал тему, чтобы такое новое и интересное написать про MapWindow GIS, в итоге нашел и решился. Помните нашу статью о том, когда мы выделяли...
Всех приветствую, хочу продолжить тему по MapWindow GIS в Delphi, а на этот раз хотелось бы поговорить о новой версии, которая вышла совсем недавно в июне, данного года, последняя версия сборки 4.8.2. Скачать можно с официального сайта MapWindow GIS, благо дан...