Files
help_lab/view.py
T

423 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from PyQt5.QtWidgets import (QMainWindow, QVBoxLayout, QHBoxLayout,
QTableWidget, QTableWidgetItem, QPushButton,
QLabel, QDoubleSpinBox, QComboBox, QLineEdit,
QWidget, QMessageBox, QGroupBox, QFrame, QHeaderView)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QColor
class MediumCalculatorWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Калькулятор питательных сред - Цифровой помощник биохимика")
self.setGeometry(200, 100, 1200, 700)
self.setStyleSheet("""
QMainWindow {
background-color: #f5f5f5;
}
QGroupBox {
font-weight: bold;
border: 2px solid #ccc;
border-radius: 5px;
margin-top: 10px;
padding-top: 10px;
background-color: white;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 5px 0 5px;
color: #1565C0;
}
QTableWidget {
gridline-color: #ddd;
background-color: white;
alternate-background-color: #f9f9f9;
}
QHeaderView::section {
background-color: #1565C0;
color: white;
padding: 8px;
border: none;
font-weight: bold;
}
QPushButton {
background-color: #2196F3;
color: white;
border: none;
padding: 8px 15px;
border-radius: 4px;
font-weight: bold;
}
QPushButton:hover {
background-color: #1976D2;
}
QPushButton:pressed {
background-color: #0D47A1;
}
QPushButton#danger {
background-color: #f44336;
}
QPushButton#danger:hover {
background-color: #da190b;
}
QPushButton#success {
background-color: #4CAF50;
}
QPushButton#success:hover {
background-color: #45a049;
}
QDoubleSpinBox, QLineEdit {
padding: 4px;
border: 1px solid #ccc;
border-radius: 3px;
background-color: white;
color: black;
font-size: 12px;
min-height: 20px;
}
QComboBox {
border: 1px solid #ccc;
border-radius: 3px;
background-color: white;
color: black;
font-size: 12px;
min-height: 20px;
padding: 2px;
}
QComboBox::drop-down {
border: none;
width: 20px;
}
QComboBox QAbstractItemView {
background-color: white;
color: black;
selection-background-color: #2196F3;
selection-color: white;
}
QLabel {
color: black;
font-size: 12px;
}
QLabel#title {
font-size: 18px;
font-weight: bold;
color: #0D47A1;
}
QLabel#info {
color: #1565C0;
font-size: 11px;
}
""")
self._init_ui()
def _init_ui(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
layout.setSpacing(15)
layout.setContentsMargins(20, 20, 20, 20)
title_label = QLabel("Калькулятор питательных сред")
title_label.setObjectName("title")
title_label.setAlignment(Qt.AlignCenter)
title_font = QFont()
title_font.setPointSize(18)
title_font.setBold(True)
title_label.setFont(title_font)
layout.addWidget(title_label)
params_group = QGroupBox("Параметры среды")
params_layout = QHBoxLayout()
params_layout.setSpacing(20)
amount_layout = QHBoxLayout()
amount_layout.addWidget(QLabel("Общее количество:"))
self.amount_input = QDoubleSpinBox()
self.amount_input.setRange(0.001, 1000000.0)
self.amount_input.setValue(1000.0)
self.amount_input.setMinimumWidth(150)
amount_layout.addWidget(self.amount_input)
self.amount_unit_combo = QComboBox()
self.amount_unit_combo.addItems(["нл", "мкл", "мл", "л"])
self.amount_unit_combo.setCurrentText("мл")
self.amount_unit_combo.setMinimumWidth(80)
amount_layout.addWidget(self.amount_unit_combo)
params_layout.addLayout(amount_layout)
solvent_layout = QHBoxLayout()
solvent_layout.addWidget(QLabel("Растворитель:"))
self.solvent_input = QLineEdit("Вода")
self.solvent_input.setMinimumWidth(150)
solvent_layout.addWidget(self.solvent_input)
params_layout.addLayout(solvent_layout)
params_layout.addStretch()
params_group.setLayout(params_layout)
layout.addWidget(params_group)
table_group = QGroupBox("Состав среды")
table_layout = QVBoxLayout()
self.table = QTableWidget()
self.table.setColumnCount(6)
self.table.setHorizontalHeaderLabels(["Название", "%", "Единица", "Коэфф.", "Разбавление (x)", "Количество"])
self.table.setAlternatingRowColors(True)
self.table.setSelectionBehavior(QTableWidget.SelectRows)
self.table.setEditTriggers(QTableWidget.DoubleClicked | QTableWidget.EditKeyPressed)
self.table.verticalHeader().setVisible(False)
self.table.setColumnWidth(0, 180)
self.table.setColumnWidth(1, 70)
self.table.setColumnWidth(2, 90)
self.table.setColumnWidth(3, 70)
self.table.setColumnWidth(4, 100)
self.table.setColumnWidth(5, 120)
table_layout.addWidget(self.table)
table_group.setLayout(table_layout)
layout.addWidget(table_group)
btn_group = QGroupBox("Управление")
btn_layout = QHBoxLayout()
btn_layout.setSpacing(10)
self.add_row_btn = QPushButton("Добавить реагент")
self.add_row_btn.setMinimumWidth(150)
btn_layout.addWidget(self.add_row_btn)
self.remove_row_btn = QPushButton("Удалить реагент")
self.remove_row_btn.setObjectName("danger")
self.remove_row_btn.setMinimumWidth(150)
btn_layout.addWidget(self.remove_row_btn)
btn_layout.addStretch()
self.calculate_btn = QPushButton("Рассчитать")
self.calculate_btn.setObjectName("success")
self.calculate_btn.setMinimumWidth(150)
btn_layout.addWidget(self.calculate_btn)
self.save_btn = QPushButton("Сохранить")
self.save_btn.setMinimumWidth(150)
btn_layout.addWidget(self.save_btn)
self.load_btn = QPushButton("Загрузить")
self.load_btn.setMinimumWidth(150)
btn_layout.addWidget(self.load_btn)
btn_group.setLayout(btn_layout)
layout.addWidget(btn_group)
info_frame = QFrame()
info_frame.setFrameShape(QFrame.StyledPanel)
info_frame.setStyleSheet("background-color: #e3f2fd; border-radius: 5px;")
info_layout = QHBoxLayout(info_frame)
info_label = QLabel("Подсказка: Реагенты в массовых единицах (г, мг и т.д.) не учитываются при расчёте объёма растворителя")
info_label.setObjectName("info")
info_layout.addWidget(info_label)
info_layout.addStretch()
layout.addWidget(info_frame)
self.add_initial_rows()
def add_initial_rows(self):
self.add_solvent_row()
self.add_new_row()
def add_solvent_row(self):
row_count = self.table.rowCount()
self.table.insertRow(row_count)
self.table.setRowHeight(row_count, 30)
solvent_name = self.solvent_input.text()
solvent_item = QTableWidgetItem(solvent_name)
solvent_item.setFlags(solvent_item.flags() & ~Qt.ItemIsEditable)
solvent_item.setBackground(QColor(230, 230, 230))
solvent_item.setForeground(QColor(0, 0, 0))
font = QFont()
font.setBold(True)
solvent_item.setFont(font)
self.table.setItem(row_count, 0, solvent_item)
percent_item = QTableWidgetItem("")
percent_item.setFlags(percent_item.flags() & ~Qt.ItemIsEditable)
percent_item.setBackground(QColor(230, 230, 230))
percent_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 1, percent_item)
unit_item = QTableWidgetItem(self.amount_unit_combo.currentText())
unit_item.setFlags(unit_item.flags() & ~Qt.ItemIsEditable)
unit_item.setBackground(QColor(230, 230, 230))
unit_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 2, unit_item)
coeff_item = QTableWidgetItem("-")
coeff_item.setFlags(coeff_item.flags() & ~Qt.ItemIsEditable)
coeff_item.setBackground(QColor(230, 230, 230))
coeff_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 3, coeff_item)
dilution_item = QTableWidgetItem("-")
dilution_item.setFlags(dilution_item.flags() & ~Qt.ItemIsEditable)
dilution_item.setBackground(QColor(230, 230, 230))
dilution_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 4, dilution_item)
result_item = QTableWidgetItem("")
result_item.setFlags(result_item.flags() & ~Qt.ItemIsEditable)
result_item.setBackground(QColor(240, 240, 240))
result_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 5, result_item)
def update_solvent_name(self):
solvent_name = self.solvent_input.text()
name_item = self.table.item(0, 0)
if name_item:
name_item.setText(solvent_name)
def format_number(self, value):
if value == int(value):
return str(int(value))
else:
formatted = f"{value:.6f}".rstrip('0').rstrip('.')
if '.' in formatted and len(formatted.split('.')[1]) > 4:
formatted = f"{value:.4f}".rstrip('0').rstrip('.')
return formatted
def add_new_row(self):
row_count = self.table.rowCount()
self.table.insertRow(row_count)
self.table.setRowHeight(row_count, 30)
name_item = QTableWidgetItem(f"Реагент_{row_count}")
name_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 0, name_item)
percent_item = QTableWidgetItem("0")
percent_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 1, percent_item)
unit_combo = QComboBox()
unit_combo.addItems(["нг", "мкг", "мг", "г", "кг", "нл", "мкл", "мл", "л"])
unit_combo.setCurrentText("мг")
self.table.setCellWidget(row_count, 2, unit_combo)
coeff_item = QTableWidgetItem("1")
coeff_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 3, coeff_item)
dilution_item = QTableWidgetItem("1")
dilution_item.setForeground(QColor(0, 0, 0))
dilution_item.setFlags(dilution_item.flags() | Qt.ItemIsEditable)
self.table.setItem(row_count, 4, dilution_item)
result_item = QTableWidgetItem("")
result_item.setFlags(result_item.flags() & ~Qt.ItemIsEditable)
result_item.setBackground(QColor(250, 250, 250))
result_item.setForeground(QColor(0, 0, 0))
self.table.setItem(row_count, 5, result_item)
def remove_selected_row(self):
selected_rows = set()
for item in self.table.selectedItems():
selected_rows.add(item.row())
for row in sorted(selected_rows, reverse=True):
if row > 0:
self.table.removeRow(row)
def get_table_data(self) -> list:
data = []
for row in range(1, self.table.rowCount()):
row_data = []
name_item = self.table.item(row, 0)
row_data.append(name_item.text() if name_item else "")
percent_item = self.table.item(row, 1)
row_data.append(percent_item.text() if percent_item else "0")
unit_widget = self.table.cellWidget(row, 2)
if unit_widget and isinstance(unit_widget, QComboBox):
row_data.append(unit_widget.currentText())
else:
row_data.append("мг")
coeff_item = self.table.item(row, 3)
row_data.append(coeff_item.text() if coeff_item else "1")
dilution_item = self.table.item(row, 4)
if dilution_item:
try:
dilution_factor = float(dilution_item.text())
except ValueError:
dilution_factor = 1.0
row_data.append(dilution_factor)
else:
row_data.append(1.0)
data.append(row_data)
return data
def update_solvent_percent(self, solvent_percent: float):
percent_item = self.table.item(0, 1)
if percent_item:
percent_item.setText(self.format_number(solvent_percent))
def show_error(self, message: str):
QMessageBox.critical(self, "Ошибка", message)
def update_results(self, results: list):
for row, amount in enumerate(results, start=1):
if row < self.table.rowCount():
formatted_amount = self.format_number(amount)
result_item = QTableWidgetItem(formatted_amount)
result_item.setFlags(result_item.flags() & ~Qt.ItemIsEditable)
result_item.setBackground(QColor(220, 255, 220))
result_item.setForeground(QColor(0, 0, 0))
font = QFont()
font.setBold(True)
result_item.setFont(font)
self.table.setItem(row, 5, result_item)
def update_solvent_result(self, solvent_amount: float, unit: str):
formatted_amount = self.format_number(solvent_amount)
result_item = self.table.item(0, 5)
if result_item:
result_item.setText(formatted_amount)
result_item.setBackground(QColor(220, 255, 220))
result_item.setForeground(QColor(0, 0, 0))
unit_item = self.table.item(0, 2)
if unit_item:
unit_item.setText(unit)
def update_display(self, solvent: str, total_amount: float, amount_unit: str):
self.solvent_input.setText(solvent)
self.update_solvent_name()
self.amount_input.setValue(total_amount)
self.amount_unit_combo.setCurrentText(amount_unit)
def clear_results(self):
for row in range(self.table.rowCount()):
result_item = self.table.item(row, 5)
if result_item:
result_item.setText("")
if row == 0:
result_item.setBackground(QColor(230, 230, 230))
else:
result_item.setBackground(QColor(250, 250, 250))
percent_item = self.table.item(0, 1)
if percent_item:
percent_item.setText("")
unit_item = self.table.item(0, 2)
if unit_item:
unit_item.setText(self.amount_unit_combo.currentText())