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

В данном разделе рассмотрим создание простейшего приложения, которое можно запускать из оболочки 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_()

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

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

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

    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_()

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

## Пример приложения из готовых компонентов

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

- LayerControlWidget - Виджет управления слоями карты.

- ViewManagerWidget - Виджет списка окон.

- DataManagerWidget - Виджет управления списком открытых данных.

- PythonConsoleWidget - Виджет ввода команд python.

- NotificationWidget - Виджет уведомлений.

    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_()

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