Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created an Intuitive GUI #23

Merged
merged 4 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions GUI/GUI_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
from PyQt5 import uic
import time
import student
import file_operations
from PyQt5.QtCore import QTimer,Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox,QProgressBar, QTextEdit, QTableWidget, QTableWidgetItem, QHeaderView,QLineEdit,QPushButton

class Mygui(QMainWindow):

def __init__(self):
super(Mygui, self).__init__()

# Load the .ui file
uic.loadUi("GUI\\pages.ui", self)

self.tableWidget = self.findChild(QTableWidget, "tableWidget")
self.pushButton_6.clicked.connect(self.display_records)

header = self.tableWidget.horizontalHeader()
header.setStretchLastSection(True)
header.setSectionResizeMode(QHeaderView.Fixed)
# Connect button signals
self.setup_buttons()
self.progressBar.setValue(3)
self.show()

def setup_buttons(self):
"""Connect buttons to their specific actions."""
# to switch between pages in a QStackedWidget

self.pushButton_1.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(0)) #first page
self.pushButton_5.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(2)) #second page
self.pushButton_7.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(1)) #third page
# To add details:
self.pushButton.clicked.connect(self.add_record)
# To Show the records:
self.pushButton_6.clicked.connect(self.display_records)
# To check the roll number:
self.pushButton_2.clicked.connect(self.check_records)
# To update the records:
self.pushButton_3.clicked.connect(self.update_student_record)
# To delete all Records:
self.pushButton_8.clicked.connect(self.delete_all_records)
# For buttons to work via enter key:
# Update-1
self.setTabOrder(self.lineEdit_4,self.pushButton_2)
# Update-2
self.setTabOrder(self.lineEdit_6,self.lineEdit_5)
self.setTabOrder(self.lineEdit_5,self.pushButton_3)
# Add
self.setTabOrder(self.lineEdit,self.lineEdit_2)
self.setTabOrder(self.lineEdit_3,self.pushButton)

def mousePressEvent(self, event):
"""Reset the progress bar to zero when any part of the window is clicked."""
self.progressBar.setValue(0)
super(Mygui, self).mousePressEvent(event)
def update_progress_bar(self):
"""fill the progress bar with a small delay."""
for i in range(101):
time.sleep(0.001)
self.progressBar.setValue(i)

def add_record(self):
roll = self.lineEdit.text()
name = self.lineEdit_2.text()
percentage = self.lineEdit_3.text()

#check if fields are not empty and percentage is numeric
if roll.isdigit() and percentage.replace('.', '', 1).isdigit():
student_obj = student.Student()
student_obj.add_record(int(roll), name, float(percentage))

self.textEdit.append("Details have been successfully added!")
# Write the student record to the binary file using file_operations
result = file_operations.write_record(student_obj)
self.statusBar().showMessage(result)
# Progress bar:
QTimer.singleShot(0, self.update_progress_bar)
# Clear the input fields
self.lineEdit.clear()
self.lineEdit_2.clear()
self.lineEdit_3.clear()
else:
self.statusBar().showMessage("Invalid input. Please check the fields.")

def check_records(self):
"""Check if the roll number exists and display the student details."""
roll = self.lineEdit_4.text()

if roll.isdigit():
roll = int(roll)
student_record = file_operations.get_record(roll)

if student_record:
# If student_record is a string, split it into components
record_fields = student_record.split(",")
if len(record_fields) == 3: # Ensure there are exactly 3 fields
roll, name, percentage = record_fields
# Format the student data and display it in the textEdit widget
self.textBrowser.setText(f"Roll Number: {roll.strip()}\n"
f"Name: {name.strip()}\n"
f"Percentage: {percentage.strip()}")
self.statusBar().showMessage("Record found!")
else:
self.textBrowser.setText("Error: Record format is incorrect.")
self.statusBar().showMessage("Record format error.")
else:
# If the roll number is not found, show an error message
self.textBrowser.setText("No record found for this roll number.")
self.statusBar().showMessage("Record not found.")
else:
self.statusBar().showMessage("Invalid roll number.")

def update_student_record(self):
# Get roll number, new name, and new percentage from the input fields
roll = self.lineEdit_4.text()
new_name = self.lineEdit_6.text()
new_percentage = self.lineEdit_5.text()

if roll.isdigit():
roll = int(roll)
if not new_name or not new_percentage:
self.statusBar().showMessage("Please provide new details to update.")
return

# If percentage is provided, ensure it's valid
if new_percentage and not new_percentage.replace('.', '', 1).isdigit():
self.statusBar().showMessage("Invalid percentage value.")
return

new_percentage = float(new_percentage) if new_percentage else None

# Call the update_record function
result = file_operations.update_record(roll, new_name, new_percentage)
print(f"Update result: {result}")

# For a success pop-up dialog box
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText(f"Record for Roll Number {roll} has been updated successfully.")
msg.setWindowTitle("Success")
msg.exec_()

# Display the result of the update
if result == "Record updated successfully.":
self.display_records()
else:
self.statusBar().showMessage(result)

# Clear the input fields after the update
self.lineEdit_4.clear()
self.lineEdit_6.clear()
self.lineEdit_5.clear()
self.textBrowser.clear()
else:
self.statusBar().showMessage("Invalid roll number.")

def keyPressEvent(self, event):
if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
# Get the currently focused widget
focused_widget = self.focusWidget()

# Check if the focused widget is a QLineEdit
if isinstance(focused_widget, QLineEdit):
# Move to the next input field or button if focus is on QLineEdit
self.focusNextChild()
elif isinstance(focused_widget, QPushButton):
# Click the QPushButton if it is focused
focused_widget.animateClick()
else:
buttons = self.findChildren(QPushButton)
for button in buttons:
if button.hasFocus():
button.animateClick()
break

