StudentActivityTrackingPage Class

Technical Documentation - Student Progress Monitoring

The StudentActivityTrackingPage class provides a comprehensive dashboard for monitoring individual student progress, combining behavioral observations with academic performance tracking. It serves as a detailed profile view for educators to track learning activities, behavioral patterns, and academic achievements in a unified interface. The page integrates multiple data visualization components including line charts, donut charts, and pie charts to provide actionable insights into student development.

This specialized widget implements a dual-view architecture with a stacked widget system that toggles between behavioral observations and educational activities. It features real-time data processing, interactive charts, and inline editing capabilities for both behavioral notes and academic assignments, creating a complete student progress monitoring solution.

🔍 1. Overview and Architecture

The StudentActivityTrackingPage is a PySide6 widget designed for comprehensive student progress monitoring. It combines student information display, behavioral observation tracking, and educational activity management in a single interface with advanced data visualization.

Architectural Pattern: Composite widget with GridLayout header and StackedWidget body. Uses QListWidget for scrollable content areas and custom widgets for data display. Follows Model-View pattern with database-backed data models.

Core Architectural Components

📊

Header Section

QGridLayout (5x6) containing student information, photo, and three chart visualizations. Shows cumulative score, average score, and activity status distribution.

🔄

Body Section

StackedWidget with two pages: behavioral observations list and educational activities list. Uses navigation buttons to toggle between views.

📈

Chart Engine

Integrates with analysis module to generate line charts, donut charts, and pie charts from student performance data using Matplotlib/Plotly.

Class Inheritance and Dependencies

class StudentActivityTrackingPage(QWidget): # Primary dependencies: # - PySide6.QtWidgets (UI components) # - PySide6.QtGui (Icons, images) # - analysis (Chart generation utilities) # - processing.Imaging.Tools (Image conversion) # - processing.text.text_processing (HTML/text processing) # - app_context (Database access)

System Architecture Diagram

[ARCHITECTURE DIAGRAM: Three-layer system showing:
1. Presentation Layer (Charts, Lists, Forms)
2. Business Logic Layer (Data processing, Status calculation)
3. Data Layer (Database queries, Image generation)
4. Navigation Layer (StackedWidget with dual views)]

🎨 2. UI Layout Structure

Grid Layout Organization (5x6 Grid)

# Header Grid Layout Structure: # Row 0-3: Student photo (spans 4 rows, column 0) # Row 4: Student ID (column 0) # Column 1: Student info (name, phone, parent details) # Column 2: Line chart (score progress over time) # Column 3: Donut chart (cumulative score) # Column 4: Donut chart (average score) # Column 5: Pie chart (activity status distribution) # Row 5: Navigation controls and action buttons

Stacked Widget Navigation System

The page uses a dual-view system with smooth transitions:

# StackedWidget setup with two pages: stacked_widget = StackedWidget() stacked_widget.add_page(self.behav_list) # Page 1: Behavioral observations stacked_widget.add_page(self.quests_list) # Page 2: Educational activities # Navigation buttons: btn_left.clicked.connect(stacked_widget.go_back) # ← Button btn_right.clicked.connect(stacked_widget.go_next) # → Button

Action Toolbar Configuration

Right-aligned action buttons provide quick access to key functions:

Button Icon Tooltip Function
Export Menu 📋 Export data Dropdown with export options (currently disabled)
Add Note ✏️ Add new behaviour note Opens dialog to add behavioral observation
New Edu-Item 📐 New Edu-Item Opens educational resources view for assignment

📊 3. Data Visualization Components

Three-Chart Dashboard System

📈

Line Chart - Score Progression

Purpose: Track score changes over time
Data: Reversed score progression list
Size: 283x170 pixels
Tooltip: "Changes in scores obtained so far."

🍩

Donut Chart - Cumulative Score

Purpose: Show overall performance (20-point scale)
Calculation: earned_score/total_score × 20
Size: 140x140 pixels
Tooltip: "Cumulative score: The sum of all scores..."

📊

Pie Chart - Activity Status

Purpose: Visualize activity completion status
Categories: Replied, Waiting, Delayed, Lost
Size: 145x140 pixels
Tooltip: From app_context.ToolTips['Activity status']

Chart Generation Implementation

# Line chart for score progression scores.reverse() # Reverse for chronological order x_values = list(range(1, 1 + len(scores))) bytes_ = analysis.create_line_chart_image(x_values, scores) image = QImage.fromData(bytes_) # Donut chart for cumulative score scaled_score = round(scaled_score, 2) bytes_ = analysis.create_donut_image(scaled_score, 20) # Pie chart for activity status bytes_ = analysis.create_pie_chart( values=items_status, labels=[f'Replied({items_status[0]})', f'Waiting({items_status[1]})', f'Delayed({items_status[2]})', f'Lost({items_status[3]})'], ncol=2 )
Data Processing Note: Scores are reversed before chart generation because database queries return records in DESC order (newest first). For time-series visualization, chronological order (oldest to newest) is required.

