Сделал лабы + контрольную

This commit is contained in:
2025-12-11 14:26:39 +03:00
parent fe28b9a58c
commit 7fd78c0de2
7 changed files with 2012 additions and 0 deletions

View File

@@ -0,0 +1,610 @@
import sys
import sqlite3
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QGroupBox, QTableWidget, QTableWidgetItem, QPushButton, QComboBox,
QLabel, QLineEdit, QMessageBox, QTabWidget, QFormLayout,
QHeaderView, QAbstractItemView, QStatusBar, QDoubleSpinBox, QSpinBox
)
from PyQt5.QtCore import Qt
class Database:
"""Класс для работы с базой данных SQLite - Аптека"""
def __init__(self, db_name="pharmacy.db"):
self.db_name = db_name
self.conn = None
self.cursor = None
self.connect()
self.create_tables()
self.populate_sample_data()
def connect(self):
"""Подключение к базе данных"""
self.conn = sqlite3.connect(self.db_name)
self.cursor = self.conn.cursor()
def create_tables(self):
"""Создание таблиц базы данных"""
# Главная таблица - Типы медикаментов
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS medication_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT,
storage_conditions TEXT,
prescription_required INTEGER DEFAULT 0
)
''')
# Подчинённая таблица - Медикаменты
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS medications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
type_id INTEGER NOT NULL,
manufacturer TEXT,
price REAL,
quantity_received INTEGER DEFAULT 0,
quantity_sold INTEGER DEFAULT 0,
FOREIGN KEY (type_id) REFERENCES medication_types(id) ON DELETE CASCADE
)
''')
self.conn.commit()
def populate_sample_data(self):
"""Заполнение тестовыми данными"""
self.cursor.execute("SELECT COUNT(*) FROM medication_types")
if self.cursor.fetchone()[0] > 0:
return
# Типы медикаментов (главная таблица)
types = [
("Антибиотики", "Препараты для борьбы с бактериальными инфекциями", "Хранить при температуре 2-8°C", 1),
("Болеутоляющие", "Препараты для снятия боли", "Хранить в сухом месте при комнатной температуре", 0),
("Жаропонижающие", "Препараты для снижения температуры", "Хранить при температуре до 25°C", 0),
("Витамины", "Витаминные комплексы и добавки", "Хранить в сухом тёмном месте", 0),
("Противовирусные", "Препараты для борьбы с вирусами", "Хранить при температуре 15-25°C", 1),
]
self.cursor.executemany(
"INSERT INTO medication_types (name, description, storage_conditions, prescription_required) VALUES (?, ?, ?, ?)",
types
)
# Медикаменты (подчинённая таблица)
medications = [
("Амоксициллин", 1, "Фармстандарт", 150.50, 100, 45),
("Азитромицин", 1, "КРКА", 280.00, 80, 30),
("Цефтриаксон", 1, "Синтез", 45.00, 200, 120),
("Ибупрофен", 2, "Борисовский завод", 85.00, 150, 90),
("Кеторол", 2, "Dr. Reddy's", 120.00, 100, 65),
("Анальгин", 2, "Фармстандарт", 35.00, 300, 180),
("Парацетамол", 3, "Медисорб", 25.00, 500, 350),
("Нурофен", 3, "Reckitt Benckiser", 180.00, 120, 75),
("Аспирин", 3, "Bayer", 95.00, 200, 140),
("Витамин C", 4, "Эвалар", 250.00, 100, 40),
("Компливит", 4, "Фармстандарт", 320.00, 80, 35),
("Арбидол", 5, "Фармстандарт", 450.00, 60, 25),
("Ингавирин", 5, "Валента", 550.00, 50, 20),
]
self.cursor.executemany(
"INSERT INTO medications (name, type_id, manufacturer, price, quantity_received, quantity_sold) VALUES (?, ?, ?, ?, ?, ?)",
medications
)
self.conn.commit()
# === CRUD для типов медикаментов (главная таблица) ===
def get_medication_types(self):
self.cursor.execute("SELECT * FROM medication_types ORDER BY name")
return self.cursor.fetchall()
def add_medication_type(self, name, description, storage_conditions, prescription_required):
self.cursor.execute(
"INSERT INTO medication_types (name, description, storage_conditions, prescription_required) VALUES (?, ?, ?, ?)",
(name, description, storage_conditions, prescription_required)
)
self.conn.commit()
return self.cursor.lastrowid
def update_medication_type(self, id, name, description, storage_conditions, prescription_required):
self.cursor.execute(
"UPDATE medication_types SET name=?, description=?, storage_conditions=?, prescription_required=? WHERE id=?",
(name, description, storage_conditions, prescription_required, id)
)
self.conn.commit()
def delete_medication_type(self, id):
self.cursor.execute("DELETE FROM medication_types WHERE id=?", (id,))
self.conn.commit()
# === CRUD для медикаментов (подчинённая таблица) ===
def get_medications(self, type_id=None, search_query=None):
"""Получить медикаменты с вычисляемым полем (остаток на складе)"""
if search_query:
query = """
SELECT m.id, m.name, m.type_id, m.manufacturer, m.price,
m.quantity_received, m.quantity_sold,
(m.quantity_received - m.quantity_sold) as quantity_remaining,
t.name as type_name
FROM medications m
JOIN medication_types t ON m.type_id = t.id
WHERE m.name LIKE ? OR m.manufacturer LIKE ?
ORDER BY m.name
"""
search = f"%{search_query}%"
self.cursor.execute(query, (search, search))
elif type_id:
self.cursor.execute("""
SELECT m.id, m.name, m.type_id, m.manufacturer, m.price,
m.quantity_received, m.quantity_sold,
(m.quantity_received - m.quantity_sold) as quantity_remaining,
t.name as type_name
FROM medications m
JOIN medication_types t ON m.type_id = t.id
WHERE m.type_id = ?
ORDER BY m.name
""", (type_id,))
else:
self.cursor.execute("""
SELECT m.id, m.name, m.type_id, m.manufacturer, m.price,
m.quantity_received, m.quantity_sold,
(m.quantity_received - m.quantity_sold) as quantity_remaining,
t.name as type_name
FROM medications m
JOIN medication_types t ON m.type_id = t.id
ORDER BY m.name
""")
return self.cursor.fetchall()
def add_medication(self, name, type_id, manufacturer, price, quantity_received, quantity_sold):
self.cursor.execute(
"INSERT INTO medications (name, type_id, manufacturer, price, quantity_received, quantity_sold) VALUES (?, ?, ?, ?, ?, ?)",
(name, type_id, manufacturer, price, quantity_received, quantity_sold)
)
self.conn.commit()
return self.cursor.lastrowid
def update_medication(self, id, name, type_id, manufacturer, price, quantity_received, quantity_sold):
self.cursor.execute(
"UPDATE medications SET name=?, type_id=?, manufacturer=?, price=?, quantity_received=?, quantity_sold=? WHERE id=?",
(name, type_id, manufacturer, price, quantity_received, quantity_sold, id)
)
self.conn.commit()
def delete_medication(self, id):
self.cursor.execute("DELETE FROM medications WHERE id=?", (id,))
self.conn.commit()
def close(self):
if self.conn:
self.conn.close()
class MainWindow(QMainWindow):
"""Главное окно приложения Аптека"""
def __init__(self):
super().__init__()
self.setWindowTitle("Контрольная работа - База данных «Аптека»")
self.setMinimumSize(1100, 700)
# Инициализация БД
self.db = Database()
# Создание интерфейса
self.init_ui()
# Загрузка данных
self.load_all_data()
def init_ui(self):
"""Инициализация интерфейса"""
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# Панель поиска медикаментов
search_group = QGroupBox("Поиск медикаментов")
search_layout = QHBoxLayout(search_group)
search_layout.addWidget(QLabel("Название/Производитель:"))
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("Введите название или производителя...")
self.search_input.returnPressed.connect(self.search_medications)
search_layout.addWidget(self.search_input)
self.btn_search = QPushButton("Поиск")
self.btn_search.clicked.connect(self.search_medications)
search_layout.addWidget(self.btn_search)
self.btn_reset_search = QPushButton("Сбросить")
self.btn_reset_search.clicked.connect(self.reset_search)
search_layout.addWidget(self.btn_reset_search)
main_layout.addWidget(search_group)
# Вкладки
self.tabs = QTabWidget()
main_layout.addWidget(self.tabs)
# Вкладка медикаментов (подчинённая таблица)
self.create_medications_tab()
# Вкладка типов медикаментов (главная таблица)
self.create_types_tab()
# Статусбар
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
self.statusBar.showMessage("Готово")
def create_medications_tab(self):
"""Вкладка медикаментов (подчинённая таблица)"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Фильтр по типу (связь главный-подчинённый)
filter_layout = QHBoxLayout()
filter_layout.addWidget(QLabel("Фильтр по типу медикамента:"))
self.medications_type_filter = QComboBox()
self.medications_type_filter.currentIndexChanged.connect(self.filter_medications_by_type)
filter_layout.addWidget(self.medications_type_filter)
filter_layout.addStretch()
layout.addLayout(filter_layout)
# Таблица медикаментов с вычисляемым полем
self.medications_table = QTableWidget()
self.medications_table.setColumnCount(8)
self.medications_table.setHorizontalHeaderLabels([
"ID", "Название", "Тип", "Производитель", "Цена (руб.)",
"Поступило", "Продано", "Остаток на складе"
])
self.medications_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.medications_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.medications_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.medications_table.setColumnHidden(0, True)
layout.addWidget(self.medications_table)
# Форма редактирования
form_group = QGroupBox("Добавить/Редактировать медикамент")
form_layout = QFormLayout(form_group)
self.med_name = QLineEdit()
self.med_type = QComboBox()
self.med_manufacturer = QLineEdit()
self.med_price = QDoubleSpinBox()
self.med_price.setRange(0, 100000)
self.med_price.setDecimals(2)
self.med_price.setSuffix(" руб.")
self.med_received = QSpinBox()
self.med_received.setRange(0, 100000)
self.med_sold = QSpinBox()
self.med_sold.setRange(0, 100000)
form_layout.addRow("Название:", self.med_name)
form_layout.addRow("Тип:", self.med_type)
form_layout.addRow("Производитель:", self.med_manufacturer)
form_layout.addRow("Цена:", self.med_price)
form_layout.addRow("Поступило:", self.med_received)
form_layout.addRow("Продано:", self.med_sold)
layout.addWidget(form_group)
# Кнопки
buttons_layout = QHBoxLayout()
btn_add = QPushButton("Добавить")
btn_add.clicked.connect(self.add_medication)
btn_edit = QPushButton("Изменить выбранный")
btn_edit.clicked.connect(self.edit_medication)
btn_delete = QPushButton("Удалить выбранный")
btn_delete.clicked.connect(self.delete_medication)
btn_load = QPushButton("Загрузить в форму")
btn_load.clicked.connect(self.load_medication_to_form)
buttons_layout.addWidget(btn_add)
buttons_layout.addWidget(btn_edit)
buttons_layout.addWidget(btn_delete)
buttons_layout.addWidget(btn_load)
buttons_layout.addStretch()
layout.addLayout(buttons_layout)
self.tabs.addTab(tab, "Медикаменты")
def create_types_tab(self):
"""Вкладка типов медикаментов (главная таблица)"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Таблица типов
self.types_table = QTableWidget()
self.types_table.setColumnCount(5)
self.types_table.setHorizontalHeaderLabels([
"ID", "Название", "Описание", "Условия хранения", "Рецепт"
])
self.types_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.types_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.types_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.types_table.setColumnHidden(0, True)
layout.addWidget(self.types_table)
# Форма редактирования
form_group = QGroupBox("Добавить/Редактировать тип медикамента")
form_layout = QFormLayout(form_group)
self.type_name = QLineEdit()
self.type_description = QLineEdit()
self.type_storage = QLineEdit()
self.type_prescription = QComboBox()
self.type_prescription.addItems(["Нет", "Да"])
form_layout.addRow("Название:", self.type_name)
form_layout.addRow("Описание:", self.type_description)
form_layout.addRow("Условия хранения:", self.type_storage)
form_layout.addRow("Требуется рецепт:", self.type_prescription)
layout.addWidget(form_group)
# Кнопки
buttons_layout = QHBoxLayout()
btn_add = QPushButton("Добавить")
btn_add.clicked.connect(self.add_type)
btn_edit = QPushButton("Изменить")
btn_edit.clicked.connect(self.edit_type)
btn_delete = QPushButton("Удалить")
btn_delete.clicked.connect(self.delete_type)
btn_load = QPushButton("Загрузить в форму")
btn_load.clicked.connect(self.load_type_to_form)
buttons_layout.addWidget(btn_add)
buttons_layout.addWidget(btn_edit)
buttons_layout.addWidget(btn_delete)
buttons_layout.addWidget(btn_load)
buttons_layout.addStretch()
layout.addLayout(buttons_layout)
self.tabs.addTab(tab, "Типы медикаментов")
def load_all_data(self):
"""Загрузка всех данных"""
self.load_types()
self.load_medications()
self.update_comboboxes()
def update_comboboxes(self):
"""Обновление выпадающих списков"""
types = self.db.get_medication_types()
# Фильтр по типу
self.medications_type_filter.clear()
self.medications_type_filter.addItem("Все типы", None)
# Комбобокс для формы
self.med_type.clear()
for t in types:
self.medications_type_filter.addItem(t[1], t[0])
self.med_type.addItem(t[1], t[0])
# === Типы медикаментов (главная таблица) ===
def load_types(self):
types = self.db.get_medication_types()
self.types_table.setRowCount(len(types))
for row, t in enumerate(types):
self.types_table.setItem(row, 0, QTableWidgetItem(str(t[0])))
self.types_table.setItem(row, 1, QTableWidgetItem(t[1]))
self.types_table.setItem(row, 2, QTableWidgetItem(t[2] or ""))
self.types_table.setItem(row, 3, QTableWidgetItem(t[3] or ""))
self.types_table.setItem(row, 4, QTableWidgetItem("Да" if t[4] else "Нет"))
def add_type(self):
name = self.type_name.text().strip()
description = self.type_description.text().strip()
storage = self.type_storage.text().strip()
prescription = self.type_prescription.currentIndex()
if not name:
QMessageBox.warning(self, "Ошибка", "Введите название типа")
return
try:
self.db.add_medication_type(name, description, storage, prescription)
self.load_all_data()
self.clear_type_form()
self.statusBar.showMessage("Тип медикамента добавлен")
except Exception as e:
QMessageBox.critical(self, "Ошибка", str(e))
def edit_type(self):
row = self.types_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите тип медикамента")
return
id = int(self.types_table.item(row, 0).text())
name = self.type_name.text().strip()
description = self.type_description.text().strip()
storage = self.type_storage.text().strip()
prescription = self.type_prescription.currentIndex()
if not name:
QMessageBox.warning(self, "Ошибка", "Введите название типа")
return
self.db.update_medication_type(id, name, description, storage, prescription)
self.load_all_data()
self.statusBar.showMessage("Тип медикамента обновлён")
def delete_type(self):
row = self.types_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите тип медикамента")
return
reply = QMessageBox.question(
self, "Подтверждение",
"Удалить тип медикамента? Это также удалит все связанные медикаменты.",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
id = int(self.types_table.item(row, 0).text())
self.db.delete_medication_type(id)
self.load_all_data()
self.statusBar.showMessage("Тип медикамента удалён")
def load_type_to_form(self):
row = self.types_table.currentRow()
if row < 0:
return
self.type_name.setText(self.types_table.item(row, 1).text())
self.type_description.setText(self.types_table.item(row, 2).text())
self.type_storage.setText(self.types_table.item(row, 3).text())
prescription = self.types_table.item(row, 4).text()
self.type_prescription.setCurrentIndex(1 if prescription == "Да" else 0)
def clear_type_form(self):
self.type_name.clear()
self.type_description.clear()
self.type_storage.clear()
self.type_prescription.setCurrentIndex(0)
# === Медикаменты (подчинённая таблица) ===
def load_medications(self, type_id=None, search_query=None):
medications = self.db.get_medications(type_id, search_query)
self.medications_table.setRowCount(len(medications))
for row, m in enumerate(medications):
self.medications_table.setItem(row, 0, QTableWidgetItem(str(m[0]))) # id
self.medications_table.setItem(row, 1, QTableWidgetItem(m[1])) # name
self.medications_table.setItem(row, 2, QTableWidgetItem(m[8])) # type_name
self.medications_table.setItem(row, 3, QTableWidgetItem(m[3] or "")) # manufacturer
self.medications_table.setItem(row, 4, QTableWidgetItem(f"{m[4]:.2f}")) # price
self.medications_table.setItem(row, 5, QTableWidgetItem(str(m[5]))) # received
self.medications_table.setItem(row, 6, QTableWidgetItem(str(m[6]))) # sold
# Вычисляемое поле - остаток на складе
remaining = m[7]
remaining_item = QTableWidgetItem(str(remaining))
# Подсветка если остаток мал
if remaining <= 10:
remaining_item.setBackground(Qt.red)
elif remaining <= 30:
remaining_item.setBackground(Qt.yellow)
self.medications_table.setItem(row, 7, remaining_item)
def filter_medications_by_type(self):
"""Фильтрация по типу (связь главный-подчинённый)"""
type_id = self.medications_type_filter.currentData()
self.load_medications(type_id)
def search_medications(self):
"""Поиск медикаментов"""
query = self.search_input.text().strip()
if query:
self.load_medications(search_query=query)
self.statusBar.showMessage(f"Поиск: {query}")
else:
self.load_medications()
def reset_search(self):
"""Сброс поиска"""
self.search_input.clear()
self.medications_type_filter.setCurrentIndex(0)
self.load_medications()
self.statusBar.showMessage("Поиск сброшен")
def add_medication(self):
name = self.med_name.text().strip()
type_id = self.med_type.currentData()
manufacturer = self.med_manufacturer.text().strip()
price = self.med_price.value()
received = self.med_received.value()
sold = self.med_sold.value()
if not name or not type_id:
QMessageBox.warning(self, "Ошибка", "Заполните обязательные поля (Название, Тип)")
return
if sold > received:
QMessageBox.warning(self, "Ошибка", "Продано не может быть больше, чем поступило")
return
self.db.add_medication(name, type_id, manufacturer, price, received, sold)
self.load_medications()
self.clear_medication_form()
self.statusBar.showMessage("Медикамент добавлен")
def edit_medication(self):
row = self.medications_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите медикамент")
return
id = int(self.medications_table.item(row, 0).text())
name = self.med_name.text().strip()
type_id = self.med_type.currentData()
manufacturer = self.med_manufacturer.text().strip()
price = self.med_price.value()
received = self.med_received.value()
sold = self.med_sold.value()
if not name or not type_id:
QMessageBox.warning(self, "Ошибка", "Заполните обязательные поля")
return
if sold > received:
QMessageBox.warning(self, "Ошибка", "Продано не может быть больше, чем поступило")
return
self.db.update_medication(id, name, type_id, manufacturer, price, received, sold)
self.load_medications()
self.statusBar.showMessage("Медикамент обновлён")
def delete_medication(self):
row = self.medications_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите медикамент")
return
reply = QMessageBox.question(
self, "Подтверждение", "Удалить медикамент?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
id = int(self.medications_table.item(row, 0).text())
self.db.delete_medication(id)
self.load_medications()
self.statusBar.showMessage("Медикамент удалён")
def load_medication_to_form(self):
row = self.medications_table.currentRow()
if row < 0:
return
self.med_name.setText(self.medications_table.item(row, 1).text())
self.med_manufacturer.setText(self.medications_table.item(row, 3).text())
self.med_price.setValue(float(self.medications_table.item(row, 4).text()))
self.med_received.setValue(int(self.medications_table.item(row, 5).text()))
self.med_sold.setValue(int(self.medications_table.item(row, 6).text()))
# Найти тип
type_name = self.medications_table.item(row, 2).text()
index = self.med_type.findText(type_name)
if index >= 0:
self.med_type.setCurrentIndex(index)
def clear_medication_form(self):
self.med_name.clear()
self.med_manufacturer.clear()
self.med_price.setValue(0)
self.med_received.setValue(0)
self.med_sold.setValue(0)
def closeEvent(self, event):
"""Закрытие приложения"""
self.db.close()
event.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

Binary file not shown.

View File

@@ -0,0 +1,2 @@
PyQt5>=5.15.0
pyinstaller>=6.0.0

430
secondLabVisualProg/main.py Normal file
View File

@@ -0,0 +1,430 @@
import sys
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QComboBox, QSlider, QFileDialog,
QMessageBox, QColorDialog, QAction, QToolBar, QStatusBar
)
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import (
QImage, QPainter, QPen, QColor, QPixmap, QIcon
)
class Canvas(QWidget):
"""Холст для рисования"""
def __init__(self, parent=None):
super().__init__(parent)
self.setMinimumSize(800, 600)
# Создаём изображение для рисования
self.image = QImage(800, 600, QImage.Format_RGB32)
self.image.fill(Qt.white)
# Параметры рисования
self.drawing = False
self.last_point = QPoint()
self.pen_color = QColor(Qt.black)
self.pen_width = 3
self.pen_style = Qt.SolidLine
self.eraser_width = 20
# История для undo/redo
self.undo_stack = []
self.redo_stack = []
self.save_state() # Сохраняем начальное состояние
def save_state(self):
"""Сохранить текущее состояние для undo"""
self.undo_stack.append(self.image.copy())
self.redo_stack.clear() # Очищаем redo при новом действии
# Ограничиваем размер истории
if len(self.undo_stack) > 50:
self.undo_stack.pop(0)
def undo(self):
"""Отменить последнее действие"""
if len(self.undo_stack) > 1:
# Сохраняем текущее состояние в redo
self.redo_stack.append(self.undo_stack.pop())
# Восстанавливаем предыдущее состояние
self.image = self.undo_stack[-1].copy()
self.update()
return True
return False
def redo(self):
"""Повторить отменённое действие"""
if self.redo_stack:
state = self.redo_stack.pop()
self.undo_stack.append(state)
self.image = state.copy()
self.update()
return True
return False
def clear_canvas(self):
"""Очистить холст"""
self.save_state()
self.image.fill(Qt.white)
self.update()
def new_image(self, width=800, height=600):
"""Создать новое изображение"""
self.image = QImage(width, height, QImage.Format_RGB32)
self.image.fill(Qt.white)
self.undo_stack.clear()
self.redo_stack.clear()
self.save_state()
self.setMinimumSize(width, height)
self.update()
def load_image(self, file_path):
"""Загрузить изображение из файла"""
loaded_image = QImage(file_path)
if loaded_image.isNull():
return False
self.image = loaded_image.convertToFormat(QImage.Format_RGB32)
self.setMinimumSize(self.image.width(), self.image.height())
self.undo_stack.clear()
self.redo_stack.clear()
self.save_state()
self.update()
return True
def save_image(self, file_path):
"""Сохранить изображение в файл"""
return self.image.save(file_path)
def set_pen_color(self, color):
"""Установить цвет кисти"""
self.pen_color = color
def set_pen_width(self, width):
"""Установить толщину кисти"""
self.pen_width = width
def set_pen_style(self, style):
"""Установить стиль линии"""
self.pen_style = style
def set_eraser_width(self, width):
"""Установить размер ластика"""
self.eraser_width = width
def paintEvent(self, event):
"""Отрисовка холста"""
painter = QPainter(self)
painter.drawImage(0, 0, self.image)
def mousePressEvent(self, event):
"""Обработка нажатия кнопки мыши"""
if event.button() == Qt.LeftButton or event.button() == Qt.RightButton:
self.drawing = True
self.last_point = event.pos()
self.save_state() # Сохраняем состояние перед началом рисования
def mouseMoveEvent(self, event):
"""Обработка движения мыши"""
if self.drawing:
painter = QPainter(self.image)
if event.buttons() & Qt.RightButton:
# Правая кнопка - ластик (стираем белым цветом)
pen = QPen(Qt.white, self.eraser_width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
else:
# Левая кнопка - рисуем
pen = QPen(self.pen_color, self.pen_width, self.pen_style, Qt.RoundCap, Qt.RoundJoin)
painter.setPen(pen)
painter.drawLine(self.last_point, event.pos())
self.last_point = event.pos()
self.update()
def mouseReleaseEvent(self, event):
"""Обработка отпускания кнопки мыши"""
if event.button() == Qt.LeftButton or event.button() == Qt.RightButton:
self.drawing = False
class MainWindow(QMainWindow):
"""Главное окно графического редактора"""
def __init__(self):
super().__init__()
self.setWindowTitle("Лабораторная работа №2 - Графический редактор")
self.setMinimumSize(1000, 750)
# Создаём холст
self.canvas = Canvas()
# Центральный виджет с холстом
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
main_layout.addWidget(self.canvas)
# Создаём меню
self.create_menu()
# Создаём панель инструментов
self.create_toolbar()
# Создаём статусбар
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
self.statusBar.showMessage("Готово")
def create_menu(self):
"""Создание меню"""
menubar = self.menuBar()
# Меню "Файл"
file_menu = menubar.addMenu("Файл")
new_action = QAction("Создать", self)
new_action.setShortcut("Ctrl+N")
new_action.triggered.connect(self.new_file)
file_menu.addAction(new_action)
open_action = QAction("Открыть", self)
open_action.setShortcut("Ctrl+O")
open_action.triggered.connect(self.open_file)
file_menu.addAction(open_action)
save_action = QAction("Сохранить", self)
save_action.setShortcut("Ctrl+S")
save_action.triggered.connect(self.save_file)
file_menu.addAction(save_action)
save_as_action = QAction("Сохранить как...", self)
save_as_action.setShortcut("Ctrl+Shift+S")
save_as_action.triggered.connect(self.save_file_as)
file_menu.addAction(save_as_action)
file_menu.addSeparator()
exit_action = QAction("Выход", self)
exit_action.setShortcut("Ctrl+Q")
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
# Меню "Редактирование"
edit_menu = menubar.addMenu("Редактирование")
undo_action = QAction("Отменить", self)
undo_action.setShortcut("Ctrl+Z")
undo_action.triggered.connect(self.undo)
edit_menu.addAction(undo_action)
redo_action = QAction("Повторить", self)
redo_action.setShortcut("Ctrl+Y")
redo_action.triggered.connect(self.redo)
edit_menu.addAction(redo_action)
edit_menu.addSeparator()
clear_action = QAction("Очистить", self)
clear_action.setShortcut("Ctrl+Delete")
clear_action.triggered.connect(self.clear_canvas)
edit_menu.addAction(clear_action)
# Меню "Инструменты"
tools_menu = menubar.addMenu("Инструменты")
color_action = QAction("Выбрать цвет...", self)
color_action.triggered.connect(self.choose_color)
tools_menu.addAction(color_action)
def create_toolbar(self):
"""Создание панели инструментов"""
toolbar = QToolBar("Инструменты")
toolbar.setMovable(False)
self.addToolBar(toolbar)
# Кнопки файловых операций
btn_new = QPushButton("Создать")
btn_new.clicked.connect(self.new_file)
toolbar.addWidget(btn_new)
btn_open = QPushButton("Открыть")
btn_open.clicked.connect(self.open_file)
toolbar.addWidget(btn_open)
btn_save = QPushButton("Сохранить")
btn_save.clicked.connect(self.save_file)
toolbar.addWidget(btn_save)
toolbar.addSeparator()
# Кнопки undo/redo
btn_undo = QPushButton("↶ Отменить")
btn_undo.clicked.connect(self.undo)
toolbar.addWidget(btn_undo)
btn_redo = QPushButton("↷ Повторить")
btn_redo.clicked.connect(self.redo)
toolbar.addWidget(btn_redo)
toolbar.addSeparator()
# Выбор цвета
toolbar.addWidget(QLabel("Цвет: "))
self.color_btn = QPushButton()
self.color_btn.setFixedSize(30, 30)
self.color_btn.setStyleSheet("background-color: black;")
self.color_btn.clicked.connect(self.choose_color)
toolbar.addWidget(self.color_btn)
toolbar.addSeparator()
# Толщина линии (TrackBar - QSlider)
toolbar.addWidget(QLabel("Толщина: "))
self.width_slider = QSlider(Qt.Horizontal)
self.width_slider.setMinimum(1)
self.width_slider.setMaximum(50)
self.width_slider.setValue(3)
self.width_slider.setFixedWidth(100)
self.width_slider.valueChanged.connect(self.change_pen_width)
toolbar.addWidget(self.width_slider)
self.width_label = QLabel("3")
toolbar.addWidget(self.width_label)
toolbar.addSeparator()
# Стиль линии (ComboBox)
toolbar.addWidget(QLabel("Стиль: "))
self.style_combo = QComboBox()
self.style_combo.addItem("Сплошная", Qt.SolidLine)
self.style_combo.addItem("Штриховая", Qt.DashLine)
self.style_combo.addItem("Пунктирная", Qt.DotLine)
self.style_combo.addItem("Штрих-пунктир", Qt.DashDotLine)
self.style_combo.addItem("Штрих-две точки", Qt.DashDotDotLine)
self.style_combo.currentIndexChanged.connect(self.change_pen_style)
toolbar.addWidget(self.style_combo)
toolbar.addSeparator()
# Размер ластика
toolbar.addWidget(QLabel("Ластик: "))
self.eraser_slider = QSlider(Qt.Horizontal)
self.eraser_slider.setMinimum(5)
self.eraser_slider.setMaximum(100)
self.eraser_slider.setValue(20)
self.eraser_slider.setFixedWidth(100)
self.eraser_slider.valueChanged.connect(self.change_eraser_width)
toolbar.addWidget(self.eraser_slider)
self.eraser_label = QLabel("20")
toolbar.addWidget(self.eraser_label)
toolbar.addSeparator()
# Кнопка очистки
btn_clear = QPushButton("Очистить")
btn_clear.clicked.connect(self.clear_canvas)
toolbar.addWidget(btn_clear)
def new_file(self):
"""Создать новое изображение"""
reply = QMessageBox.question(
self, "Новый файл",
"Создать новое изображение? Несохранённые изменения будут потеряны.",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if reply == QMessageBox.Yes:
self.canvas.new_image()
self.current_file = None
self.statusBar.showMessage("Создано новое изображение")
def open_file(self):
"""Открыть изображение"""
file_path, _ = QFileDialog.getOpenFileName(
self, "Открыть изображение", "",
"Изображения (*.png *.jpg *.jpeg *.bmp *.gif);;Все файлы (*)"
)
if file_path:
if self.canvas.load_image(file_path):
self.current_file = file_path
self.statusBar.showMessage(f"Открыто: {file_path}")
else:
QMessageBox.critical(self, "Ошибка", "Не удалось открыть изображение")
def save_file(self):
"""Сохранить изображение"""
if hasattr(self, 'current_file') and self.current_file:
if self.canvas.save_image(self.current_file):
self.statusBar.showMessage(f"Сохранено: {self.current_file}")
else:
QMessageBox.critical(self, "Ошибка", "Не удалось сохранить изображение")
else:
self.save_file_as()
def save_file_as(self):
"""Сохранить изображение как..."""
file_path, _ = QFileDialog.getSaveFileName(
self, "Сохранить изображение", "",
"PNG (*.png);;JPEG (*.jpg *.jpeg);;BMP (*.bmp);;Все файлы (*)"
)
if file_path:
if self.canvas.save_image(file_path):
self.current_file = file_path
self.statusBar.showMessage(f"Сохранено: {file_path}")
else:
QMessageBox.critical(self, "Ошибка", "Не удалось сохранить изображение")
def undo(self):
"""Отменить действие"""
if self.canvas.undo():
self.statusBar.showMessage("Отменено")
else:
self.statusBar.showMessage("Нечего отменять")
def redo(self):
"""Повторить действие"""
if self.canvas.redo():
self.statusBar.showMessage("Повторено")
else:
self.statusBar.showMessage("Нечего повторять")
def clear_canvas(self):
"""Очистить холст"""
reply = QMessageBox.question(
self, "Очистить",
"Очистить холст?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if reply == QMessageBox.Yes:
self.canvas.clear_canvas()
self.statusBar.showMessage("Холст очищен")
def choose_color(self):
"""Выбрать цвет кисти"""
color = QColorDialog.getColor(self.canvas.pen_color, self, "Выберите цвет")
if color.isValid():
self.canvas.set_pen_color(color)
self.color_btn.setStyleSheet(f"background-color: {color.name()};")
self.statusBar.showMessage(f"Выбран цвет: {color.name()}")
def change_pen_width(self, value):
"""Изменить толщину кисти"""
self.canvas.set_pen_width(value)
self.width_label.setText(str(value))
def change_pen_style(self, index):
"""Изменить стиль линии"""
style = self.style_combo.itemData(index)
self.canvas.set_pen_style(style)
def change_eraser_width(self, value):
"""Изменить размер ластика"""
self.canvas.set_eraser_width(value)
self.eraser_label.setText(str(value))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

Binary file not shown.

968
thirdLabVisualProg/main.py Normal file
View File

@@ -0,0 +1,968 @@
import sys
import sqlite3
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QGroupBox, QTableWidget, QTableWidgetItem, QPushButton, QComboBox,
QLabel, QLineEdit, QMessageBox, QTabWidget, QFormLayout,
QHeaderView, QAbstractItemView, QStatusBar, QSpinBox
)
from PyQt5.QtCore import Qt
class Database:
"""Класс для работы с базой данных SQLite"""
def __init__(self, db_name="faculty.db"):
self.db_name = db_name
self.conn = None
self.cursor = None
self.connect()
self.create_tables()
self.populate_sample_data()
def connect(self):
"""Подключение к базе данных"""
self.conn = sqlite3.connect(self.db_name)
self.cursor = self.conn.cursor()
def create_tables(self):
"""Создание таблиц базы данных"""
# Таблица факультетов
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS faculties (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
dean TEXT
)
''')
# Таблица кафедр
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS departments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
faculty_id INTEGER,
head TEXT,
FOREIGN KEY (faculty_id) REFERENCES faculties(id) ON DELETE CASCADE
)
''')
# Таблица групп
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
department_id INTEGER,
course INTEGER,
FOREIGN KEY (department_id) REFERENCES departments(id) ON DELETE CASCADE
)
''')
# Таблица студентов
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
last_name TEXT NOT NULL,
first_name TEXT NOT NULL,
middle_name TEXT,
group_id INTEGER,
birth_year INTEGER,
email TEXT,
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
)
''')
self.conn.commit()
def populate_sample_data(self):
"""Заполнение тестовыми данными (если таблицы пустые)"""
self.cursor.execute("SELECT COUNT(*) FROM faculties")
if self.cursor.fetchone()[0] > 0:
return
# Факультеты
faculties = [
("Информатика и вычислительная техника", "Иванов И.И."),
("Экономика и управление", "Петров П.П."),
("Инфокоммуникационные технологии", "Сидоров С.С.")
]
self.cursor.executemany("INSERT INTO faculties (name, dean) VALUES (?, ?)", faculties)
# Кафедры
departments = [
("Программная инженерия", 1, "Козлов А.А."),
("Информационные системы", 1, "Новиков Б.Б."),
("Менеджмент", 2, "Смирнова В.В."),
("Сети связи", 3, "Федоров Г.Г.")
]
self.cursor.executemany(
"INSERT INTO departments (name, faculty_id, head) VALUES (?, ?, ?)",
departments
)
# Группы
groups = [
("ПИ-21", 1, 3),
("ПИ-22", 1, 2),
("ИС-21", 2, 3),
("М-21", 3, 3),
("СС-21", 4, 3)
]
self.cursor.executemany(
"INSERT INTO groups (name, department_id, course) VALUES (?, ?, ?)",
groups
)
# Студенты
students = [
("Александров", "Алексей", "Андреевич", 1, 2003, "alex@mail.ru"),
("Борисова", "Бэлла", "Борисовна", 1, 2004, "bella@mail.ru"),
("Васильев", "Виктор", "Владимирович", 2, 2004, "victor@mail.ru"),
("Григорьева", "Галина", "Геннадьевна", 2, 2003, "galina@mail.ru"),
("Дмитриев", "Денис", "Дмитриевич", 3, 2003, "denis@mail.ru"),
("Егорова", "Елена", "Евгеньевна", 3, 2004, "elena@mail.ru"),
("Жуков", "Захар", "Зиновьевич", 4, 2003, "zahar@mail.ru"),
("Иванова", "Ирина", "Игоревна", 4, 2004, "irina@mail.ru"),
("Кузнецов", "Кирилл", "Константинович", 5, 2003, "kirill@mail.ru"),
("Лебедева", "Любовь", "Леонидовна", 5, 2004, "lubov@mail.ru"),
]
self.cursor.executemany(
"INSERT INTO students (last_name, first_name, middle_name, group_id, birth_year, email) VALUES (?, ?, ?, ?, ?, ?)",
students
)
self.conn.commit()
# === CRUD операции для факультетов ===
def get_faculties(self):
self.cursor.execute("SELECT * FROM faculties ORDER BY name")
return self.cursor.fetchall()
def add_faculty(self, name, dean):
self.cursor.execute("INSERT INTO faculties (name, dean) VALUES (?, ?)", (name, dean))
self.conn.commit()
return self.cursor.lastrowid
def update_faculty(self, id, name, dean):
self.cursor.execute("UPDATE faculties SET name=?, dean=? WHERE id=?", (name, dean, id))
self.conn.commit()
def delete_faculty(self, id):
self.cursor.execute("DELETE FROM faculties WHERE id=?", (id,))
self.conn.commit()
# === CRUD операции для кафедр ===
def get_departments(self, faculty_id=None):
if faculty_id:
self.cursor.execute("""
SELECT d.id, d.name, d.faculty_id, d.head, f.name as faculty_name
FROM departments d
JOIN faculties f ON d.faculty_id = f.id
WHERE d.faculty_id = ?
ORDER BY d.name
""", (faculty_id,))
else:
self.cursor.execute("""
SELECT d.id, d.name, d.faculty_id, d.head, f.name as faculty_name
FROM departments d
JOIN faculties f ON d.faculty_id = f.id
ORDER BY d.name
""")
return self.cursor.fetchall()
def add_department(self, name, faculty_id, head):
self.cursor.execute(
"INSERT INTO departments (name, faculty_id, head) VALUES (?, ?, ?)",
(name, faculty_id, head)
)
self.conn.commit()
return self.cursor.lastrowid
def update_department(self, id, name, faculty_id, head):
self.cursor.execute(
"UPDATE departments SET name=?, faculty_id=?, head=? WHERE id=?",
(name, faculty_id, head, id)
)
self.conn.commit()
def delete_department(self, id):
self.cursor.execute("DELETE FROM departments WHERE id=?", (id,))
self.conn.commit()
# === CRUD операции для групп ===
def get_groups(self, department_id=None):
if department_id:
self.cursor.execute("""
SELECT g.id, g.name, g.department_id, g.course, d.name as department_name
FROM groups g
JOIN departments d ON g.department_id = d.id
WHERE g.department_id = ?
ORDER BY g.name
""", (department_id,))
else:
self.cursor.execute("""
SELECT g.id, g.name, g.department_id, g.course, d.name as department_name
FROM groups g
JOIN departments d ON g.department_id = d.id
ORDER BY g.name
""")
return self.cursor.fetchall()
def add_group(self, name, department_id, course):
self.cursor.execute(
"INSERT INTO groups (name, department_id, course) VALUES (?, ?, ?)",
(name, department_id, course)
)
self.conn.commit()
return self.cursor.lastrowid
def update_group(self, id, name, department_id, course):
self.cursor.execute(
"UPDATE groups SET name=?, department_id=?, course=? WHERE id=?",
(name, department_id, course, id)
)
self.conn.commit()
def delete_group(self, id):
self.cursor.execute("DELETE FROM groups WHERE id=?", (id,))
self.conn.commit()
# === CRUD операции для студентов ===
def get_students(self, group_id=None, search_query=None):
if search_query:
query = """
SELECT s.id, s.last_name, s.first_name, s.middle_name,
s.group_id, s.birth_year, s.email, g.name as group_name
FROM students s
JOIN groups g ON s.group_id = g.id
WHERE s.last_name LIKE ? OR s.first_name LIKE ? OR s.middle_name LIKE ?
ORDER BY s.last_name, s.first_name
"""
search = f"%{search_query}%"
self.cursor.execute(query, (search, search, search))
elif group_id:
self.cursor.execute("""
SELECT s.id, s.last_name, s.first_name, s.middle_name,
s.group_id, s.birth_year, s.email, g.name as group_name
FROM students s
JOIN groups g ON s.group_id = g.id
WHERE s.group_id = ?
ORDER BY s.last_name, s.first_name
""", (group_id,))
else:
self.cursor.execute("""
SELECT s.id, s.last_name, s.first_name, s.middle_name,
s.group_id, s.birth_year, s.email, g.name as group_name
FROM students s
JOIN groups g ON s.group_id = g.id
ORDER BY s.last_name, s.first_name
""")
return self.cursor.fetchall()
def add_student(self, last_name, first_name, middle_name, group_id, birth_year, email):
self.cursor.execute(
"INSERT INTO students (last_name, first_name, middle_name, group_id, birth_year, email) VALUES (?, ?, ?, ?, ?, ?)",
(last_name, first_name, middle_name, group_id, birth_year, email)
)
self.conn.commit()
return self.cursor.lastrowid
def update_student(self, id, last_name, first_name, middle_name, group_id, birth_year, email):
self.cursor.execute(
"UPDATE students SET last_name=?, first_name=?, middle_name=?, group_id=?, birth_year=?, email=? WHERE id=?",
(last_name, first_name, middle_name, group_id, birth_year, email, id)
)
self.conn.commit()
def delete_student(self, id):
self.cursor.execute("DELETE FROM students WHERE id=?", (id,))
self.conn.commit()
def search_student_exact(self, last_name):
"""Поиск студента по точной фамилии"""
self.cursor.execute("""
SELECT s.id, s.last_name, s.first_name, s.middle_name,
s.group_id, s.birth_year, s.email, g.name as group_name
FROM students s
JOIN groups g ON s.group_id = g.id
WHERE s.last_name = ?
ORDER BY s.first_name
""", (last_name,))
return self.cursor.fetchall()
def close(self):
if self.conn:
self.conn.close()
class MainWindow(QMainWindow):
"""Главное окно приложения"""
def __init__(self):
super().__init__()
self.setWindowTitle("Лабораторная работа №3 - База данных «Факультет»")
self.setMinimumSize(1100, 700)
# Инициализация базы данных
self.db = Database()
# Создание интерфейса
self.init_ui()
# Загрузка данных
self.load_all_data()
def init_ui(self):
"""Инициализация интерфейса"""
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# Верхняя панель - поиск студентов
search_group = QGroupBox("Поиск студентов")
search_layout = QHBoxLayout(search_group)
search_layout.addWidget(QLabel("Фамилия:"))
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("Введите фамилию для поиска...")
self.search_input.returnPressed.connect(self.search_students)
search_layout.addWidget(self.search_input)
self.btn_search = QPushButton("Поиск (частичный)")
self.btn_search.clicked.connect(self.search_students)
search_layout.addWidget(self.btn_search)
self.btn_search_exact = QPushButton("Точный поиск")
self.btn_search_exact.clicked.connect(self.search_students_exact)
search_layout.addWidget(self.btn_search_exact)
self.btn_reset_search = QPushButton("Сбросить")
self.btn_reset_search.clicked.connect(self.reset_search)
search_layout.addWidget(self.btn_reset_search)
main_layout.addWidget(search_group)
# Вкладки для разных таблиц
self.tabs = QTabWidget()
main_layout.addWidget(self.tabs)
# Вкладка студентов
self.create_students_tab()
# Вкладка групп
self.create_groups_tab()
# Вкладка кафедр
self.create_departments_tab()
# Вкладка факультетов
self.create_faculties_tab()
# Статусбар
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
self.statusBar.showMessage("Готово")
def create_students_tab(self):
"""Создание вкладки студентов"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Фильтр по группе
filter_layout = QHBoxLayout()
filter_layout.addWidget(QLabel("Фильтр по группе:"))
self.students_group_filter = QComboBox()
self.students_group_filter.currentIndexChanged.connect(self.filter_students_by_group)
filter_layout.addWidget(self.students_group_filter)
filter_layout.addStretch()
layout.addLayout(filter_layout)
# Таблица студентов
self.students_table = QTableWidget()
self.students_table.setColumnCount(7)
self.students_table.setHorizontalHeaderLabels([
"ID", "Фамилия", "Имя", "Отчество", "Группа", "Год рождения", "Email"
])
self.students_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.students_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.students_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.students_table.setColumnHidden(0, True) # Скрываем ID
layout.addWidget(self.students_table)
# Форма редактирования
form_group = QGroupBox("Добавить/Редактировать студента")
form_layout = QFormLayout(form_group)
self.student_last_name = QLineEdit()
self.student_first_name = QLineEdit()
self.student_middle_name = QLineEdit()
self.student_group = QComboBox()
self.student_birth_year = QSpinBox()
self.student_birth_year.setRange(1990, 2010)
self.student_birth_year.setValue(2003)
self.student_email = QLineEdit()
form_layout.addRow("Фамилия:", self.student_last_name)
form_layout.addRow("Имя:", self.student_first_name)
form_layout.addRow("Отчество:", self.student_middle_name)
form_layout.addRow("Группа:", self.student_group)
form_layout.addRow("Год рождения:", self.student_birth_year)
form_layout.addRow("Email:", self.student_email)
layout.addWidget(form_group)
# Кнопки управления
buttons_layout = QHBoxLayout()
btn_add = QPushButton("Добавить")
btn_add.clicked.connect(self.add_student)
btn_edit = QPushButton("Изменить выбранного")
btn_edit.clicked.connect(self.edit_student)
btn_delete = QPushButton("Удалить выбранного")
btn_delete.clicked.connect(self.delete_student)
btn_load = QPushButton("Загрузить в форму")
btn_load.clicked.connect(self.load_student_to_form)
buttons_layout.addWidget(btn_add)
buttons_layout.addWidget(btn_edit)
buttons_layout.addWidget(btn_delete)
buttons_layout.addWidget(btn_load)
buttons_layout.addStretch()
layout.addLayout(buttons_layout)
self.tabs.addTab(tab, "Студенты")
def create_groups_tab(self):
"""Создание вкладки групп"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Фильтр по кафедре
filter_layout = QHBoxLayout()
filter_layout.addWidget(QLabel("Фильтр по кафедре:"))
self.groups_dept_filter = QComboBox()
self.groups_dept_filter.currentIndexChanged.connect(self.filter_groups_by_department)
filter_layout.addWidget(self.groups_dept_filter)
filter_layout.addStretch()
layout.addLayout(filter_layout)
# Таблица групп
self.groups_table = QTableWidget()
self.groups_table.setColumnCount(4)
self.groups_table.setHorizontalHeaderLabels(["ID", "Название", "Кафедра", "Курс"])
self.groups_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.groups_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.groups_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.groups_table.setColumnHidden(0, True)
layout.addWidget(self.groups_table)
# Форма редактирования
form_group = QGroupBox("Добавить/Редактировать группу")
form_layout = QFormLayout(form_group)
self.group_name = QLineEdit()
self.group_department = QComboBox()
self.group_course = QSpinBox()
self.group_course.setRange(1, 6)
self.group_course.setValue(1)
form_layout.addRow("Название:", self.group_name)
form_layout.addRow("Кафедра:", self.group_department)
form_layout.addRow("Курс:", self.group_course)
layout.addWidget(form_group)
# Кнопки
buttons_layout = QHBoxLayout()
btn_add = QPushButton("Добавить")
btn_add.clicked.connect(self.add_group)
btn_edit = QPushButton("Изменить")
btn_edit.clicked.connect(self.edit_group)
btn_delete = QPushButton("Удалить")
btn_delete.clicked.connect(self.delete_group)
btn_load = QPushButton("Загрузить в форму")
btn_load.clicked.connect(self.load_group_to_form)
buttons_layout.addWidget(btn_add)
buttons_layout.addWidget(btn_edit)
buttons_layout.addWidget(btn_delete)
buttons_layout.addWidget(btn_load)
buttons_layout.addStretch()
layout.addLayout(buttons_layout)
self.tabs.addTab(tab, "Группы")
def create_departments_tab(self):
"""Создание вкладки кафедр"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Фильтр по факультету
filter_layout = QHBoxLayout()
filter_layout.addWidget(QLabel("Фильтр по факультету:"))
self.depts_faculty_filter = QComboBox()
self.depts_faculty_filter.currentIndexChanged.connect(self.filter_departments_by_faculty)
filter_layout.addWidget(self.depts_faculty_filter)
filter_layout.addStretch()
layout.addLayout(filter_layout)
# Таблица кафедр
self.departments_table = QTableWidget()
self.departments_table.setColumnCount(4)
self.departments_table.setHorizontalHeaderLabels(["ID", "Название", "Факультет", "Заведующий"])
self.departments_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.departments_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.departments_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.departments_table.setColumnHidden(0, True)
layout.addWidget(self.departments_table)
# Форма редактирования
form_group = QGroupBox("Добавить/Редактировать кафедру")
form_layout = QFormLayout(form_group)
self.dept_name = QLineEdit()
self.dept_faculty = QComboBox()
self.dept_head = QLineEdit()
form_layout.addRow("Название:", self.dept_name)
form_layout.addRow("Факультет:", self.dept_faculty)
form_layout.addRow("Заведующий:", self.dept_head)
layout.addWidget(form_group)
# Кнопки
buttons_layout = QHBoxLayout()
btn_add = QPushButton("Добавить")
btn_add.clicked.connect(self.add_department)
btn_edit = QPushButton("Изменить")
btn_edit.clicked.connect(self.edit_department)
btn_delete = QPushButton("Удалить")
btn_delete.clicked.connect(self.delete_department)
btn_load = QPushButton("Загрузить в форму")
btn_load.clicked.connect(self.load_department_to_form)
buttons_layout.addWidget(btn_add)
buttons_layout.addWidget(btn_edit)
buttons_layout.addWidget(btn_delete)
buttons_layout.addWidget(btn_load)
buttons_layout.addStretch()
layout.addLayout(buttons_layout)
self.tabs.addTab(tab, "Кафедры")
def create_faculties_tab(self):
"""Создание вкладки факультетов"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Таблица факультетов
self.faculties_table = QTableWidget()
self.faculties_table.setColumnCount(3)
self.faculties_table.setHorizontalHeaderLabels(["ID", "Название", "Декан"])
self.faculties_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.faculties_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.faculties_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.faculties_table.setColumnHidden(0, True)
layout.addWidget(self.faculties_table)
# Форма редактирования
form_group = QGroupBox("Добавить/Редактировать факультет")
form_layout = QFormLayout(form_group)
self.faculty_name = QLineEdit()
self.faculty_dean = QLineEdit()
form_layout.addRow("Название:", self.faculty_name)
form_layout.addRow("Декан:", self.faculty_dean)
layout.addWidget(form_group)
# Кнопки
buttons_layout = QHBoxLayout()
btn_add = QPushButton("Добавить")
btn_add.clicked.connect(self.add_faculty)
btn_edit = QPushButton("Изменить")
btn_edit.clicked.connect(self.edit_faculty)
btn_delete = QPushButton("Удалить")
btn_delete.clicked.connect(self.delete_faculty)
btn_load = QPushButton("Загрузить в форму")
btn_load.clicked.connect(self.load_faculty_to_form)
buttons_layout.addWidget(btn_add)
buttons_layout.addWidget(btn_edit)
buttons_layout.addWidget(btn_delete)
buttons_layout.addWidget(btn_load)
buttons_layout.addStretch()
layout.addLayout(buttons_layout)
self.tabs.addTab(tab, "Факультеты")
def load_all_data(self):
"""Загрузка всех данных"""
self.load_faculties()
self.load_departments()
self.load_groups()
self.load_students()
self.update_comboboxes()
def update_comboboxes(self):
"""Обновление выпадающих списков"""
# Факультеты
faculties = self.db.get_faculties()
self.depts_faculty_filter.clear()
self.depts_faculty_filter.addItem("Все факультеты", None)
self.dept_faculty.clear()
for f in faculties:
self.depts_faculty_filter.addItem(f[1], f[0])
self.dept_faculty.addItem(f[1], f[0])
# Кафедры
departments = self.db.get_departments()
self.groups_dept_filter.clear()
self.groups_dept_filter.addItem("Все кафедры", None)
self.group_department.clear()
for d in departments:
self.groups_dept_filter.addItem(d[1], d[0])
self.group_department.addItem(d[1], d[0])
# Группы
groups = self.db.get_groups()
self.students_group_filter.clear()
self.students_group_filter.addItem("Все группы", None)
self.student_group.clear()
for g in groups:
self.students_group_filter.addItem(g[1], g[0])
self.student_group.addItem(g[1], g[0])
# === Факультеты ===
def load_faculties(self):
faculties = self.db.get_faculties()
self.faculties_table.setRowCount(len(faculties))
for row, f in enumerate(faculties):
self.faculties_table.setItem(row, 0, QTableWidgetItem(str(f[0])))
self.faculties_table.setItem(row, 1, QTableWidgetItem(f[1]))
self.faculties_table.setItem(row, 2, QTableWidgetItem(f[2] or ""))
def add_faculty(self):
name = self.faculty_name.text().strip()
dean = self.faculty_dean.text().strip()
if not name:
QMessageBox.warning(self, "Ошибка", "Введите название факультета")
return
try:
self.db.add_faculty(name, dean)
self.load_all_data()
self.faculty_name.clear()
self.faculty_dean.clear()
self.statusBar.showMessage("Факультет добавлен")
except Exception as e:
QMessageBox.critical(self, "Ошибка", str(e))
def edit_faculty(self):
row = self.faculties_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите факультет")
return
id = int(self.faculties_table.item(row, 0).text())
name = self.faculty_name.text().strip()
dean = self.faculty_dean.text().strip()
if not name:
QMessageBox.warning(self, "Ошибка", "Введите название факультета")
return
self.db.update_faculty(id, name, dean)
self.load_all_data()
self.statusBar.showMessage("Факультет обновлен")
def delete_faculty(self):
row = self.faculties_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите факультет")
return
reply = QMessageBox.question(self, "Подтверждение",
"Удалить факультет? Это также удалит все связанные кафедры, группы и студентов.",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
id = int(self.faculties_table.item(row, 0).text())
self.db.delete_faculty(id)
self.load_all_data()
self.statusBar.showMessage("Факультет удален")
def load_faculty_to_form(self):
row = self.faculties_table.currentRow()
if row < 0:
return
self.faculty_name.setText(self.faculties_table.item(row, 1).text())
self.faculty_dean.setText(self.faculties_table.item(row, 2).text())
# === Кафедры ===
def load_departments(self, faculty_id=None):
departments = self.db.get_departments(faculty_id)
self.departments_table.setRowCount(len(departments))
for row, d in enumerate(departments):
self.departments_table.setItem(row, 0, QTableWidgetItem(str(d[0])))
self.departments_table.setItem(row, 1, QTableWidgetItem(d[1]))
self.departments_table.setItem(row, 2, QTableWidgetItem(d[4])) # faculty_name
self.departments_table.setItem(row, 3, QTableWidgetItem(d[3] or ""))
def filter_departments_by_faculty(self):
faculty_id = self.depts_faculty_filter.currentData()
self.load_departments(faculty_id)
def add_department(self):
name = self.dept_name.text().strip()
faculty_id = self.dept_faculty.currentData()
head = self.dept_head.text().strip()
if not name or not faculty_id:
QMessageBox.warning(self, "Ошибка", "Заполните все обязательные поля")
return
self.db.add_department(name, faculty_id, head)
self.load_all_data()
self.dept_name.clear()
self.dept_head.clear()
self.statusBar.showMessage("Кафедра добавлена")
def edit_department(self):
row = self.departments_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите кафедру")
return
id = int(self.departments_table.item(row, 0).text())
name = self.dept_name.text().strip()
faculty_id = self.dept_faculty.currentData()
head = self.dept_head.text().strip()
if not name or not faculty_id:
QMessageBox.warning(self, "Ошибка", "Заполните все обязательные поля")
return
self.db.update_department(id, name, faculty_id, head)
self.load_all_data()
self.statusBar.showMessage("Кафедра обновлена")
def delete_department(self):
row = self.departments_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите кафедру")
return
reply = QMessageBox.question(self, "Подтверждение",
"Удалить кафедру? Это также удалит все связанные группы и студентов.",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
id = int(self.departments_table.item(row, 0).text())
self.db.delete_department(id)
self.load_all_data()
self.statusBar.showMessage("Кафедра удалена")
def load_department_to_form(self):
row = self.departments_table.currentRow()
if row < 0:
return
self.dept_name.setText(self.departments_table.item(row, 1).text())
self.dept_head.setText(self.departments_table.item(row, 3).text())
# Найти факультет в комбобоксе
faculty_name = self.departments_table.item(row, 2).text()
index = self.dept_faculty.findText(faculty_name)
if index >= 0:
self.dept_faculty.setCurrentIndex(index)
# === Группы ===
def load_groups(self, department_id=None):
groups = self.db.get_groups(department_id)
self.groups_table.setRowCount(len(groups))
for row, g in enumerate(groups):
self.groups_table.setItem(row, 0, QTableWidgetItem(str(g[0])))
self.groups_table.setItem(row, 1, QTableWidgetItem(g[1]))
self.groups_table.setItem(row, 2, QTableWidgetItem(g[4])) # department_name
self.groups_table.setItem(row, 3, QTableWidgetItem(str(g[3])))
def filter_groups_by_department(self):
dept_id = self.groups_dept_filter.currentData()
self.load_groups(dept_id)
def add_group(self):
name = self.group_name.text().strip()
dept_id = self.group_department.currentData()
course = self.group_course.value()
if not name or not dept_id:
QMessageBox.warning(self, "Ошибка", "Заполните все обязательные поля")
return
self.db.add_group(name, dept_id, course)
self.load_all_data()
self.group_name.clear()
self.statusBar.showMessage("Группа добавлена")
def edit_group(self):
row = self.groups_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите группу")
return
id = int(self.groups_table.item(row, 0).text())
name = self.group_name.text().strip()
dept_id = self.group_department.currentData()
course = self.group_course.value()
if not name or not dept_id:
QMessageBox.warning(self, "Ошибка", "Заполните все обязательные поля")
return
self.db.update_group(id, name, dept_id, course)
self.load_all_data()
self.statusBar.showMessage("Группа обновлена")
def delete_group(self):
row = self.groups_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите группу")
return
reply = QMessageBox.question(self, "Подтверждение",
"Удалить группу? Это также удалит всех студентов группы.",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
id = int(self.groups_table.item(row, 0).text())
self.db.delete_group(id)
self.load_all_data()
self.statusBar.showMessage("Группа удалена")
def load_group_to_form(self):
row = self.groups_table.currentRow()
if row < 0:
return
self.group_name.setText(self.groups_table.item(row, 1).text())
self.group_course.setValue(int(self.groups_table.item(row, 3).text()))
dept_name = self.groups_table.item(row, 2).text()
index = self.group_department.findText(dept_name)
if index >= 0:
self.group_department.setCurrentIndex(index)
# === Студенты ===
def load_students(self, group_id=None, search_query=None):
students = self.db.get_students(group_id, search_query)
self.students_table.setRowCount(len(students))
for row, s in enumerate(students):
self.students_table.setItem(row, 0, QTableWidgetItem(str(s[0])))
self.students_table.setItem(row, 1, QTableWidgetItem(s[1]))
self.students_table.setItem(row, 2, QTableWidgetItem(s[2]))
self.students_table.setItem(row, 3, QTableWidgetItem(s[3] or ""))
self.students_table.setItem(row, 4, QTableWidgetItem(s[7])) # group_name
self.students_table.setItem(row, 5, QTableWidgetItem(str(s[5])))
self.students_table.setItem(row, 6, QTableWidgetItem(s[6] or ""))
def filter_students_by_group(self):
group_id = self.students_group_filter.currentData()
self.load_students(group_id)
def search_students(self):
query = self.search_input.text().strip()
if query:
self.load_students(search_query=query)
self.statusBar.showMessage(f"Поиск: {query}")
else:
self.load_students()
def search_students_exact(self):
query = self.search_input.text().strip()
if query:
students = self.db.search_student_exact(query)
self.students_table.setRowCount(len(students))
for row, s in enumerate(students):
self.students_table.setItem(row, 0, QTableWidgetItem(str(s[0])))
self.students_table.setItem(row, 1, QTableWidgetItem(s[1]))
self.students_table.setItem(row, 2, QTableWidgetItem(s[2]))
self.students_table.setItem(row, 3, QTableWidgetItem(s[3] or ""))
self.students_table.setItem(row, 4, QTableWidgetItem(s[7]))
self.students_table.setItem(row, 5, QTableWidgetItem(str(s[5])))
self.students_table.setItem(row, 6, QTableWidgetItem(s[6] or ""))
self.statusBar.showMessage(f"Точный поиск: {query} (найдено: {len(students)})")
def reset_search(self):
self.search_input.clear()
self.students_group_filter.setCurrentIndex(0)
self.load_students()
self.statusBar.showMessage("Поиск сброшен")
def add_student(self):
last_name = self.student_last_name.text().strip()
first_name = self.student_first_name.text().strip()
middle_name = self.student_middle_name.text().strip()
group_id = self.student_group.currentData()
birth_year = self.student_birth_year.value()
email = self.student_email.text().strip()
if not last_name or not first_name or not group_id:
QMessageBox.warning(self, "Ошибка", "Заполните обязательные поля (Фамилия, Имя, Группа)")
return
self.db.add_student(last_name, first_name, middle_name, group_id, birth_year, email)
self.load_students()
self.clear_student_form()
self.statusBar.showMessage("Студент добавлен")
def edit_student(self):
row = self.students_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите студента")
return
id = int(self.students_table.item(row, 0).text())
last_name = self.student_last_name.text().strip()
first_name = self.student_first_name.text().strip()
middle_name = self.student_middle_name.text().strip()
group_id = self.student_group.currentData()
birth_year = self.student_birth_year.value()
email = self.student_email.text().strip()
if not last_name or not first_name or not group_id:
QMessageBox.warning(self, "Ошибка", "Заполните обязательные поля")
return
self.db.update_student(id, last_name, first_name, middle_name, group_id, birth_year, email)
self.load_students()
self.statusBar.showMessage("Студент обновлен")
def delete_student(self):
row = self.students_table.currentRow()
if row < 0:
QMessageBox.warning(self, "Ошибка", "Выберите студента")
return
reply = QMessageBox.question(self, "Подтверждение", "Удалить студента?",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
id = int(self.students_table.item(row, 0).text())
self.db.delete_student(id)
self.load_students()
self.statusBar.showMessage("Студент удален")
def load_student_to_form(self):
row = self.students_table.currentRow()
if row < 0:
return
self.student_last_name.setText(self.students_table.item(row, 1).text())
self.student_first_name.setText(self.students_table.item(row, 2).text())
self.student_middle_name.setText(self.students_table.item(row, 3).text())
self.student_birth_year.setValue(int(self.students_table.item(row, 5).text()))
self.student_email.setText(self.students_table.item(row, 6).text())
# Найти группу
group_name = self.students_table.item(row, 4).text()
index = self.student_group.findText(group_name)
if index >= 0:
self.student_group.setCurrentIndex(index)
def clear_student_form(self):
self.student_last_name.clear()
self.student_first_name.clear()
self.student_middle_name.clear()
self.student_email.clear()
self.student_birth_year.setValue(2003)
def closeEvent(self, event):
"""Закрытие приложения"""
self.db.close()
event.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

View File

@@ -0,0 +1,2 @@
PyQt5>=5.15.0
pyinstaller>=6.0.0