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("", 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()