0

I have a situation where I have two lists of different lengths. These lists may not be consistent every time this script is run, but for the purposes of this example, I'm going to use students and grades.

In this example, I have 4 students and 6 grades. I want to be able to generate a GUI where I have a label for each student in the columns and then assign a letter grade (A-F) to each student. I've managed to create the labels in a dictionary format using dictionary comprehension, as the number of students may change.

The problem arises when I try to get an equal amount of option menus to assign the letter grade. Rather than equaling the number of students, it will equal the number of grades (6 in this example).

1). How do I get the number of option menus to equal the number of students (but retain the 6 grades in the grade list)?

2). How can I dynamically extract (return?) the assigned student grade to the debbger/main memory to be used in later calculations outside of the class?

Here's my code:

import tkinter as tk
from tkinter import Tk, filedialog, ttk, StringVar, OptionMenu, Button

root = tk.Tk()
root.geometry("1200x600")
root.resizable(True, True)
root.title("Define Grades")


class DefineGrades:
    def __init__(self, master):
        """Creates a GUI to assign letter grades (n=6) to a limited number of students (n=4)"""
        self.students = ['Student_1', 'Student_2', 'Student_3', 'Student_4']
        self.grades = ['A', 'B', 'C', 'D', 'E', 'F']

        # Create labels for the students in the GUI
        self.student_labels = {student: ttk.Label(root, text=f'Select the grade for {student}')
                               for student in self.students}
        # Place the student label on the GUI
        _ = {student: self.student_labels[student].grid(column=0, row=student_num, pady=5)
             for student_num, student in enumerate(self.students)}

        # Create the option menu for the grades to be assigned
        self.grade_selection_menu = {grade: StringVar(root) for grade in self.grades}
        _ = {grade: self.grade_selection_menu[grade].set('Set Grade')
             for grade in self.grades}
        self.grade_selection = {grade: OptionMenu(root, self.grade_selection_menu[grade], *self.grades)
                              for grade in self.grades}

        # place the option menus for the grades on the GUI
        _ = {grade: self.grade_selection[grade].grid(column=1, row=grade_num)
             for grade_num, grade in enumerate(self.grades)}

        # Create a button to submit the data to the main memory
        self.submit_button = ttk.Button(master, text="Submit Grades", command=self.submit_grades)
        self.submit_button.grid(column=2, row=0)

    def submit_grades(self):
        global submitted_grades

        submitted_grades = {grade: self.grade_selection[grade].get()
                            for grade in self.grades}
        return submitted_grades


_ = DefineGrades(root)

root.mainloop()

print(submitted_grades)
ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
Nev Pires
  • 175
  • 1
  • 9

1 Answers1

0

Comprehension is good thing to know, but in this case it makes code hard to read and makes it complicated.

In the end, you're creating labeled menu. There is plenty of ways to do it, but I will just use plain old for loop and generalize your solution a bit.
Also I removed global submit variable and replaces it with get method, so you can easily evaluate the code.

import tkinter as tk
from tkinter import ttk, StringVar, OptionMenu

root = tk.Tk()
root.geometry("1200x600")
root.resizable(True, True)
root.title("Define Grades")


class DefineGrades:
    def __init__(self, master):
        """Creates a GUI to assign letter grades (n=6) to a limited number of students (n=4)"""
        labels = ['Student_1', 'Student_2', 'Student_3', 'Student_4']
        menu_options = ['A', 'B', 'C', 'D', 'E', 'F']
        self.menu_vars = []

        for row, label in enumerate(labels):
            # Create menu label amd place it on grid
            label_item = ttk.Label(root, text=f'Select the grade for {label}')
            label_item.grid(column=0, row=row, pady=5)
            # Create menu combox and place it on the grid
            self.menu_vars.append(StringVar(root, value='Set Grade'))
            menu_combox = OptionMenu(root, self.menu_vars[-1], *menu_options)
            menu_combox.grid(column=1, row=row)

        # Create a button to submit the data to the main memory
        self.submit_button = ttk.Button(master, text="Get Grades", command=self.get_values)
        self.submit_button.grid(column=2, row=0)

    def get_values(self):
        final_values = {i: menu_item.get() for i, menu_item in enumerate(self.menu_vars)}
        print(final_values)
        return final_values


student_grades = DefineGrades(root)
root.mainloop()

print(student_grades.get_values())
Domarm
  • 2,360
  • 1
  • 5
  • 17