Не отображается имя в QTreeWidget

Рейтинг: 0Ответов: 0Опубликовано: 16.08.2025

Пытаюсь написать структуру для проекта, вроде всё работает, но вот имя не отображается в дереве. Хотя настройки видят правильное имя проекта. Пробовал всё, что только можно, не понимаю абсолютно, почему так происходит введите сюда описание изображения введите сюда описание изображения

tree.py

import sys
from PyQt5.QtWidgets import (
    QApplication, QTreeWidget, QTreeWidgetItem, QWidget,
    QVBoxLayout, QMainWindow, QMenu, QAction, QInputDialog,
    QMessageBox, QPushButton, QHBoxLayout, QLabel, QLineEdit,
    QFormLayout, QSpinBox, QDoubleSpinBox, QDateEdit, QGroupBox,
    QDialog, QComboBox
)
from PyQt5.QtCore import Qt, QDate

try:
    from _project import Project, createProject
except ImportError as e:
    print("Ошибка: не удалось импортировать _project.py")
    print(e)
    sys.exit(1)

# === Главное окно ===
class TreeWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Система управления проектами")
        self.resize(700, 600)

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)

        self.create_project_btn = QPushButton("➕ Создать проект")
        self.create_project_btn.clicked.connect(self.create_new_project)
        layout.addWidget(self.create_project_btn)

        # === QTreeWidget ===
        self.tree = QTreeWidget()
        self.tree.setHeaderLabels(["Элемент"])
        self.tree.itemClicked.connect(self.on_item_clicked)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.open_context_menu)
        layout.addWidget(self.tree)

        # Скрыть дерево, если нет проектов
        #self.tree.hide()

        # Храним текущий активный проект
        #self.current_project = None

    def create_new_project(self):
        dialog = ProjectCreationDialog(self)
        if dialog.exec_() == QDialog.Accepted:
            data = dialog.get_data()

            # Создаём проект
            project = createProject(
                name=data["name"],
                autor=data["author"],
                start_date=data["start_date"]
            )

            # Обновляем атрибуты проекта
            project._ambientMinTemp5Day = data["ambientMinTemp5Day"]
            project._ambientMinTemp = data["ambientMinTemp"]
            project._ambientMaxTemp = data["ambientMaxTemp"]
            project._startUpMinTemp = data["startUpMinTemp"]
            project._fiveDaysDiameter = data["fiveDaysDiameter"]
            project._exZone = data["exZone"]
            project._nomVoltagePN = data["nomVoltagePN"]
            project._nomVoltagePP = data["nomVoltagePP"]
            project._nomVoltageUp = data["nomVoltageUp"]
            project._nomVoltageDown = data["nomVoltageDown"]
            project._circuitBreakerMaxCurrent = data["circuitBreakerMaxCurrent"]

            # Добавляем проект в дерево
            self.add_project_to_tree(project)

            # Показываем дерево (если было скрыто)
            self.tree.show()

    def add_project_to_tree(self, project):
        """Добавляет проект в QTreeWidget"""
        item = QTreeWidgetItem([project._projectName])
        item.setData(0, 1, project)
        item.setData(0, 2, "project")
        self.tree.addTopLevelItem(item)

    def on_item_clicked(self, item, column):
        obj = item.data(0, 1)
        if obj:
            print(f"Выбран: {item.text(0)}")

    def open_context_menu(self, position):
        """Контекстное меню"""
        item = self.tree.itemAt(position)
        if not item:
            return

        node_type = item.data(0, 2)
        menu = QMenu(self)

        if node_type == "project":
            project = item.data(0, 1)

            # Переименовать
            rename_action = QAction("🔁 Переименовать проект", self)
            rename_action.triggered.connect(lambda: self.rename_project(item, project))

            # Сохранить
            save_action = QAction("💾 Сохранить проект", self)
            save_action.triggered.connect(lambda: self.save_project(project))

            # Загрузить (пример, можно расширить)
            load_action = QAction("📥 Загрузить проект", self)
            load_action.triggered.connect(lambda: self.load_project())

            # Настройки
            settings_action = QAction("⚙️ Настройки проекта", self)
            settings_action.triggered.connect(lambda: self.edit_project_settings(item, project))

            # Создать трубопровод
            new_pipe_action = QAction("➕ Создать трубопровод", self)
            new_pipe_action.triggered.connect(lambda: self.create_pipe_line(item, project))

            menu.addAction(rename_action)
            menu.addAction(save_action)
            menu.addAction(load_action)
            menu.addAction(settings_action)
            menu.addSeparator()
            menu.addAction(new_pipe_action)

        elif node_type == "pipe":
            pipe = item.data(0, 1)

            rename_action = QAction("🔁 Переименовать трубу", self)
            rename_action.triggered.connect(lambda: self.rename_pipe(item, pipe))

            calc_action = QAction("🧮 Рассчитать EHT", self)
            calc_action.triggered.connect(pipe.calculateEHT)

            menu.addAction(rename_action)
            menu.addAction(calc_action)

        elif node_type == "segment":
            edit_action = QAction("📝 Редактировать сегмент", self)
            edit_action.triggered.connect(lambda: self.edit_segment(item))
            menu.addAction(edit_action)

        menu.exec_(self.tree.viewport().mapToGlobal(position))

    def rename_project(self, item, project):
        text, ok = QInputDialog.getText(
            self, "Переименовать проект", "Новое имя:",
            text=project._projectName
        )
        if ok and text.strip():
            new_name = text.strip()

            project._projectName = new_name  # сначала обновляем объект
            item.setText(0, new_name)        # потом отражаем в дереве

            item.setData(0, 1, project)
            item.setData(0, 2, "project")


    def rename_pipe(self, item, pipe):
        text, ok = QInputDialog.getText(
            self, "Переименовать трубу", "Новое имя:",
            text=pipe._pipeLineName
        )
        if ok and text.strip():
            pipe._pipeLineName = text.strip()
            item.setText(0, text.strip())

    def edit_segment(self, item):
        segment = item.data(0, 1)
        msg = (
            f"🔢 Номер сегмента: {segment._segmentNumber}\n"
            f"📏 Длина: {segment._segmentLength} м\n"
            f"🌡 Температура поддержания: {segment._tempMaintain} °C\n"
            f"🏗 Тип изоляции: {segment._insulationType}\n"
            f"📍 Координаты подключения: {segment._connCoordinates}"
        )
        QMessageBox.information(self, "Свойства сегмента", msg)

    def save_project(self, project):
        filename, ok = QInputDialog.getText(
            self, "Сохранить проект", "Имя файла (без расширения):",
            text=f"{project._projectName}.json"
        )
        if ok and filename.strip():
            if not filename.endswith(".json"):
                filename += ".json"
            try:
                project.saveProject(filename)
                QMessageBox.information(self, "Сохранение", f"Проект сохранён как:\n{filename}")
            except Exception as e:
                QMessageBox.critical(self, "Ошибка", f"Не удалось сохранить проект:\n{str(e)}")

    def load_project(self):
        filename, ok = QInputDialog.getText(
            self, "Загрузить проект", "Имя файла (с расширением .json):"
        )
        if ok and filename.strip():
            try:
                project = Project.loadProject(filename.strip())
                self.add_project_to_tree(project)
                self.tree.show()
                self.create_project_btn.hide()
                QMessageBox.information(self, "Загрузка", f"Проект '{project._projectName}' загружен.")
            except Exception as e:
                QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить проект:\n{str(e)}")

    def edit_project_settings(self, item, project):
        dialog = ProjectSettingsDialog(project, self)
        if dialog.exec_() == QDialog.Accepted:
            props = dialog.get_properties()
            project.setProjectProperties(props)  # обновляем объект

            # Обновляем видимые данные в дереве
            new_name = project._projectName
            item.setText(0, new_name)               # изменяем отображаемый текст
            item.setData(0, 1, project)             # обновляем хранимый объект
            item.setData(0, 2, "project")           # сохраняем тип узла

            print(f"Проект переименован в: {new_name}")  # отладка

            


    def create_pipe_line(self, project_item, project):
        name, ok = QInputDialog.getText(self, "Новый трубопровод", "Имя трубопровода:")
        if ok and name.strip():
            pipe = project.createPipeLine(name.strip())
            pipe_item = QTreeWidgetItem([pipe._pipeLineName])
            pipe_item.setData(0, 1, pipe)
            pipe_item.setData(0, 2, "pipe")
            project_item.addChild(pipe_item)