Activity Status Classification

The system classifies educational activities into four status categories:

Status Condition Score Impact Color Coding
Replied Answer submitted before deadline Full/partial score counted Green (success)
Waiting Not replied, deadline not passed Not yet evaluated Blue (pending)
Delayed Answer submitted after deadline Score counted (may be penalized) Orange (warning)
Lost Not replied, deadline passed Zero score assigned Red (failure)

📝 4. Behavioral Observation System

Observation Data Model

Behavioral observations are stored with the following structure:

# Database schema for observed_behaviours: # Id: Primary key # date_time_: Observation timestamp # student_id: Foreign key to personal_info # observed_behaviour_: Teacher's observation notes # analysis_: Teacher's professional analysis cmd = "SELECT Id, date_time_, observed_behaviour_, analysis_ " cmd += "FROM observed_behaviours WHERE student_id ='" + self.student[0] + "' " cmd += "ORDER BY date_time_ DESC;"

Observation Widget Structure

Each observation is displayed in a custom widget with editing capabilities:

# ___create_observed_note_widget() creates: # 1. Header label with ID, date, and menu button # 2. QPlainTextEdit for observed behavior (read-only display) # 3. QPlainTextEdit for teacher analysis (read-only display) # 4. Context menu with Update and Remove actions widget = QWidget() layout = QGridLayout(widget) # Fixed heights: 100px for each text area # Word wrap enabled for readability

CRUD Operations for Observations

Create - add_behaviour_note()

Opens a dialog for adding new observations with separate fields for behavior description and teacher analysis.

query = 'INSERT INTO observed_behaviours(date_time_, student_id, observed_behaviour_, analysis_)' query += 'VALUES (%s, %s, %s,%s) RETURNING Id;' now = datetime.now() id = app_context.database.fetchone(query, (now, self.student[0], behaviuor, analysis))

Update - edit_behaviour_note()

Allows inline editing of existing observations through context menu action.

query = 'UPDATE observed_behaviours SET observed_behaviour_=%s, analysis_=%s WHERE Id=%s;' app_context.database.execute(query, (new_behaviour, new_analysis, record_id))

Delete - delete_behaviour_note()

Includes confirmation dialog before removal to prevent accidental deletion.

button = QMessageBox.warning(self, 'DELETE RECORD', 'ARE YOU SURE TO DELETE THE RECORD ?', QMessageBox.StandardButton.Ok, QMessageBox.StandardButton.Cancel) if not button == QMessageBox.StandardButton.Ok: return query = 'DELETE FROM observed_behaviours WHERE student_Id=%s AND Id =%s;' app_context.database.execute(query, (self.student[0], record_Id))

Behavioral Observation Workflow

[WORKFLOW DIAGRAM: Showing observation lifecycle:
1. Teacher observes behavior → 2. Opens add dialog → 3. Enters observation + analysis
4. Saves to database → 5. Appears in list → 6. Can edit/update later → 7. Optional deletion
With real-time updates and user notifications at each step]

📚 5. Educational Activity Tracking

Activity Data Model and Relationships

Educational activities (quests) are linked to educational resources:

# Complex JOIN query for activity data: cmd = 'SELECT quests.id, quests.max_point_, quests.earned_point_, quests.assign_date_, ' cmd += 'quests.deadline_, quests.answer_, quests.reply_date_, quests.feedback_ , ' cmd += 'educational_resources.content_description_ ' cmd += 'FROM quests LEFT JOIN educational_resources ' cmd += 'ON quests.qb_id = educational_resources.id WHERE quests.student_id = %s ' cmd += 'ORDER BY quests.assign_date_ DESC;' # Record structure (9 fields): # [0] quests.id, [1] max_point_, [2] earned_point_, [3] assign_date_ # [4] deadline_, [5] answer_, [6] reply_date_, [7] feedback_ # [8] content_description_ (from educational_resources)

EduItemStudentWidget Integration

Each activity is displayed using a specialized widget with rich functionality:

# Widget creation with comprehensive data: item = EduItemStudentWidget(record[0], record[8], answer, feedback, record[1], record[2], record[3], record[4], record[6], status) # Signal connections for interactivity: item.data_updated.connect(lambda _, message: PopupNotifier.Notify(self, '', message)) item.delete_executed.connect(lambda _, message: ( self.quests_list.takeItem(row), PopupNotifier.Notify(self, '', message) ))

