Добавление списка слоёв в приложение PyQGIS

QGIS помимо готовой пользовательской ГИС является еще и набором библиотек, которые могут быть использованы для создания новых приложений. К сожалению, при разработке таких приложений некоторые элементы интерфейса необходимо создавать самостоятельно. Один из примеров такого элемента — список загруженных слоёв (иногда неверно называемый легендой).

Этот пост описывает процесс встраивания списка слоёв в приложение PyQGIS. В основе лежит перевод поста «Layer list widget for PyQGIS applications», сделанного German Carrillo в блоге GeoTux.

Работоспособность кода проверена на QGIS 1.7. В новых версиях QGIS могут быть внесены изменения, делающие его неработоспособным.

Подготовка

Будем исходить из того, что все программное обеспечение установлено при помощи установщика OSGeo4W используя путь по умолчанию C:\OSGeo4W. Кроме самой QGIS со всеми зависимостями, необходимо выбрать следующие пакеты в категории Libs: pyqt4, qt4-devel, qt4-doc, qt4-libs. В этих пакетах находятся инструменты разработчика, необходимые библиотеки и документация.

Предполагается, что читатель уже знаком с процессом создания приложений PyQGIS и QGIS Python API. Если это не так, рекомендую ознакомиться с разделом «Creating PyQGIS Applications» из QGIS Coding and Compilation Guide. Для демонстрации основных аспектов работы со списком слоёв я немного модифицировал пример, рассмотренный там.

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

Общие сведения

Рассматриваемый виджет разработан German Carrillo и является упрощенной версией списка слоёв QGIS. Основное отличие от оригинала — не поддерживается новая символика и отсутствуют группы слоёв.

Вот так выглядит приложение со списком слоёв

Виджет обладает следующими возможностями:

  • получение упорядоченного списка слоёв
  • изменение порядка следования слоёв в легенде с соответствующим изменением порядка слоёв карты
  • управление видимостью слоя
  • отображение/изменение символики слоя (рекомендуется создать свой собственный диалог настройки символики, автор виджета предлагает лишь очень простой пример)
  • изменение некоторых параметров слоя
  • загрузка/сохранение стилей (.qml)
  • удаление слоёв
  • интеграция с картой и инструментами, действующими на загруженные слои (Скрыть/Показать всё, Удалить всё)

Код виджета распространяется по условиям GNU GPL v2.

Подключение списка слоёв к приложению

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

  • файл legend.py, который реализует весь функционал легенды
  • несколько иконок, необходимых для отображения слоёв разных типов
  • иконки действий для выпадающего меню
  • диалог настройки свойств слоя

Инициализация

В основном классе нашего приложения импортируем класс Legend из файла legend.py

from legend import Legend

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

def createLegendWidget(self):
    # создаем легенду
    self.legend = Legend(self)
    self.legend.setCanvas(self.canvas)
    self.legend.setObjectName("theMapLegend")

    # создаем плавающую панель и добавляем к ней легенду
    self.LegendDock = QDockWidget("Layers", self)
    self.LegendDock.setObjectName("legend")
    self.LegendDock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
    self.LegendDock.setWidget(self.legend)
    self.LegendDock.setContentsMargins(9, 9, 9, 9)
    self.addDockWidget(Qt.LeftDockWidgetArea, self.LegendDock)

Вызов этого метода необходимо добавить в метод __init__() основного класса приложения. Обратите внимание, что создание легенды необходимо выполнять после создания виджета карты (QgsMapCanvas).

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        MainWindow.__init__(self)

        # Требуется Qt4 для инициализации пользовательского интерфейса
        self.setupUi(self)
        # Создаем карту
        self.canvas = QgsMapCanvas()
        …
        # создаем легенду
        self.createLegendWidget()

Использование

Виджет легенды использует несколько иконок: иконки для разных типов слоёв и иконки для контекстного меню слоя. Чтобы они отображались необходимо скомпилировать входящий в архив файл resources.qrc командой