# === Диалог создания проекта ===
class ProjectCreationDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Создать новый проект")
        self.resize(400, 500)
        layout = QVBoxLayout(self)

        # Форма
        form = QFormLayout()

        self.name_edit = QLineEdit()
        self.author_edit = QLineEdit()
        self.date_edit = QDateEdit()
        self.date_edit.setDisplayFormat("dd.MM.yyyy")
        self.date_edit.setDate(QDate.currentDate())
        self.date_edit.setCalendarPopup(True)

        form.addRow("Название проекта:", self.name_edit)
        form.addRow("Автор:", self.author_edit)
        form.addRow("Дата начала:", self.date_edit)

        layout.addLayout(form)

        # Группа климатических условий
        climate_group = QGroupBox("Климатические условия")
        climate_layout = QFormLayout()

        self.amb_min_5day = QDoubleSpinBox()
        self.amb_min_5day.setRange(-100, 100)
        self.amb_min_5day.setValue(-35)
        climate_layout.addRow("Мин. t₅ дней (°C):", self.amb_min_5day)

        self.amb_min = QDoubleSpinBox()
        self.amb_min.setRange(-100, 100)
        self.amb_min.setValue(-40)
        climate_layout.addRow("Мин. t (°C):", self.amb_min)

        self.amb_max = QDoubleSpinBox()
        self.amb_max.setRange(-100, 100)
        self.amb_max.setValue(40)
        climate_layout.addRow("Макс. t (°C):", self.amb_max)

        self.startup_min = QDoubleSpinBox()
        self.startup_min.setRange(-100, 100)
        self.startup_min.setValue(-20)
        climate_layout.addRow("Мин. t пуска (°C):", self.startup_min)

        self.diameter_5days = QDoubleSpinBox()
        self.diameter_5days.setRange(0, 1000)
        self.diameter_5days.setValue(150)
        climate_layout.addRow("Диаметр 150 мм:", self.diameter_5days)

        climate_group.setLayout(climate_layout)
        layout.addWidget(climate_group)

        # Взрывоопасная зона — через QInputDialog.getItem
        self.ex_zone_combo = QComboBox()
        self.ex_zone_combo.addItems(["Нет", "Да"])
        layout.addWidget(QLabel("Взрывоопасная зона:"))
        layout.addWidget(self.ex_zone_combo)

        voltage_group = QGroupBox("Параметры сети")
        voltage_layout = QFormLayout()

        self.voltage_pn = QDoubleSpinBox()
        self.voltage_pn.setRange(0, 1000)
        self.voltage_pn.setValue(230)
        voltage_layout.addRow("Uₚₙ (В):", self.voltage_pn)

        self.voltage_pp = QDoubleSpinBox()
        self.voltage_pp.setRange(0, 1000)
        self.voltage_pp.setValue(400)
        voltage_layout.addRow("Uₚₚ (В):", self.voltage_pp)

        self.voltage_up = QDoubleSpinBox()
        self.voltage_up.setRange(0, 1000)
        self.voltage_up.setValue(690)
        voltage_layout.addRow("Uₚₐₙₑₗ (В):", self.voltage_up)

        self.voltage_down = QDoubleSpinBox()
        self.voltage_down.setRange(0, 1000)
        self.voltage_down.setValue(24)
        voltage_layout.addRow("Uₙₐₚᵣₐₕ (В):", self.voltage_down)

        self.cb_current = QDoubleSpinBox()
        self.cb_current.setRange(0, 10000)
        self.cb_current.setValue(0)
        voltage_layout.addRow("Макс. ток АВ (А):", self.cb_current)

        voltage_group.setLayout(voltage_layout)
        layout.addWidget(voltage_group)

        buttons = QHBoxLayout()
        ok_btn = QPushButton("Создать")
        ok_btn.clicked.connect(self.accept)
        cancel_btn = QPushButton("Отмена")
        cancel_btn.clicked.connect(self.reject)
        buttons.addStretch()
        buttons.addWidget(ok_btn)
        buttons.addWidget(cancel_btn)
        layout.addLayout(buttons)

    def get_data(self):
        return {
            "name": self.name_edit.text().strip() or "Безымянный проект",
            "author": self.author_edit.text().strip() or "Неизвестный автор",
            "start_date": self.date_edit.date().toPyDate(),

            "ambientMinTemp5Day": self.amb_min_5day.value(),
            "ambientMinTemp": self.amb_min.value(),
            "ambientMaxTemp": self.amb_max.value(),
            "startUpMinTemp": self.startup_min.value(),
            "fiveDaysDiameter": self.diameter_5days.value(),

            "exZone": self.ex_zone_combo.currentText() == "Да",

            "nomVoltagePN": self.voltage_pn.value(),
            "nomVoltagePP": self.voltage_pp.value(),
            "nomVoltageUp": self.voltage_up.value(),
            "nomVoltageDown": self.voltage_down.value(),
            "circuitBreakerMaxCurrent": self.cb_current.value() or None,
        }