Status Calculation Algorithm

The system implements sophisticated status determination logic:

if record[6] == None: # No reply yet if today <= deadline: # Still within deadline has_time += 1 status = 'Waiting' else: # Deadline passed without reply lost += 1 status = 'Lost' score_progress.append(record[2]/record[1]) # Zero score included else: # Reply exists if reply <= deadline: # On time replied += 1 status = 'Replied' else: # Delayed submission delayed += 1 status = 'Delayed' score_progress.append(record[2]/record[1]) # Actual score ratio
Score Calculation Note: "Lost" activities (deadline passed without reply) contribute zero scores to the progress calculation, affecting both cumulative and average score metrics. This ensures late or missing submissions properly impact performance metrics.

HTML Content Processing

The system extracts HTML body content for display in widgets:

answer = text_processing.get_html_body_content(record[5]) # Student's answer feedback = text_processing.get_html_body_content(record[7]) # Teacher's feedback # Uses text_processing module to safely extract # HTML body content while stripping potentially # unsafe tags and preserving formatting

⚙️ 6. Core Method Analysis

Initialization and Setup Methods

Method Purpose Complexity Key Operations
__init__(student) Constructor, stores student data O(1) Student data assignment, UI initialization
initUI() Main UI construction O(1) Layout creation, widget assembly, signal connections
init_StudentInfoUI() Student header creation O(1) Grid layout, photo display, info labels

Data Loading Methods

Method Data Source Performance Output
load_behav_data() observed_behaviours table O(n) + widget creation Populated QListWidget with observation widgets
load_quests_data() quests + educational_resources JOIN O(n) + complex calculations Populated QListWidget, returns scores and status counts
___create_observed_note_widget() Individual observation record O(1) per widget Custom widget for display and editing

Interactive Methods

create_charts() - Visualization Assembly

Integrates multiple chart types into the header layout:

  • Line Chart: Position (0,2), spans 5 rows, shows score progression
  • Cumulative Donut: Position (0,3), spans 4 rows, shows overall performance
  • Average Donut: Position (0,4), spans 4 rows, shows mean performance
  • Status Pie: Position (0,5), spans 5 rows, shows activity distribution
# Column stretching for responsive layout: header_layout.setColumnStretch(2, 1) header_layout.setColumnStretch(3, 1) header_layout.setColumnStretch(4, 1) header_layout.setColumnStretch(5, 1)

assign_edu_to_student() - Navigation Integration

Connects to the main application window to open educational resource assignment:

window = QApplication.activeWindow() window.add_page(EduResourcesView(window, [stu])) # Creates a student dictionary with required format: stu = {'Id': self.student[0], 'Name': f'{self.student[1]} {self.student[2]}'}

💾 7. Database Integration

Table Relationships and Joins

Table Primary Key Fields Used Relationship Type
observed_behaviours Id 4 fields (Id, date_time_, observed_behaviour_, analysis_) One-to-many with personal_info
quests id 9 fields including scores, dates, and content Many-to-one with educational_resources
educational_resources id content_description_ (via JOIN) Parent of quests (qb_id foreign key)
personal_info Id Student[0-12] tuple fields Parent of observed_behaviours and quests

Query Patterns and Optimization

Behavioral Observations Query

Simple SELECT with filtering and ordering:

cmd = "SELECT Id, date_time_, observed_behaviour_, analysis_ " cmd += "FROM observed_behaviours WHERE student_id ='" + self.student[0] + "' " cmd += "ORDER BY date_time_ DESC;" # Security Note: Uses string concatenation for student_id # Should be parameterized: WHERE student_id = %s # Potential SQL injection vulnerability
Security Warning: The behavioral observations query uses string concatenation instead of parameterized queries, creating a potential SQL injection vulnerability. Should be updated to use parameterized queries like the quests query.

Educational Activities Query

Complex LEFT JOIN with proper parameterization:

cmd = 'SELECT quests.id, quests.max_point_, quests.earned_point_, quests.assign_date_, ' cmd += 'quests.deadline_, quests.answer_, quests.reply_date_, quests.feedback_ , ' cmd += 'educational_resources.content_description_ ' cmd += 'FROM quests LEFT JOIN educational_resources ' cmd += 'ON quests.qb_id = educational_resources.id WHERE quests.student_id = %s ' cmd += 'ORDER BY quests.assign_date_ DESC;' records = app_context.database.fetchall(cmd, (self.student[0],)) # Parameterized
Query Optimization: Uses LEFT JOIN to ensure quests without linked educational resources still appear in results. ORDER BY assign_date_ DESC shows most recent activities first.

Transaction Management

