Implementing Book Addition and Removal in a PyQt5 Library Management System

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:

  1. BookDbManager - Handles book records including queries, additions, updates, and deletions
  2. AddOrDropManager - Tracks inventory changes for audit purposes

These components work together to maintain consistent state between the user interface and the underlying data store.

Tags: PyQt5 Library Management database integration UI Design book management

Posted on Fri, 24 Jul 2026 16:38:18 +0000 by Ifa