class ProjectSettingsDialog(QDialog):
    def __init__(self, project, parent=None):
        super().__init__(parent)
        self.setWindowTitle(f"Настройки проекта: {project._projectName}")
        self.project = project
        layout = QVBoxLayout(self)

        form = QFormLayout()

        self.name_edit = QLineEdit(project._projectName or "")
        self.author_edit = QLineEdit(project._projectAutor or "")

        self.amb_min_5day = QDoubleSpinBox()
        self.amb_min_5day.setRange(-100, 100)
        self.amb_min_5day.setValue(project._ambientMinTemp5Day)

        self.amb_min = QDoubleSpinBox()
        self.amb_min.setRange(-100, 100)
        self.amb_min.setValue(project._ambientMinTemp)

        self.amb_max = QDoubleSpinBox()
        self.amb_max.setRange(-100, 100)
        self.amb_max.setValue(project._ambientMaxTemp)

        self.startup_min = QDoubleSpinBox()
        self.startup_min.setRange(-100, 100)
        self.startup_min.setValue(project._startUpMinTemp)

        self.diameter_5days = QDoubleSpinBox()
        self.diameter_5days.setRange(0, 1000)
        self.diameter_5days.setValue(project._fiveDaysDiameter)

        self.voltage_pn = QDoubleSpinBox()
        self.voltage_pn.setRange(0, 1000)
        self.voltage_pn.setValue(project._nomVoltagePN)

        self.voltage_pp = QDoubleSpinBox()
        self.voltage_pp.setRange(0, 1000)
        self.voltage_pp.setValue(project._nomVoltagePP)

        self.voltage_up = QDoubleSpinBox()
        self.voltage_up.setRange(0, 1000)
        self.voltage_up.setValue(project._nomVoltageUp)

        self.voltage_down = QDoubleSpinBox()
        self.voltage_down.setRange(0, 1000)
        self.voltage_down.setValue(project._nomVoltageDown)

        self.cb_current = QDoubleSpinBox()
        self.cb_current.setRange(0, 10000)
        self.cb_current.setValue(project._circuitBreakerMaxCurrent or 0)

        form.addRow("Название:", self.name_edit)
        form.addRow("Автор:", self.author_edit)
        form.addRow("Мин. t₅ дней (°C):", self.amb_min_5day)
        form.addRow("Мин. t (°C):", self.amb_min)
        form.addRow("Макс. t (°C):", self.amb_max)
        form.addRow("Мин. t пуска (°C):", self.startup_min)
        form.addRow("Диаметр 150 мм:", self.diameter_5days)

        # Выпадающий список для взрывоопасной зоны
        self.ex_combo = QComboBox()
        self.ex_combo.addItems(["Нет", "Да"])
        self.ex_combo.setCurrentText("Да" if project._exZone else "Нет")
        form.addRow("Взрывоопасная зона:", self.ex_combo)

        form.addRow("Uₚₙ (В):", self.voltage_pn)
        form.addRow("Uₚₚ (В):", self.voltage_pp)
        form.addRow("Uₚₐₙₑₗ (В):", self.voltage_up)
        form.addRow("Uₙₐₚᵣₐₕ (В):", self.voltage_down)
        form.addRow("Макс. ток АВ (А):", self.cb_current)

        layout.addLayout(form)

        buttons = QHBoxLayout()
        ok_btn = QPushButton("Сохранить")
        ok_btn.clicked.connect(self.accept)
        cancel_btn = QPushButton("Отмена")
        cancel_btn.clicked.connect(self.reject)
        buttons.addStretch()
        buttons.addWidget(ok_btn)
        buttons.addWidget(cancel_btn)
        layout.addLayout(buttons)

    def get_properties(self):
        return {
            "projectName": self.name_edit.text().strip(),
            "projectAutor": self.author_edit.text().strip(),
            "ambientMinTemp5Day": self.amb_min_5day.value(),
            "ambientMinTemp": self.amb_min.value(),
            "ambientMaxTemp": self.amb_max.value(),
            "startUpMinTemp": self.startup_min.value(),
            "fiveDaysDiameter": self.diameter_5days.value(),
            "exZone": self.ex_combo.currentText() == "Да",
            "nomVoltagePN": self.voltage_pn.value(),
            "nomVoltagePP": self.voltage_pp.value(),
            "nomVoltageUp": self.voltage_up.value(),
            "nomVoltageDown": self.voltage_down.value(),
            "circuitBreakerMaxCurrent": self.cb_current.value() or None,
        }


