Files
004_comission/hdhdjshxh/task2/project/src/Assignment.py
louiscklaw 118e4a5f39 update,
2025-01-31 19:51:33 +08:00

509 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import sys
import re
import datetime
import tkinter
import tkinter.ttk
import tkinter.messagebox
import tkinter.scrolledtext
from tkinter import *
# class starts
class HDinfo():
# Attributes:
# institutionName a non-public string to store the HD institution name of the applicant.
# programmeTitle a non-public string to store the HD programme name of the applicant.
# gpa a non-public double to store the HD GPA of the applicant.
# expectedGradeYear a non-public int to store the Expected HD Graduation Year of the applicant.
# Methods:
# init initialize all attributes in HDinfo object. It is a Parameterized constructor.
# str return a string containing the Attributes of HDinfo object. This method is used to display in Summary ScrolledText.
# constructor __init__
def __init__(self, institutionName="", programmeTitle="", gpa="", expectedGraYear=""):
self.institutionName = institutionName
self.programmeTitle = programmeTitle
self.gpa = gpa
self.expectedGraYear = expectedGraYear
pass
# __str__ method
def __str__(self):
return """
Higher Diploma Information:
Institution Name: {hd_institution_name}
Programme Title: {hd_programme_title}
GPA: {hd_gpa}
Expected Graduation Year: {expectedGraYear}
""".strip().format(
hd_institution_name=self.institutionName,
hd_programme_title=self.programmeTitle,
hd_gpa=self.gpa,
expectedGraYear=self.expectedGraYear,
)
class Applicant():
# Attributes:
# name a non-public string to store the name of the applicant.
# email a non-public string to store the email of the applicant.
# gender a non-public string to store the gender of the applicant.
# dateOfBirth a non-public string to store the applicant date of birth.
# applyDegreeProgramme a non-public string to store the applicant selected
# degree programme
# hdInfo a non-public HDinfo(self-defined class) to store the applicant Higher
# Diploma information
# Methods:
# init initialize all attributes in Applicant object. It is a Parameterized constructor.
# setPeronalInfo setter method to set the name, email, gender, dateOfBirth, applyDegreeProgrmme into the Applicant object.
# setHDinfo setter method to set the HDinfo object into the Applicant object.
# str return a string containing the Attributes of this Applicant. This function is used to display in Summary ScrolledText.
# constructor __init__
def __init__(self, name="", email="", gender="", dateOfBirth="", applyDegreeProgramme="", hdInfo=HDinfo()):
self.name = name
self.email = email
self.gender = gender
self.dateOfBirth = dateOfBirth
self.applyDegreeProgramme = applyDegreeProgramme
pass
# Set Personal Info Method
def setPeronalInfo(self, name, email, gender, dateOfBirth, applyDegreeProgramme):
self.name = name
self.email = email
self.gender = gender
self.dateOfBirth = dateOfBirth
self.applyDegreeProgramme = applyDegreeProgramme
# Set HD Info Method
def setHDInfo(self, hd):
self.hd = hd
pass
# __str__ method
def __str__(self):
"""
Returns a string representation of the Applicant object.
Returns:
str: A formatted string containing the applicant's name, email, gender, date of birth, and applied degree programme.
Also includes a string representation of the Higher Diploma object.
"""
return """
Applicant Name: {applicant_name}
Applicant Email: {applicant_email}
Gender: {gender}
Date of Birth: {DOB}
Apply Degree Programme: {applyDegreeProgramme}
""".strip().format(
applicant_name=self.name,
applicant_email=self.email,
gender=self.gender,
DOB=self.dateOfBirth,
applyDegreeProgramme=self.applyDegreeProgramme,
) + '\n' + self.hd.__str__()
applicant = Applicant()
# class ends
# Tkinter starts
# Parent class for Personal and HighDiploma
class ApplicationPage(tkinter.Frame):
"""Base class for managed pages. Provides methods to be overridden by subclasses."""
def __init__(self, master):
super().__init__(master)
def is_complete(self) -> bool:
"""Check if the current page is complete."""
return True
class Personal(ApplicationPage):
def __init__(self, master):
super().__init__(master)
frm_base = tkinter.Frame(self)
frm_base.pack(fill=tkinter.BOTH, expand=True)
frm_title = tkinter.Frame(frm_base)
frm_title.pack(fill=tkinter.BOTH)
lbl_title = tkinter.Label(
frm_title, text="Personal Infromation", font=("bold", 15))
lbl_title.pack(anchor=tkinter.W)
###
# Write your coding here
# Frame for the content
frm_content = tkinter.Frame(frm_base)
frm_content.pack(fill=tkinter.BOTH, expand=True)
frm_content.grid_columnconfigure(2, weight=1)
# Row counter, to advance row in screen
row = 0
# Label for applicant name
lbl_name = tkinter.Label(
frm_content, text="Applicant Name", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
# Entry box for applicant name
self.ent_applicant_name = tkinter.Entry(frm_content)
self.ent_applicant_name.insert(0, "")
self.ent_applicant_name.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
# Label for applicant email
lbl_name = tkinter.Label(
frm_content, text="Applicant Email", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
# Entry box for applicant email
self.ent_applicant_email = tkinter.Entry(frm_content)
self.ent_applicant_email.insert(0, "")
self.ent_applicant_email.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
# String variable to store the selected gender
self.gender_select = tkinter.StringVar(value="Male")
# Label for gender
lbl_gender = tkinter.Label(
frm_content, text="Gender", anchor="w", justify="left", width=20)
lbl_gender.grid(row=row, column=0)
# Radio buttons for gender selection
rad_male = tkinter.Radiobutton(
frm_content, variable=self.gender_select, text="Male", value="Male")
rad_male.grid(row=row, column=1)
rad_female = tkinter.Radiobutton(
frm_content, variable=self.gender_select, text="Female", value="Female")
rad_female.grid(row=row, column=2)
row += 1
# Label for date of birth
lbl_name = tkinter.Label(
frm_content, text="Date of Birth", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
# Entry box for date of birth
self.ent_applicant_DOB = tkinter.Entry(frm_content)
self.ent_applicant_DOB.insert(0, "")
self.ent_applicant_DOB.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
# Label for apply programme
lbl_name = tkinter.Label(
frm_content, text="Apply Programme", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
# List of programme options and combobox for apply programme
lst_programme = ["Bachelor of Science in Cybersecurity",
"Bachelor of Science in Computer Science and AI"]
self.applicant_programme = tkinter.ttk.Combobox(
frm_content, textvariable=lst_programme, values=lst_programme, state="readonly",)
self.applicant_programme.current(0)
self.applicant_programme.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
def is_complete(self):
###
# Write your coding here
entry_valid = True
if self.ent_applicant_name.get() == "":
tkinter.messagebox.showinfo("Information", "name cannot empty.")
entry_valid = False
if self.ent_applicant_email.get() == "":
tkinter.messagebox.showinfo(
"Information", "email field cannot empty.")
entry_valid = False
else:
# check if email field valid
# https://www.geeksforgeeks.org/check-if-email-address-valid-or-not-in-python/
if not re.match(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b', self.ent_applicant_email.get()):
tkinter.messagebox.showinfo(
"Information", "email: format error, it should be email.")
entry_valid = False
if self.ent_applicant_DOB.get() == "":
tkinter.messagebox.showinfo(
"Information", "dob field cannot empty.")
entry_valid = False
else:
# python re to check if yyyy/mm/dd
if not re.match(r'^\d{4}/\d{2}/\d{2}$', self.ent_applicant_DOB.get()):
tkinter.messagebox.showinfo(
"Information", "DOB format error, it should be yyyy/mm/dd.")
entry_valid = False
# ptyhon to check if the day entered is latter than today
today = datetime.date.today()
if datetime.datetime.strptime(self.ent_applicant_DOB.get(), '%Y/%m/%d').date() > today:
tkinter.messagebox.showinfo(
"Information", "DOB the day enter is latter than today.")
entry_valid = False
if (entry_valid):
applicant.setPeronalInfo(
self.ent_applicant_name.get(),
self.ent_applicant_email.get(),
self.gender_select.get(),
self.ent_applicant_DOB.get(),
self.applicant_programme.get()
)
return True
return False
class HighDiploma(ApplicationPage):
def __init__(self, master):
super().__init__(master)
frm_base = tkinter.Frame(self)
frm_base.pack(fill=tkinter.BOTH, expand=True)
frm_title = tkinter.Frame(frm_base)
frm_title.pack(fill=tkinter.BOTH)
lbl_title = tkinter.Label(
frm_title, text="Higher Diploma Information", font=("bold", 15))
lbl_title.pack(anchor=tkinter.W)
###
# Write your coding here
# Content frame for the form entries
row = 0 # row counter for the form
frm_content = tkinter.Frame(frm_base)
frm_content.pack(fill=tkinter.BOTH)
frm_content.grid_columnconfigure(2, weight=1)
# Label and entry for Institution name
lbl_name = tkinter.Label(
frm_content, text="Institution Name", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
self.ent_institution_name = tkinter.Entry(frm_content)
self.ent_institution_name.insert(0, "")
self.ent_institution_name.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
# Label and entry for Programme Title
lbl_name = tkinter.Label(
frm_content, text="Programme Title", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
self.ent_programme_title = tkinter.Entry(frm_content)
self.ent_programme_title.insert(0, "")
self.ent_programme_title.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
# Label and entry for GPA
lbl_name = tkinter.Label(
frm_content, text="GPA", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
self.ent_GPA = tkinter.Entry(frm_content)
self.ent_GPA.insert(0, "")
self.ent_GPA.grid(row=row, column=1, columnspan=2,
sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
# Label and entry for Expected Graduation Year
lbl_name = tkinter.Label(
frm_content, text="Expected Graduation Year", anchor="w", justify="left", width=20)
lbl_name.grid(row=row, column=0)
self.expected_grad_year = tkinter.Entry(frm_content)
self.expected_grad_year.insert(0, "")
self.expected_grad_year.grid(
row=row, column=1, columnspan=2, sticky="nsew", pady=(10, 10), padx=(10, 10))
row += 1
###
def is_complete(self):
###
# Write your coding here
entry_valid = True
if self.ent_institution_name.get() == "":
tkinter.messagebox.showinfo(
"Information", "institution name field cannot empty.")
entry_valid = False
if self.ent_programme_title.get() == "":
tkinter.messagebox.showinfo(
"Information", "programme title field cannot empty.")
entry_valid = False
if self.ent_GPA.get() == "":
tkinter.messagebox.showinfo(
"Information", "GPA field cannot empty.")
entry_valid = False
else:
# check if gpa field is a number
try:
float(self.ent_GPA.get())
except ValueError:
tkinter.messagebox.showinfo(
"Information", "GPA field should be a number.")
entry_valid = False
if self.expected_grad_year.get() == "":
tkinter.messagebox.showinfo(
"Information", "Expected graduation year field cannot empty.")
entry_valid = False
else:
# check if gpa field is a number
try:
int(self.expected_grad_year.get())
# check if expected grad year is after current year
today = datetime.date.today()
if int(self.expected_grad_year.get()) < today.year:
tkinter.messagebox.showinfo(
"Information", "Expected graduation year should be after current year.")
entry_valid = False
except ValueError:
tkinter.messagebox.showinfo(
"Information", "Expected graduation year field should be a number.")
entry_valid = False
hd = HDinfo(
self.ent_institution_name.get(),
self.ent_programme_title.get(),
self.ent_GPA.get(),
self.expected_grad_year.get()
)
if (entry_valid):
applicant.setHDInfo(hd)
return True
return False
class Result(ApplicationPage):
def __init__(self, master):
super().__init__(master)
frm_base = tkinter.Frame(self)
frm_base.pack(fill=tkinter.BOTH, expand=True)
frm_title = tkinter.Frame(frm_base)
frm_title.pack(fill=tkinter.BOTH)
lbl_title = tkinter.Label(frm_base, text="Summary", font=("bold", 15))
lbl_title.pack(anchor=tkinter.W)
# Summary Output
###
# Write your coding here
row = 0
frm_content = tkinter.Frame(frm_base)
frm_content.pack(fill=tkinter.BOTH)
frm_content.grid_columnconfigure(2, weight=1)
# textbox for summary
self.txt_summary = tkinter.Text(frm_content, height=12)
self.txt_summary.grid(row=row, column=1, columnspan=2,
sticky="nsew", pady=(1, 1), padx=(1, 1))
row += 1
# right justify button with text "show"
btn_show = tkinter.Button(frm_base, text="Show", anchor=tkinter.E)
btn_show.pack(side=tkinter.RIGHT)
# tkinter bind button click
btn_show.bind("<Button-1>", self.show)
###
def show(self, _): # Show Button method
###
# Write your coding here
self.txt_summary.insert(tkinter.INSERT, str(applicant))
###
class Application(tkinter.Tk):
def __init__(self):
super().__init__()
# Configure GUI
self.title("Undergraduate Application Form")
self.geometry("450x300")
# Content Frame
frm_content = tkinter.Frame(self, relief=tkinter.RIDGE, borderwidth=1)
frm_content.pack(fill=tkinter.BOTH, expand=True)
frm_content.rowconfigure(0, weight=1)
frm_content.columnconfigure(0, weight=1)
# Application Pages
self.__frames: list[ApplicationPage] = [
Personal(frm_content),
HighDiploma(frm_content),
Result(frm_content),
]
for i in self.__frames:
i.grid(row=0, column=0, sticky=tkinter.NSEW)
self.__current_page = 0
self.__frames[self.__current_page].tkraise()
# Bottom Frame
frm_button = tkinter.Frame(self, padx=4, pady=4)
frm_button.pack(side=tkinter.BOTTOM, fill=tkinter.X)
# Next Button
self.btn_next = tkinter.Button(
frm_button, text="Next", command=self.next_page)
self.btn_next.pack(side=tkinter.RIGHT)
# Quit Button
self.btn_quit = tkinter.Button(
frm_button, text="Quit", command=self.destroy)
def next_page(self):
# Check if the current page is complete
if not self.__frames[self.__current_page].is_complete():
tkinter.messagebox.showinfo(
"Information", "Please fill the missing fields."
)
return
# Navigate to next page
self.__current_page += 1
self.__frames[self.__current_page].tkraise()
# If we reached the last page, replace the next button with quit button
if self.__current_page + 1 == len(self.__frames):
self.btn_next.pack_forget()
self.btn_quit.pack(side=tkinter.RIGHT)
# Tkinter ends
if __name__ == "__main__":
app = Application()
app.mainloop()