super(Mygui, self).keyPressEvent(event)

def display_records(self):
records = file_operations.display_all_records() # Get all records from the file

# Clear the table before displaying new records
self.tableWidget.clearContents()

# Reset row count to match the number of records
self.tableWidget.setRowCount(0)

# Set the number of columns and headers
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(["Roll Number", "Name", "Percentage"])

# Enable the grid and set grid style (if needed)
self.tableWidget.setShowGrid(True)
self.tableWidget.setGridStyle(1)

self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.setAlternatingRowColors(True)

# Set column width to ensure text fits properly
self.tableWidget.setColumnWidth(0, 150) # Adjust the width for Roll Number
self.tableWidget.setColumnWidth(1, 200) # Adjust the width for Name
self.tableWidget.setColumnWidth(2, 150) # Adjust the width for Percentage

if records and records[0] != "No records found.":
# Set row count to the number of records
self.tableWidget.setRowCount(len(records))
for row, record in enumerate(records):
fields = record.strip().split(",")
if len(fields) == 3:
roll, name, percentage = fields
self.tableWidget.setItem(row, 0, QTableWidgetItem(roll.strip()))
self.tableWidget.setItem(row, 1, QTableWidgetItem(name.strip()))
self.tableWidget.setItem(row, 2, QTableWidgetItem(percentage.strip()))
else:
# If no records, ensure the table is empty
self.tableWidget.setRowCount(1)
self.tableWidget.setItem(0, 0, QTableWidgetItem("No records found"))

# Delete all records with confirmation dialog
def delete_all_records(self):
"""Show a confirmation dialog before deleting all records."""
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setWindowTitle("Delete All Records")
msg.setText("Are you sure you want to delete all records?")
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)

# Show the confirmation dialog and check the user's choice
result = msg.exec_()

if result == QMessageBox.Yes:
# Call the file operation to clear all records
result = file_operations.clear_all_records() # Make sure to implement this function
if result == "All records deleted.":
self.display_records() # Refresh the table after deletion
self.statusBar().showMessage("All records have been deleted.")
else:
self.statusBar().showMessage("Error deleting records.")
else:
self.statusBar().showMessage("Delete action canceled.")


def load_stylesheet(app, stylesheet_file):
"""Load the external QSS file."""
try:
with open(stylesheet_file, "r") as file:
app.setStyleSheet(file.read())
except Exception as e:
print(f"Error loading stylesheet: {e}")

def main():
app = QApplication([])

# Load the external stylesheet
load_stylesheet(app, "GUI/stylesheet.qss")
window = Mygui()
app.exec_()

if __name__ == '__main__':
main()

2 changes: 1 addition & 1 deletion GUI/GUI_student.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Mygui(QMainWindow):

def __init__(self):
super(Mygui, self).__init__()
uic.loadUi("first_gui.ui", self)
uic.loadUi("Student-Management-System\\GUI\\first_gui.ui", self)

self.show()

Expand Down
76 changes: 70 additions & 6 deletions GUI/file_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
def write_record(student):
try:
with open("stud.dat", "ab") as file:
pickle.dump(student, file) # Ensure student is a Student instance
return "Record added in file!"
pickle.dump(student, file) # Add the student object to the file
print("New record added successfully.")
return "Record added successfully."
except Exception as e:
return f"Error: {str(e)}"


return f"Error writing record: {e}"

def display_all_records():
records = []
try:
with open("stud.dat", "rb") as file:
while True:
try:
student = pickle.load(file) # Load the Student object
records.append(student.display_record()) # Append the student's record
records.append(student.display_record())
except EOFError:
break
return records if records else ["No records found."]
Expand All @@ -29,6 +29,70 @@ def display_all_records():
return ["Error in unpickling data! The file might be corrupted."]
except IOError:
return ["File could not be opened!"]

def update_record(roll_number, new_name=None, new_percentage=None):
updated = False
records = []

try:
# Open the file in read-binary mode
with open("stud.dat", "rb") as file:
while True:
try:
student_obj = pickle.load(file) # Load each student record
if student_obj.roll == roll_number:
# Update the student details
if new_name:
student_obj.name = new_name.upper()
if new_percentage is not None:
student_obj.per = new_percentage
updated = True
records.append(student_obj)
except EOFError:
break

# Rewrite the updated records
with open("stud.dat", "wb") as file:
for student_obj in records:
pickle.dump(student_obj, file)

if updated:
return f"Record for Roll Number {roll_number} updated successfully."
else:
return f"Record with Roll Number {roll_number} not found."

except FileNotFoundError:
return "File not found! Please add a record first."
except pickle.UnpicklingError:
return "Error in unpickling data! The file might be corrupted."
except Exception as e:
return f"An error occurred: {e}"

def get_record(roll_number):
try:
with open("stud.dat", "rb") as file:
while True:
try:
student_obj = pickle.load(file) # Load each student object
if student_obj.roll == roll_number:
return student_obj.display_record() # Return the record if roll number matches
except EOFError:
break
return f"Record with Roll Number {roll_number} not found."
except FileNotFoundError:
return "File not found! Please add a record first."
except pickle.UnpicklingError:
return "Error in unpickling data! The file might be corrupted."
except Exception as e:
return f"An error occurred: {e}"

def clear_all_records():
try:
with open("stud.dat", "wb") as file:
pass # This will clear the file
return "All records deleted."
except Exception as e:
return f"Error deleting records: {str(e)}"

def delete_file(self):
try:
Expand Down
Loading
Loading