# === Запуск приложения ===
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = TreeWindow()
    window.show()
    sys.exit(app.exec_())

project.py

# КЛАСС ПРОЕКТ
import uuid
from datetime import date, datetime
from _pipeLine import PipeLine
import json
def serialize_obj(obj):
    """
    Позволяет json.dumps() корректно обрабатывать:
    - uuid.UUID → str
    - date, datetime → ISO-строка
    """
    if isinstance(obj, uuid.UUID):
        return str(obj)
    elif isinstance(obj, (date, datetime)):
        return obj.isoformat()
    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
def createProject(name=None, autor=None, start_date=None):
    return Project(projectName=name, projectAutor=autor, projectStartDate=start_date)

class Project:
    def __init__(self, projectName=None, projectAutor=None, projectStartDate=date.today()):
        # Имя проекта
        self._projectName = projectName
        self._projectAutor = projectAutor
        self._projectStartDate = projectStartDate
        self._projectCurrentRevision = 1
        
        self._projectID = uuid.uuid4()

        self._ambientMinTemp5Day = -35
        self._ambientMinTemp = -40
        self._ambientMaxTemp = 40
        self._startUpMinTemp  = -20
        self._fiveDaysDiameter = 150

        # Атрибуты взрывоопасной зоны
        self._exZone = True

        self._nomVoltagePN = 230
        self._nomVoltagePP = 400
        self._nomVoltageUp = 690
        self._nomVoltageDown = 24
        self._circuitBreakerMaxCurrent = None
        
        # Объекты проекта
        self._pipeLines = []
        self._pipeSegments = []

        self._deletedPipeLines = []
        self._deletedPipeSegments = []

        self._pipeLinesCounter = 0

    def getProjectProperties(self):
        ProjectProperties = {"projectName":self._projectName, 
                             "projectAutor":self._projectAutor, 
                             "ambientMinTemp5Day":self._ambientMinTemp5Day,
                             "ambientMinTemp":self._ambientMinTemp,
                             "ambientMaxTemp":self._ambientMaxTemp,
                             "startUpMinTemp":self._startUpMinTemp,
                             "fiveDaysDiameter":self._fiveDaysDiameter,
                             "exZone":self._exZone,
                             "nomVoltagePN":self._nomVoltagePN,
                             "nomVoltagePP":self._nomVoltagePP,
                             "nomVoltageUp":self._nomVoltageUp,
                             "nomVoltageDown":self._nomVoltageDown,
                             "circuitBreakerMaxCurrent":self._circuitBreakerMaxCurrent,
                             }
        return ProjectProperties
    
    def setProjectProperties(self, ProjectProperties):
        self._projectName = ProjectProperties["projectName"]
        self._projectAutor = ProjectProperties["projectAutor"]
        self._ambientMinTemp5Day = ProjectProperties["ambientMinTemp5Day"]
        self._ambientMinTemp = ProjectProperties["ambientMinTemp"]
        self._ambientMaxTemp = ProjectProperties["ambientMaxTemp"]
        self._startUpMinTemp = ProjectProperties["startUpMinTemp"]
        self._fiveDaysDiameter = ProjectProperties["fiveDaysDiameter"]
        self._exZone = ProjectProperties["exZone"]
        self._nomVoltagePN = ProjectProperties["nomVoltagePN"]
        self._nomVoltagePP = ProjectProperties["nomVoltagePP"]
        self._nomVoltageUp = ProjectProperties["nomVoltageUp"]
        self._nomVoltageDown = ProjectProperties["nomVoltageDown"]
        self._circuitBreakerMaxCurrent = ProjectProperties["circuitBreakerMaxCurrent"]
        return
    # Создание объектов
    def createPipeLine(self, pipeLineName):
        self._pipeLinesCounter += 1
        newPipeLine = PipeLine(pipeLineName, self)
        newPipeLine._pipeLineNumber = self._pipeLinesCounter
        self._pipeLines.append(newPipeLine)

        return newPipeLine
    
    def deletePipeLine(self, pipeLine):
        if pipeLine in self._pipeLines:
            self._pipeLines.remove(pipeLine)
            self._deletedPipeLines.append(pipeLine)


    def createPipeSegment(self):
        pass


    # Другие типы обогреваемых объектов будут добавлены позднее
    # def createVessel(self):
    #     pass
    # def createInstrument(self):
    #     pass
    # def createRoof(self):
    #     pass
    # def createFloor(self):
    #     pass
    
    

    # Если происходили изменения в настройках проекта, нужно обновить их для всех обогреваемых объектов
    def updateJoinedObjects(self):
        for pipeLine in self._pipeLines:
            pipeLine.sync_with_project()


