Files
004_comission/daniel_jo/ITP4459_assignment_2023/src/python/app.py
louiscklaw 5ea2c37f8d update,
2025-01-31 19:38:17 +08:00

191 lines
7.7 KiB
Python

import tkinter
import tkinter.ttk
import constants
from models import Programme
from widgets import ModuleWidget
from pprint import pprint
# app.py - Main GUI dialog
class App(tkinter.Tk):
def __init__(self, db):
super().__init__()
self.__db = db
self.__programme = None
self.__modules = None
self.refresh_db()
self.setup_ui()
# NOTE: Do not modify this method
def report_callback_exception(self, *args):
"""When an error is occurred, raise the exception
so main_gui.py will handle the display of error.
"""
raise args[1].with_traceback(args[2])
def refresh_db(self):
# Fetch all program records from database, and store it in __programme as a list
self.__programme = Programme.fetchall(self.__db)
def setup_ui(self):
self.title(constants.APP_NAME)
self.minsize(640, 480)
# Set weight of column 0 for auto resizing on X axis
self.columnconfigure(0, weight=1)
# Header
frm_top_bar = tkinter.Frame(self)
frm_top_bar.grid(row=0, sticky=tkinter.EW)
tkinter.Label(
frm_top_bar,
text = constants.APP_NAME,
font = ('bold', 16)
).pack(side = tkinter.LEFT, padx=8, pady=8)
tkinter.ttk.Separator(self).grid(row=1, sticky=tkinter.EW)
# Content
frm_content = tkinter.Frame(self)
frm_content.grid(row=2, sticky=tkinter.NSEW)
self.rowconfigure(2, weight=1)
# Options
frm_filter = tkinter.LabelFrame(frm_content, text = "Options")
frm_filter.pack(fill=tkinter.X, side=tkinter.TOP, padx=8, pady=(4, 0))
frm_filter_container = tkinter.Frame(frm_filter)
frm_filter_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4))
# Options variables
# Option widgets
tkinter.Label(frm_filter_container,text = "Programme",).grid(row=0, column=0, padx=(0, 4))
list_of_programme=[]
for p in self.__programme:
list_of_programme.append(p.get_name())
self.selected_programme = tkinter.StringVar()
self.__om_programme_filter = tkinter.ttk.Combobox(frm_filter_container,textvariable=self.selected_programme, width=50)
self.__om_programme_filter.set('Please select')
self.__om_programme_filter['values'] = list_of_programme
self.__om_programme_filter['state'] = 'readonly'
self.__om_programme_filter.grid(row=0, column=1, padx=(0, 4), sticky=tkinter.EW)
self.__om_programme_filter.bind('<<ComboboxSelected>>', self.on_programme_changed )
# Semester select
tkinter.Label( frm_filter_container, text = "Semester").grid(row=0, column=2, padx=(0, 4))
self.selected_semester = tkinter.StringVar()
self.__om_semester_filter = tkinter.ttk.Combobox(frm_filter_container, textvariable=self.selected_semester)
self.__om_semester_filter.set('Please select')
self.__om_semester_filter['state'] = 'disabled'
self.__om_semester_filter.grid(row=0, column=3, padx=(4, 4))
self.__om_semester_filter.bind('<<ComboboxSelected>>', self.on_semester_changed)
# Modules
frm_modules = tkinter.LabelFrame(frm_content, text = "Modules")
frm_modules.pack(fill=tkinter.BOTH, side=tkinter.TOP, expand=1, padx=8, pady=(4, 0))
self.__frm_modules_container = tkinter.Frame(frm_modules)
self.__frm_modules_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4))
self.__module_widgets = list()
for _ in range(constants.APP_MAX_MODULES):
widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed)
widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8)
widget.set_module(None)
self.__module_widgets.append(widget)
# Bottom bar
frm_bottom_bar = tkinter.Frame(self)
frm_bottom_bar.grid(row=3, column=0,padx=(0, 10), pady=(4,4), sticky=tkinter.E)
# Result Label
self.semester_gpa = tkinter.StringVar()
self.lbl_stu_list = tkinter.ttk.Label(frm_bottom_bar, text='Semester GPA: %.2f' % 0, font=("bold",11))
self.lbl_stu_list.grid(row=0, column=0, sticky=tkinter.E)
def setup_module_list(self):
# Update the ModuleWidget in list __module_widgets to display
# modules for the selected programme and semester
current_select_idx = self.__om_semester_filter.current()
selected_semester = list(sorted(self.__modules.keys()))[current_select_idx]
module_in_semester = self.__modules[selected_semester]
for widget in self.__frm_modules_container.winfo_children():
widget.destroy()
self.__module_widgets = list()
i = 0
for _ in range(constants.APP_MAX_MODULES):
widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed)
widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8)
if (i < len(module_in_semester)):
widget.set_module(module_in_semester[i])
self.__module_widgets.append(widget)
i = i + 1
def on_programme_changed(self, _):
# Get selected programme based on option menu index, and update GUI
for program in self.__programme:
if (self.selected_programme.get() == program.get_name()):
self.__om_semester_filter['values'] = sorted(program.get_modules().keys())
self.__modules = program.get_modules()
break
self.__om_semester_filter['state'] = 'readonly'
self.__om_semester_filter.set('Please select')
for widget in self.__frm_modules_container.winfo_children():
widget.destroy()
self.__module_widgets = list()
for _ in range(constants.APP_MAX_MODULES):
widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed)
widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8)
widget.set_module(None)
self.__module_widgets.append(widget)
# reset gpa
self.lbl_stu_list.configure(text='Semester GPA: %.2f' % (0))
def on_semester_changed(self, _):
# Get modules based on option menu value, and update GUI
self.setup_module_list()
# reset gpa
self.lbl_stu_list.configure(text='Semester GPA: %.2f' % (0))
def on_gpa_changed(self):
# Calcuate semester GPA based on self.__modules
# 1. For each modules in self.__modules, App class
# 2. Obtain the module credit of current module and add it to the total credits
# 3. Calculate the module gpa by multiplying the current module gpa and module credit
# 4. Add the calculated module gpa to total module gpa
# 5. After all module gpa are calculated, divide the total module gpa by total credits
total = 0
current_select_idx = self.__om_semester_filter.current()
selected_semester = list(sorted(self.__modules.keys()))[current_select_idx]
module_in_semester = self.__modules[selected_semester]
number_of_modules = len(module_in_semester)
should_update = True
all_credit = 0
for i in range(0, number_of_modules):
gpa = self.__module_widgets[i].get_gpa()
if (gpa == -1):
# not selected
should_update = False
else:
credit =self.__module_widgets[i].get_module().get_credit()
all_credit = all_credit + credit
total = total + (gpa * credit)
if should_update:
self.lbl_stu_list.configure(text='Semester GPA: %.2f' % (total / all_credit))