Welcome, guest | Sign In | My Account | Store | Cart

Before discovering http://quizlet.com/, the following program was developed for running custom quizzes to help with studying for college courses. The program is not very advanced, but it works reasonably well for what it was designed to do. If the program were developed further, it would need greater capabilities than it currently has and would require a secondary system for actually creating the quizzes (currently, they are hand-typed). Quiz Me could be a starting point for anyone who wishes to actually write a program such as this and inspire others to write much better programs than what this recipe currently offers.

This is the main entry point to the Quiz Me program. It creates the GUI context and sets the program up for automatic error logging. Experimental threading support is provided but unused in the program. Since the main application subclasses a frame, it can easily be embedded in another application without much difficulty. Quiz Me is entirely event based and has an event runner in the very last method shown here.

Python, 163 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import source   # Access the source
source.main()   # and execute main.

####################
# source/__init__.py
####################

import tkinter, time, os, sys, test.support
import xml.sax._exceptions

from tkinter import Label, Frame, LabelFrame, Entry, Button
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showinfo, showwarning, showerror

from . import exe_queue, gui_logs, splash, teach_me, testbank

################################################################################

def main():
    with test.support.captured_output('stderr') as stderr:
        tkinter.NoDefaultRoot()
        root = tkinter.Tk()
        with splash.Splash(root, 'images//QuizMe Logo.gif', 3):
            # Set up the root window.
            root.title('QuizMe 2.5')
            root.resizable(False, False)
            root.wm_iconbitmap(default='images//Icon.ico')
            # Create the program GUI.
            application = QuizMe(root)
            application.grid()
        mainloop(root)
    cleanup(stderr)

def mainloop(root):
    # Threading Support Experiment
    gui_logs.root = exe_queue.Pipe(root)
    while True:
        try:
            root.update()
        except:
            return
        time.sleep(1 / 64)
        gui_logs.root.update()

def cleanup(stream):
    # Record Any Errors
    value = stream.getvalue()
    if value:
        today = time.asctime()
        ruler = '=' * len(today)
        stamp = '{1}\n{0}\n{1}\n'.format(today, ruler)
        file = open('error.log', 'at')
        file.write(stamp)
        file.write(value)
        file.close()

################################################################################

class QuizMe(Frame):

    PROMPT = 'What testbank do you want to open?'

    def __init__(self, master):
        # Initialize the Frame object.
        super().__init__(master)
        # Create every opening widget.
        self.intro = Label(self, text=self.PROMPT)
        self.group = LabelFrame(self, text='Filename')
        self.entry = Entry(self.group, width=35)
        self.click = Button(self.group, text='Browse ...', command=self.file)
        self.enter = Button(self, text='Continue', command=self.start)
        # Make Windows entry bindings.
        def select_all(event):
            event.widget.selection_range(0, tkinter.END)
            return 'break'
        self.entry.bind('<Control-Key-a>', select_all)
        self.entry.bind('<Control-Key-/>', lambda event: 'break')
        # Position them in this frame.
        options = {'sticky': tkinter.NSEW, 'padx': 5, 'pady': 5}
        self.intro.grid(row=0, column=0, **options)
        self.group.grid(row=1, column=0, **options)
        self.entry.grid(row=0, column=0, **options)
        self.click.grid(row=0, column=1, **options)
        self.enter.grid(row=2, column=0, **options)

    def file(self):
        # Find filename for self.entry
        options = {'defaultextension': '.xml',
                   'filetypes': [('All', '*'), ('XML', '.xml')],
                   'initialdir': os.path.join(os.getcwd(), 'tests'),
                   'parent': self,
                   'title': 'Testbank to Open'}
        filename = askopenfilename(**options)
        if filename:
            self.entry.delete(0, tkinter.END)
            self.entry.insert(0, filename)

    def start(self):
        # Validate self.entry and begin
        path = self.entry.get()
        if os.path.exists(path):
            if os.path.isfile(path):
                try:
                    bank = testbank.parse(path)
                    engine = teach_me.FAQ(bank)
                except xml.sax._exceptions.SAXParseException as error:
                    title = error.getMessage().title()
                    LN = error.getLineNumber()
                    CN = error.getColumnNumber()
                    message = 'Line {}, Column {}'.format(LN, CN)
                    showerror(title, message, master=self)
                except AssertionError as error:
                    title = 'Validation Error'
                    message = error.args[0]
                    showerror(title, message, master=self)
                except:
                    title = 'Error'
                    message = 'Unknown exception was thrown!'
                    showerror(title, message, master=self)
                else:
                    self.done = False
                    self.next_event = iter(engine).__next__
                    self.after_idle(self.execute_quiz)
            else:
                title = 'Warning'
                message = 'File does not exist.'
                showwarning(title, message, master=self)
        else:
            title = 'Information'
            message = 'Path does not exist.'
            showinfo(title, message, master=self)

    def execute_quiz(self):
        # Follow the logic from the last program.
        # This will be called to handle an event.
        try:
            event = self.next_event()
        except StopIteration:
            assert self.done, 'Final event not processed!'
        else:
            if isinstance(event, teach_me.Enter):
                gui_logs.ShowStatus(self, 'Entering', event, self.execute_quiz)
            elif isinstance(event, teach_me.Exit):
                gui_logs.ShowStatus(self, 'Exiting', event, self.execute_quiz)
                self.last_exit = event.kind
            elif isinstance(event, teach_me.Question):
               gui_logs. AskQuestion(self, event, self.execute_quiz)
            elif isinstance(event, teach_me.Report):
                flag = [True]
                if self.last_exit == 'Section' and event.wrong:
                    flag[0] = False
                    gui_logs.ReviewProblems(self, event, flag)
                if flag[0]:
                    gui_logs.ShowReport(self, event, self.execute_quiz)
                if event.final:
                    title = 'Congratulations!'
                    message = 'You have finished the test.'
                    showinfo(title, message, master=self)
                    self.done = True
            else:
                title = 'Type Error'
                message = repr(event)
                showerror(title, message, master=self)