# СОХРАНЕНИЕ И ЗАГРУЗКА
    



    
    def to_dict(self):
        return {
            "projectID": self._projectID,
            "projectName": self._projectName,
            "projectAutor": self._projectAutor,
            "projectStartDate": self._projectStartDate,
            "projectCurrentRevision": self._projectCurrentRevision,
            "projectProperties": self.getProjectProperties(),
            "pipeLines": [pl.to_dict() for pl in self._pipeLines]
        }

    @staticmethod
    def from_dict(data, insulationLib=None):
        from _InsulationLib import defaultInsulationLib
        if insulationLib is None:
            insulationLib = defaultInsulationLib

        start_date = date.fromisoformat(data["projectStartDate"]) if data["projectStartDate"] else date.today()

        project = Project(
            projectName=data["projectName"],
            projectAutor=data["projectAutor"],
            projectStartDate=start_date
        )
        project._projectID = uuid.UUID(data["projectID"])
        project._projectCurrentRevision = data["projectCurrentRevision"]
        project.setProjectProperties(data["projectProperties"])

        for pl_data in data["pipeLines"]:
            pipeLine = PipeLine.from_dict(pl_data, project, insulationLib)
            project._pipeLines.append(pipeLine)
            project._pipeLinesCounter = max(project._pipeLinesCounter, pipeLine._pipeLineNumber)

        return project
    

    def saveProject(self, filename: str) -> None:
        """
        Сохраняет проект в JSON-файл с использованием to_dict() и пользовательского сериализатора.

        :param filename: Имя файла (например, 'my_project.json')
        """
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(
                    self.to_dict(),           # преобразуем весь проект в словарь
                    f,
                    default=serialize_obj,    # обрабатываем UUID, date и т.д.
                    ensure_ascii=False,
                    indent=4
                )
            print(f"✅ Проект успешно сохранён: {filename}")
        except Exception as e:
            print(f"❌ Ошибка при сохранении проекта: {e}")
            raise


    @staticmethod
    def loadProject(filename: str, insulationLib=None):
        """
        Загружает проект из JSON-файла.

        :param filename: Путь к файлу
        :param insulationLib: Библиотека изоляции (по умолчанию — defaultInsulationLib)
        :return: Новый объект Project
        """
        # Подгружаем библиотеку изоляции, если не передана
        if insulationLib is None:
            from _InsulationLib import defaultInsulationLib
            insulationLib = defaultInsulationLib

        try:
            with open(filename, 'r', encoding='utf-8') as f:
                data = json.load(f)  # Загружаем словарь из JSON

            # Восстанавливаем проект через from_dict
            project = Project.from_dict(data, insulationLib=insulationLib)
            print(f"✅ Проект успешно загружен: {filename}")
            return project

        except FileNotFoundError:
            print(f"❌ Файл не найден: {filename}")
            raise
        except KeyError as e:
            print(f"❌ Ошибка структуры файла (отсутствует ключ): {e}")
            raise
        except Exception as e:
            print(f"❌ Ошибка при загрузке проекта: {e}")
            raise

Ответы

Ответов пока нет.