The class implements proper error handling for database operations:

try: # Attempt database operation app_context.database.execute(query, (self.student[0], record_Id)) msg = 'The note with Id ' + str(record_Id) + ' removed from database.' except Exception as e: msg = f'Database Error: {e}' # User feedback via notification system PopupNotifier.Notify(self, "Message", msg, 'bottom-right', delay=3000)

⚡ 8. Performance Considerations

Memory Usage Analysis

📝

Observation Widgets

Issue: Each observation creates 5+ widgets (QLabels, QPlainTextEdit, QPushButton)
Impact: Linear memory growth with observation count
Solution: Implement pagination or virtual scrolling

📚

Activity Widgets

Issue: EduItemStudentWidget is complex with HTML content
Impact: High per-item memory consumption
Solution: Lazy loading of HTML content

🖼️

Chart Images

Issue: Three chart images stored as QPixmap in memory
Impact: Fixed ~500KB memory usage
Solution: Already optimized with fixed sizes

Time Complexity Analysis

Operation Method Complexity Bottleneck Optimization Potential
Initial data load load_quests_data() O(n) + O(n × w) Widget creation for each activity High - Virtual scrolling
Status calculation Loop in load_quests_data() O(n) Date comparisons and conditionals Low - Already efficient
Chart generation create_charts() O(1) + image processing External chart library overhead Medium - Cache charts
Observation loading load_behav_data() O(n) + O(n × w) Widget creation per observation High - Deferred rendering

Optimization Recommendations

Immediate Improvements

  1. Fix SQL Injection Vulnerability: Parameterize the behavioral observations query
  2. Implement Pagination: Load observations and activities in batches of 20-50
  3. Add Loading Indicators: Show progress during data loading operations
  4. Cache Chart Images: Store generated charts to avoid regeneration on every view

Architectural Improvements

  1. Virtual Scrolling: Replace QListWidget with QListView + custom delegate
  2. Background Loading: Load data in separate thread to prevent UI freezing
  3. Database Indexing: Ensure proper indexes on student_id, date_time_ columns
  4. Lazy HTML Parsing: Parse HTML content only when widget becomes visible

Performance Profiling Results

[PERFORMANCE CHART: Showing execution time vs data volume for:
• Initial Page Load • Chart Generation • Observation Loading • Activity Loading
Highlighting memory usage patterns and CPU utilization peaks]

📚 9. API Reference

Public Methods Reference

Method Parameters Return Description Thread Safety
__init__(student) student: tuple None Constructor with student data UI thread only
add_behaviour_note(data) data: tuple or None None Opens dialog to add behavioral observation UI thread only
edit_behaviour_note() record_id, behaviour_widget, analysis_widget None Updates existing observation UI thread only
delete_behaviour_note() record_Id, record_index None Deletes observation after confirmation UI thread only
assign_edu_to_student(stu) stu: dict None Navigates to educational resource assignment UI thread only
load_behav_data() None None Loads behavioral observations from database UI thread only
load_quests_data() None tuple: (scaled_score, scores, items_status) Loads educational activities and calculates metrics UI thread only

Signal/Slot Connections

Signal Source Signal Slot/Method Purpose
Left navigation button clicked stacked_widget.go_back Shows behavioral observations page
Right navigation button clicked stacked_widget.go_next Shows educational activities page
Add note button clicked add_behaviour_note Opens behavior note dialog
New Edu-Item button clicked assign_edu_to_student Opens educational resources view
EduItemStudentWidget data_updated PopupNotifier.Notify Shows update notifications
EduItemStudentWidget delete_executed Item removal + notification Handles activity deletion

Dependencies and Requirements

Core Dependencies

  • PySide6: >= 6.4.0
  • Python: >= 3.8 (datetime, typing support)
  • analysis module: Custom chart generation utilities

Custom Module Dependencies

  • app_context: Database access and application settings
  • PopupNotifier: User notification system
  • processing.Imaging.Tools: bytea_to_pixmap() for photo conversion
  • processing.text.text_processing: HTML parsing and text utilities
  • processing.text: local_culture_digits() for number formatting
  • ui.widgets.widgets: EduItemStudentWidget, ObservedBehaviourWidget
  • ui.pages.edu_resource_view: EduResourcesView for assignment
  • PySideAbdhUI.Widgets: StackedWidget, Separator (custom UI components)
  • PySideAbdhUI.Notify: PopupNotifier for user feedback

Module Dependency Graph

[DEPENDENCY GRAPH: Visual representation showing:
Core Qt Dependencies → Custom UI Framework → Data Processing Modules →
Database Layer → Visualization Engine → External Widget Libraries
With arrows indicating import relationships and usage frequency]