Создание приложения

В данном разделе рассмотрим создание простейшего приложения, которое можно запускать из оболочки python. При этом пользовательский интерфейс будет строится исходя из предпочтений пользователя. В рамках примера создадим приложение, которое будет открывать файл и показывать его в окне карты. Также вставим стандартное окно управления слоями карты axipy.LayerControlWidget.

Примечание

Для использования библиотеки axipy без интерфейса Аксиомы требуется платная лицензия.

Первым шагом проинициализируем ядро (подробнее см. Initialization, Finalization, and Threads) и определим главное окно нашего будущего приложения. Код будет выглядеть следующим образом:

from PySide2.QtWidgets import QMainWindow
from axipy import init_axioma


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Пример окна приложения")


# Инициализация ядра
app = init_axioma()

# Создание и отображение главного окна
main_window = MainWindow()
main_window.resize(1200, 800)
main_window.show()

# Запуск основного цикла программы
app.exec_()

После того как мы создали пустое окно добавим панель инструментов со стандартными действиями (полный список действий можно посмотреть axipy.ActionManager.items()). Код будет выглядеть следующим образом:

from PySide2.QtWidgets import QMainWindow
from axipy import init_axioma, ActionManager


class MainWindow(QMainWindow):

    def __init__(self) -> None:
        super().__init__()
        self.setWindowTitle("Пример окна приложения")
        self._add_buttons()

    def _add_buttons(self) -> None:
        def _add_action(name) -> None:
            # Добавляем системное действие
            act = ActionManager.get(name)
            if act:
                self.toolbar.addAction(act)

        # Создаем панель инструментов
        self.toolbar = self.addToolBar("Панель")
        # Добавляем стандартные кнопки
        _add_action("SaveTables")
        _add_action("Select")
        _add_action("Pan")
        _add_action("ZoomIn")
        _add_action("ZoomOut")
        _add_action("PointDraw")


# Инициализация ядра
app = init_axioma()

# Создание и отображение главного окна
main_window = MainWindow()
main_window.resize(1200, 800)
main_window.show()

# Запуск основного цикла программы
app.exec_()

После запуска окно будет выглядеть примерно так:

../_images/main_window_empty.png

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

Результирующий код будет выглядеть следующим образом:

from PySide2.QtCore import Qt
from PySide2.QtWidgets import QMainWindow, QFileDialog, QDockWidget, QAction
from axipy import (
    init_axioma, provider_manager, Layer, view_manager, Map, LayerControlWidget, ActionManager
)


class MainWindow(QMainWindow):

    def __init__(self) -> None:
        super().__init__()
        self.setWindowTitle("Пример окна приложения")
        self._add_buttons()

    # Открытие файла
    def __open_file(self) -> None:
        file_name, _ = QFileDialog.getOpenFileName(self, "Открыть", filter="MapInfo TAB (*.tab)")
        if file_name:
            table = provider_manager.openfile(file_name)
            # создаем слой
            layer = Layer.create(table)
            # если карты нет, то создаем ее
            if not view_manager.active:
                map_ = Map([layer])
                mapview = view_manager.create_mapview(map_)
                self._create_layer_control_dock()
                view_manager.activate(mapview)
                self.setCentralWidget(mapview.widget)
            # если есть, добавляем слой в окно карты
            else:
                view_manager.active.map.layers.append(layer)

    # Добавление по левой стороне окно управления слоями карты
    def _create_layer_control_dock(self) -> None:
        self._layer_control_w = LayerControlWidget()
        dock_layer_control = QDockWidget(self._layer_control_w.widget.windowTitle(), self)
        dock_layer_control.setWidget(self._layer_control_w.widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock_layer_control)

    # Добавление кнопок на панель инструментов
    def _add_buttons(self) -> None:
        # Создаем панель инструментов
        self.toolbar = self.addToolBar("Панель")

        # Пользовательское действие открытия файла
        self.action_open = QAction(ActionManager.icon_by_name("open"), "Открыть файл")
        self.action_open.triggered.connect(self.__open_file)
        self.toolbar.addAction(self.action_open)

        def _add_action(name) -> None:
            # Добавляем системное действие
            act = ActionManager.get(name)
            if act:
                self.toolbar.addAction(act)

        _add_action("SaveTables")
        _add_action("Select")
        _add_action("Pan")
        _add_action("ZoomIn")
        _add_action("ZoomOut")
        _add_action("PointDraw")


# Инициализация ядра
app = init_axioma()

# Создание и отображение главного окна
main_window = MainWindow()
main_window.resize(1200, 800)
main_window.show()

# Запуск основного цикла программы
app.exec_()

Результат работы:

../_images/main_window.png

Следующим этапом попробуем усложнить пример и сделать приложение, которое содержит помимо окна карты и окна с деревом слоев и другие. Перечислим их:

from PySide2.QtCore import Qt, Slot
from PySide2.QtWidgets import QMainWindow, QDockWidget, QStackedWidget

