from PyQt5.QtWidgets import ( QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QDoubleSpinBox, QComboBox, QPushButton, QTableWidget, QTableWidgetItem, QLineEdit, QMessageBox ) from PyQt5.QtCore import Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Калькулятор питательных сред") self.setGeometry(100, 100, 800, 600) self._init_ui() def _init_ui(self): """Инициализирует все виджеты интерфейса""" central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) # Секция параметров среды params_layout = QHBoxLayout() # Общее количество среды amount_layout = QHBoxLayout() amount_layout.addWidget(QLabel("Общее количество:")) self.amount_input = QDoubleSpinBox() self.amount_input.setRange(0.001, 1000000) self.amount_input.setValue(1000.0) self.amount_input.setSingleStep(10) amount_layout.addWidget(self.amount_input) # Единица измерения self.amount_unit_combo = QComboBox() self.amount_unit_combo.addItems(["нг", "мкг", "мг", "г", "кг", "нл", "мкл", "мл", "л"]) self.amount_unit_combo.setCurrentText("мл") amount_layout.addWidget(self.amount_unit_combo) # Растворитель solvent_layout = QHBoxLayout() solvent_layout.addWidget(QLabel("Растворитель:")) self.solvent_input = QLineEdit() self.solvent_input.setText("Вода") solvent_layout.addWidget(self.solvent_input) params_layout.addLayout(amount_layout) params_layout.addSpacing(20) params_layout.addLayout(solvent_layout) params_layout.addStretch() layout.addLayout(params_layout) # Таблица реагентов self.table = QTableWidget() self.table.setColumnCount(5) self.table.setHorizontalHeaderLabels([ "Название реагента", "Процент (%)", "Единица измерения", "Коэффициент пересчёта", "Результат" ]) layout.addWidget(self.table) # Кнопки управления buttons_layout = QHBoxLayout() self.add_row_btn = QPushButton("Добавить реагент") self.remove_row_btn = QPushButton("Удалить реагент") self.calculate_btn = QPushButton("Рассчитать") self.save_btn = QPushButton("Сохранить") self.load_btn = QPushButton("Загрузить") buttons_layout.addWidget(self.add_row_btn) buttons_layout.addWidget(self.remove_row_btn) buttons_layout.addWidget(self.calculate_btn) buttons_layout.addWidget(self.save_btn) buttons_layout.addWidget(self.load_btn) buttons_layout.addStretch() layout.addLayout(buttons_layout) # Добавляем начальную строку self.add_initial_row() def add_initial_row(self): """Добавляет начальную строку в таблицу""" self.table.insertRow(0) self.table.setItem(0, 0, QTableWidgetItem("Реагент")) self.table.setItem(0, 1, QTableWidgetItem("1.0")) unit_combo = QComboBox() unit_combo.addItems(["нг", "мкг", "мг", "г", "кг", "нл", "мкл", "мл", "л"]) unit_combo.setCurrentText("мг") self.table.setCellWidget(0, 2, unit_combo) self.table.setItem(0, 3, QTableWidgetItem("1.0")) self.table.setItem(0, 4, QTableWidgetItem("")) def set_model(self, model): """Устанавливает связь с моделью""" self.model = model def update_results(self, results: list): """Обновляет столбец результатов в таблице""" for row, amount in enumerate(results): if row < self.table.rowCount(): # Округление до 4 знаков после запятой self.table.setItem(row, 4, QTableWidgetItem(f"{amount:.4f}")) def show_error(self, message: str): """Показывает диалоговое окно с ошибкой""" QMessageBox.critical(self, "Ошибка", message) def get_table_data(self) -> list: """Возвращает данные из таблицы для отладки""" data = [] for row in range(self.table.rowCount()): row_data = [] for col in range(self.table.columnCount() - 1): # не берём столбец результатов item = self.table.item(row, col) if item: row_data.append(item.text()) else: widget = self.table.cellWidget(row, col) if widget and isinstance(widget, QComboBox): row_data.append(widget.currentText()) else: row_data.append("") data.append(row_data) return data