pyrcc4 resources.qrc -o resources_rc.py

В файле legend.py уже присутствует ссылка на сгенерированый таким образом файл. Если приложение использует свой собственный ресурсный файл (а так чаще всего и бывает), есть два варианта

  • переименовать один из ресурсных файлов
  • поместить все ресурсы в один файл

В последнем случае может потребоваться задание раздельных префиксов для ресурсов, относящихся к разным частям приложения (например, один префикс для иконок легенды и второй для остальных файлов). При изменении префикса для ресурсов легенды также необходимо соответствующим образом изменить переменную resource_prefix в файле legend.py

resources_prefix = ":/legend/imgs/"

Я выбрал второй вариант: все изображения находятся в каталоге images и вложенных каталогах, в ресурсном файле создано два префикса и соответственно изменена переменная resource_prefix в файле legend.py. Обратите внимание, что помимо задания другого префикса, для каждого файла был создан псевдоним (alias).

При использовании легенды немного меняется процедура добавления слоёв. Если раньше для загрузки и отображения слоя мы использовали свой собственный метод, в котором добавляли слой и обновляли LayerSet, то теперь контролировать процесс загрузки и удаления будет виджет легенды. Виджет имеет слот, обновляющий список слоёв при каждом добавлении, удалении или перемещении слоя. Всё что от нас требуется — вызвать соответствующие методы класса QgsMapLayerRegistry (например, addMapLayer() или removeMapLayer()). А вот вызов метода setLayerSet() класса QgsMapCanvas теперь не нужен, т.к. об этом заботится виджет легенды. Его можно закомментировать или вообще удалить. Таким образом, для добавления нового слоя необходима всего одна строка кода.

QgsMapLayerRegistry.instance().addMapLayer(layer)

здесь layer — экземпляр класса QgsVectorLayer или QgsRasterLayer, подробнее об этом можно прочесть в уже упоминавшемся Coding and Compilation Guide.

Вместе в легендой поставляется простой диалог свойств слоя. Чтобы им можно было пользоваться, необходимо скомпилировать файл dlgLayerProperties.ui

pyuic4 dlgLayerProperties.ui -o dlgLayerProperties_ui.py

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

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

self.connect(self.legend, SIGNAL("activeLayerChanged"), self.enableTools)

def enableTools(self):
    if not self.legend.activeLayer():
        # нет активного слоя, деактивируем инструменты общего назначения
    else:
        # делаем инструменты общего назначения доступными
        …
        layerType = self.legend.activeLayer().layer().type()
        if layerType == 0: # Vector Layer
            # активируем инструменты для работы с вектором и деактивируем остальные
        elif layerType == 1: # Raster Layer
            # активируем инструменты для работы с растром и деактивируем остальные

Также виджет предоставляет несколько полезных методов, с помощью которых можно

  • перебрать все слои
    for layer in self.legend.layers:
        # сделать что-то со слоем
  • скрыть или отобразить все слои
    def showAllLayers(self):
        self.legend.setStatusForAllLayers(True)
  • получить активный слой
    return self.legend.activeLayer()
  • обновить символику слоя
    self.legend.refreshLayerSymbology(layer)
  • удалить слои с заданными идентификаторами
    self.legend.removeLayers(layerIds)

Разумеется, это далеко не полный список методов рассматриваемого виджета. Более полное представление о его возможностях можно получить заглянув в файл legend.py, код достаточно прозрачный и снабжен комментариями, так что разобраться в нем не составит труда.

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

Исходные коды примера, а так же все необходимые изображения и тестовый набор данных можно скачать одним файлом.

Необходимо отметить, что существует еще один вариант легенды, созданный Aaron Racicot для проекта OpenOceanMap и основанный на элементе управления QCheckBox, а не на QTreeWidget.

Мітки: ,

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

*