Database Integration
The application requires database functionality to manage book records. Before implementing the addition and removal features, ensure the database module is properly configured.
UI Design for Adding Books
The interface for adding books uses a dialog window with input fields for:
- Title
- ISBN
- Author
- Category (predefined list)
- Publisher
- Publication date
- Quantity to add
Class Initialization
from PyQt5.QtWidgets import QDialog, QFormLayout, QLabel, QLineEdit, QComboBox, QPushButton, QDateTimeEdit, QMessageBox
from PyQt5.QtCore import pyqtSignal, Qt
from db.book_manager import BookDbManager, AddOrDropManager
class AddBookDialog(QDialog):
add_book_success_signal = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.setup_ui()
self.setWindowModality(Qt.WindowModal)
self.book_db = BookDbManager()
self.add_drop_db = AddOrDropManager()
self.setWindowTitle("Add New Book")
User Interface Construction
def setup_ui(self):
categories = ["Philosophy", "Social Sciences", "Politics", "Law", "Military", "Economics",
"Culture", "Education", "Sports", "Languages", "Arts", "History", "Geography",
"Astronomy", "Biology", "Medicine", "Agriculture"]
self.resize(300, 400)
layout = QFormLayout()
self.setLayout(layout)
# Labels
self.title_label = QLabel(" Add New Book")
self.title_label.setAlignment(Qt.AlignCenter)
self.title_label.setStyleSheet("font-size: 20px; font-weight: bold;")
self.name_label = QLabel("Title:")
self.isbn_label = QLabel("ISBN:")
self.author_label = QLabel("Author:")
self.category_label = QLabel("Category:")
self.publisher_label = QLabel("Publisher:")
self.date_label = QLabel("Publication Date:")
self.quantity_label = QLabel("Quantity:")
# Input widgets
self.title_input = QLineEdit()
self.isbn_input = QLineEdit()
self.author_input = QLineEdit()
self.category_combo = QComboBox()
self.category_combo.addItems(categories)
self.publisher_input = QLineEdit()
self.date_picker = QDateTimeEdit()
self.date_picker.setDisplayFormat("yyyy-MM-dd")
self.quantity_input = QLineEdit()
# Validation
self.title_input.setMaxLength(10)
self.isbn_input.setMaxLength(6)
self.author_input.setMaxLength(10)
self.publisher_input.setMaxLength(10)
self.quantity_input.setMaxLength(12)
self.quantity_input.setValidator(QIntValidator())
# Layout arrangement
layout.addRow(self.title_label)
layout.addRow(self.name_label, self.title_input)
layout.addRow(self.isbn_label, self.isbn_input)
layout.addRow(self.author_label, self.author_input)
layout.addRow(self.category_label, self.category_combo)
layout.addRow(self.publisher_label, self.publisher_input)
layout.addRow(self.date_label, self.date_picker)
layout.addRow(self.quantity_label, self.quantity_input)
# Button
self.add_button = QPushButton("Add Book")
layout.addRow(self.add_button)
# Event connection
self.add_button.clicked.connect(self.handle_add)
Adding Logic Implementation
def handle_add(self):
title = self.title_input.text().strip()
isbn = self.isbn_input.text().strip()
author = self.author_input.text().strip()
category = self.category_combo.currentText()
publisher = self.publisher_input.text().strip()
date = self.date_picker.text()
quantity = self.quantity_input.text().strip()
# Validation check
if not all([title, isbn, author, category, publisher, date, quantity]):
QMessageBox.warning(self, "Warning", "All fields must be filled!", QMessageBox.Ok)
return
try:
quantity = int(quantity)
except ValueError:
QMessageBox.warning(self, "Error", "Invalid quantity entered!", QMessageBox.Ok)
return
# Check if book exists
existing_book = self.book_db.query_by_isbn(isbn)
if existing_book:
# Update existing record
self.book_db.update_book_info(quantity, isbn, add_flag=True)
else:
# Create new record
self.book_db.add_book(title, isbn, author, category, publisher, date, quantity, quantity, 0)
# Log the transaction
import time
current_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
self.add_drop_db.add_info(isbn, current_date, quantity)
QMessageBox.information(self, "Success", "Book added successfully!", QMessageBox.Ok)
self.add_book_success_signal.emit()
self.close()
self.clear_fields()
def clear_fields(self):
self.title_input.clear()
self.isbn_input.clear()
self.author_input.clear()
self.quantity_input.clear()
self.publisher_input.clear()
UI Design for Removing Books
The removal interface shares similar elements but restricts most fields to read-only mode, allowing only ISBN and quantity inputs.
Removal Class Structure
from PyQt5.QtWidgets import QDialog, QFormLayout, QLabel, QLineEdit, QComboBox, QPushButton, QMessageBox
from PyQt5.QtCore import pyqtSignal, Qt
from db.book_manager import BookDbManager, AddOrDropManager
class RemoveBookDialog(QDialog):
remove_book_successful_signal = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.setup_ui()
self.setWindowModality(Qt.WindowModal)
self.setWindowTitle("Remove Book")
self.book_db = BookDbManager()
self.add_drop_db = AddOrDropManager()
Interface Setup
def setup_ui(self):
categories = ["Philosophy", "Social Sciences", "Politics", "Law", "Military", "Economics",
"Culture", "Education", "Sports", "Languages", "Arts", "History", "Geography",
"Astronomy", "Biology", "Medicine", "Agriculture"]
self.resize(300, 400)
layout = QFormLayout()
self.setLayout(layout)
# Labels
self.title_label = QLabel(" Remove Book")
self.title_label.setAlignment(Qt.AlignCenter)
self.title_label.setStyleSheet("font-size: 20px; font-weight: bold;")
self.name_label = QLabel("Title:")
self.isbn_label = QLabel("ISBN:")
self.author_label = QLabel("Author:")
self.category_label = QLabel("Category:")
self.publisher_label = QLabel("Publisher:")
self.date_label = QLabel("Publication Date:")
self.quantity_label = QLabel("Removal Quantity:")
# Input widgets
self.title_input = QLineEdit()
self.title_input.setReadOnly(True)
self.title_input.setStyleSheet("background-color: #363636;")
self.isbn_input = QLineEdit()
self.author_input = QLineEdit()
self.author_input.setReadOnly(True)
self.author_input.setStyleSheet("background-color: #363636;")
self.category_combo = QComboBox()
self.category_combo.addItems(categories)
self.category_combo.setStyleSheet("background-color: #363636;")
self.publisher_input = QLineEdit()
self.publisher_input.setReadOnly(True)
self.publisher_input.setStyleSheet("background-color: #363636;")
self.date_input = QLineEdit()
self.date_input.setStyleSheet("background-color: #363636;")
self.quantity_input = QLineEdit()
self.quantity_input.setValidator(QIntValidator())
# Layout arrangement
layout.addRow(self.title_label)
layout.addRow(self.name_label, self.title_input)
layout.addRow(self.isbn_label, self.isbn_input)
layout.addRow(self.author_label, self.author_input)
layout.addRow(self.category_label, self.category_combo)
layout.addRow(self.publisher_label, self.publisher_input)
layout.addRow(self.date_label, self.date_input)
layout.addRow(self.quantity_label, self.quantity_input)
# Button
self.remove_button = QPushButton("Remove Book")
layout.addRow(self.remove_button)
# Event connections
self.isbn_input.textChanged.connect(self.on_isbn_changed)
self.remove_button.clicked.connect(self.handle_remove)
Removal Logic Implementation
def on_isbn_changed(self):
isbn = self.isbn_input.text().strip()
if not isbn:
self.clear_fields()
return
book_info = self.book_db.query_by_isbn(isbn)
if book_info:
data = book_info[0]
self.title_input.setText(data[0])
self.author_input.setText(data[2])
self.category_combo.setCurrentText(data[3])
self.publisher_input.setText(data[4])
self.date_input.setText(data[5])
def handle_remove(self):
isbn = self.isbn_input.text().strip()
quantity = self.quantity_input.text().strip()
if not isbn:
QMessageBox.warning(self, "Error", "Please enter an ISBN first!", QMessageBox.Ok)
return
if not quantity:
QMessageBox.warning(self, "Warning", "Removal quantity cannot be empty!", QMessageBox.Ok)
return
try:
quantity = int(quantity)
except ValueError:
QMessageBox.warning(self, "Error", "Invalid quantity entered!", QMessageBox.Ok)
return
book_info = self.book_db.query_by_isbn(isbn)
if not book_info:
QMessageBox.warning(self, "Error", "Book not found in database!", QMessageBox.Ok)
return
data = book_info[0]
total_stock = data[6]
available_stock = data[7]
borrowed_count = data[8]
# Validation checks
if quantity > available_stock:
QMessageBox.warning(self, "Warning", f"Cannot remove more than {available_stock} copies!", QMessageBox.Ok)
return
if quantity <= 0:
QMessageBox.warning(self, "Warning", "Invalid removal quantity!", QMessageBox.Ok)
return
# Process removal
if quantity < available_stock:
self.book_db.update_book_info(quantity, isbn, add_flag=False)
elif quantity == total_stock and borrowed_count == 0:
self.book_db.remove_book(isbn)
# Log transaction
import time
current_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
self.add_drop_db.drop_info(isbn, current_date, quantity)
QMessageBox.information(self, "Success", "Book removed successfully!", QMessageBox.Ok)
self.remove_book_successful_signal.emit()
self.close()
def clear_fields(self):
self.title_input.clear()
self.author_input.clear()
self.publisher_input.clear()
self.date_input.clear()
self.quantity_input.clear()
Database Operations
The system relies on two core database managers:
- BookDbManager - Handles book records including queries, additions, updates, and deletions
- AddOrDropManager - Tracks inventory changes for audit purposes
These components work together to maintain consistent state between the user interface and the underlying data store.