import os
from axipy import (Notifications, LayerControlWidget, DataManagerWidget, NotificationWidget, ViewManagerWidget,
                PythonConsoleWidget, view_manager, init_axioma, provider_manager, Layer, Map, View, ActionManager)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Пример окна приложения")

        self._stacked_widget = QStackedWidget()
        view_manager.active_changed.connect(self.set_stacked_widget)

        self.setCentralWidget(self._stacked_widget)
        self.__initButtons()

    def _add_action(self, id):
        act = ActionManager[id]
        if act:
            self.toolbar.addAction(act)
            self.menu.addAction(act)

    def __initButtons(self):
        self.toolbar = self.addToolBar('Панель')
        self.menu = self.menuBar().addMenu('Меню')
        self._add_action('Select')
        self._add_action('SelectInRect')
        self._add_action('Pan')
        self._add_action('ZoomIn')
        self._add_action('ZoomOut')
        self.toolbar.addSeparator()
        self._add_action('PointDraw')
        self._add_action('RectangleDraw')
        self._add_action('SymbolStyle')
        ActionManager.activate("Pan")

    def _create_maps_dock(self):
        self._layer_control_w = LayerControlWidget()
        self._layer_control_w.mapview_activated.connect(self.set_center_widget)
        dock_layer_control = QDockWidget(self._layer_control_w.widget.windowTitle(), main_window)
        dock_layer_control.setWidget(self._layer_control_w.widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock_layer_control)

    def _create_data_manager_dock(self):
        data_manager_w = DataManagerWidget()
        dock_catalog = QDockWidget(data_manager_w.widget.windowTitle())
        dock_catalog.setWidget(data_manager_w.widget)

        def notify_selection():
            """
            Отслеживание выборки в списке открытых данных.
            """
            objects = data_manager_w.objects
            if len(objects) > 0:
                names = ', '.join(obj.name for obj in objects)
                Notifications.push("Выбрано", names, Notifications.Warning)

        data_manager_w.selection_changed.connect(notify_selection)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock_catalog)

    def _create_notification_dock(self):
        notification_w = NotificationWidget()
        notification_w.widget.setFixedHeight(150)
        dock_notification = QDockWidget(notification_w.widget.windowTitle())
        dock_notification.setWidget(notification_w.widget)
        self.addDockWidget(Qt.BottomDockWidgetArea, dock_notification)

    def _create_python_dock(self):
        notification_w = PythonConsoleWidget()
        notification_w.widget.setFixedHeight(150)
        dock_notification = QDockWidget(notification_w.widget.windowTitle())
        dock_notification.setWidget(notification_w.widget)
        self.addDockWidget(Qt.BottomDockWidgetArea, dock_notification)

    def _create_view_manager_dock(self):
        self._view_manager_w = ViewManagerWidget()
        self._view_manager_w.view_changed.connect(self.set_center_widget)
        dock_widget = QDockWidget(self._view_manager_w.widget.windowTitle(), main_window)
        dock_widget.setWidget(self._view_manager_w.widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock_widget)

    def init_gui(self):
        # Окно управления слоями
        self._create_maps_dock()
        # Открытые источники
        self._create_data_manager_dock()
        # Окно уведомлений
        self._create_notification_dock()
        # Окно консоли python
        self._create_python_dock()
        # Список окон
        self._create_view_manager_dock()

    @Slot(View)
    def set_center_widget(self, inp_view: View):
        """
        Устанавливает активное окно.
        """
        view_manager.activate(inp_view)

    @Slot()
    def set_stacked_widget(self):
        w = view_manager.active.widget
        i = self._stacked_widget.indexOf(w)
        if i == -1:
            self._stacked_widget.insertWidget(0, w)
        else:
            self._stacked_widget.setCurrentIndex(i)


# Инициализция ядра
app = init_axioma()

# Создаем главное окно приложения
main_window = MainWindow()
main_window.init_gui()


# Открываем таблицы
def path_to_file(file_name: str) -> str:
    return os.path.join(os.path.dirname(__file__), "tab", file_name)


table_world = provider_manager.openfile(path_to_file("world.tab"))
table_world_cap = provider_manager.openfile(path_to_file("worldcap.tab"))
table_rf = provider_manager.openfile(path_to_file("SubjectRF.TAB"))

# Создаем слои
layer_world = Layer.create(table_world)
layer_world_cap = Layer.create(table_world_cap)
layer_rf = Layer.create(table_rf)

# Создаем окно карты
map_world_all = Map([layer_world_cap, layer_world])
mapview = view_manager.create_mapview(map_world_all)

# Еще одна карта
map_world = Map([layer_rf, layer_world])
view_manager.create_mapview(map_world)

# Таблицы просмотра
view_manager.create_tableview(table_world)
view_manager.create_tableview(table_rf)

# Отчет
#view_manager.create_reportview()

# Первое окно как основное
main_window.set_center_widget(mapview)

# Левый верхний угол окна
x, y = 200, 10
# Ширина и высота окна
width, height = 1200, 800
main_window.resize(width, height)
main_window.move(x, y)

# Показываем главное окно
main_window.show()
app.exec_()

Результат работы:

../_images/app_custom.png