객관식 문제 채점 프로그램 (python)

    목차
반응형

용도 : 시험 대비 등을 위하여 같은 문제를 여러 번 반복해서 풀어보기 위해 책 대신 다른 곳에 답을 적을 때 이 프로그램에 답을 입력, (답안 텍스트 파일을 설정 시) 채점까지 대신해준다.

 

Grading.exe
7.07MB
Grading.py
0.03MB

 

기능

1. 프로그램 내 타이머가 있어 시간 제한을 둘 수 있다.

2. 답안 텍스트 파일을 통해 채점을 대신하여 합불합 여부를 알려준다. (과락인지 종합 점수 부족인지 또한 알려준다.)

3. 성적이 향상했는지 확인할 수 있도록 결과를 저장할 수 있다.

 

주의사항 : 답안 텍스트 파일 작성시 한 줄에 10문제씩 입력해야한다. (연습문제 한정, 모의고사는 관계 없음)

 

사용법 예시1 - 연습문제

더보기

연습문제 버튼을 클릭하여 문항수와 시간을 설정하고 확인을 누르면 아래와 같은 시험창이 뜬다.

띄어쓰기 없이 답을 입력한다.

코드를 대충 짜서 한 줄에 답을 열개 이상 입력해도 입력은 된다. 그래도 채점에는 들어가지 않는다.

 

이후 제출하기를 클릭하면 답안 텍스트 파일을 선택해야한다.

위 그림처럼 한 줄에 10문제의 답을 적어 텍스트 파일을 만들어 이 파일을 선택해주면 아래와 같은 결과창이 뜬다. 

 

사용법 예시2 - 모의고사

더보기

실제 시험처럼 과목 수, 과목별 점수컷, 전체 점수컷을 입력해준다.

이후 과목별 문항수와 시간을 입력하고 확인을 누르면 아래와 같은 시험창이 뜬다.

(1과목 5문제, 2과목 5문제, 3과목 10문제로 설정)

오른쪽의 < , > 버튼으로 과목을 바꿔가며 답을 입력해준다.

 

시간이 다 되거나 제출하기를 클릭하고 답안 파일을 선택하면 아래와 같은 결과창이 뜬다.

마찬가지로 오른쪽의 < , > 버튼으로 과목을 변경할 수 있다.

 

결과 저장을 누르고 저장할 파일의 이름을 입력해주면

이같은 텍스트 파일을 생성한다.

 

 

전체 코드

더보기
from tkinter import *
import tkinter.font as font
import os
import tkinter.messagebox as msgbox
import time
from tkinter import filedialog

root = Tk()
root.title("채점 프로그램")
root.geometry("200x280")
root.resizable(False,False)
root.focus_set()

frame_button = Frame(root)
frame_button.pack(fill='both', expand=True)

# 연습문제
def practice():
    root_practice = Tk()
    root_practice.title("연습문제")
    root_practice.focus_force()
    root_practice.resizable(False, False)

    frame_practice = Frame(root_practice)
    frame_practice.pack(fill='both', expand=True)


    # 연습문제 정보 입력 (문항, 시간)
    label_prac_num = Label(frame_practice, text='문항 수', font=font.Font(size=12))
    label_prac_num.grid(row=0, column=0, padx=5, pady=5, sticky=N+E+W+S)
    entry_prac_num = Entry(frame_practice, font=font.Font(size=12))
    entry_prac_num.grid(row=0, column=1, columnspan=5, padx=5, pady=5, sticky=N+E+W+S)

    label_prac_time = Label(frame_practice, text='시간(시:분:초)', font=font.Font(size=12))
    label_prac_time.grid(row=1, column=0, padx=3, pady=3, sticky=N+E+W+S)
    
    entry_prac_time_h = Entry(frame_practice, font=font.Font(size=12), width=2)
    entry_prac_time_h.grid(row=1, column=1, padx=3, pady=3, sticky=N+E+W+S)

    label_prac_time_c1 = Label(frame_practice, text=':', font=font.Font(size=12))
    label_prac_time_c1.grid(row=1, column=2, sticky=N+E+W+S)
    
    entry_prac_time_m = Entry(frame_practice, font=font.Font(size=12), width=2)
    entry_prac_time_m.grid(row=1, column=3, padx=1, pady=3, sticky=N+E+W+S)
    
    label_prac_time_c2 = Label(frame_practice, text=':', font=font.Font(size=12))
    label_prac_time_c2.grid(row=1, column=4, sticky=N+E+W+S)
    
    entry_prac_time_s = Entry(frame_practice, font=font.Font(size=12), width=2)
    entry_prac_time_s.grid(row=1, column=5, padx=3, pady=3, sticky=N+E+W+S)

    label_prac_time_c = Label(frame_practice,
                              text='문항수는 최대 200개입니다.'
                              +'\n시간을 0으로 설정하면 시간제한 없이 진행합니다.')
    label_prac_time_c.grid(row=2, column=0, columnspan=6, padx=5, pady=5, sticky=N+E+W+S)

    frame_practice2 = Frame(root_practice)
    frame_practice2.pack(fill='both', expand=True)

    # 정보 입력 완료
    def prac_ok():
        global now_str, now, isgrading
        isgrading = False
        prac_num = entry_prac_num.get()
        prac_time_h = entry_prac_time_h.get()
        prac_time_m = entry_prac_time_m.get()
        prac_time_s = entry_prac_time_s.get()
        try :
            prac_num = int(prac_num)
            prac_time_h = int(prac_time_h)
            prac_time_m = int(prac_time_m)
            prac_time_s = int(prac_time_s)
        except :
            msgbox.showerror("오류", "알맞은 숫자를 입력해 주세요")
            root_practice.focus_force()
            return

        if prac_num <= 0 or prac_num > 200 or prac_time_h < 0 or prac_time_m > 60 or prac_time_m < 0 or prac_time_s > 60 or prac_time_s < 0:
            msgbox.showerror("오류", "알맞은 숫자를 입력해 주세요")
            root_practice.focus_force()
            return

        root_practice.destroy()
        
        # 시험 시작
        root_practice_start = Tk()
        root_practice_start.geometry("1100x450")
        root_practice_start.title("연습문제")
        root_practice_start.resizable(False, False)
        root_practice_start.focus_force()
        frame_prac_sl = Frame(root_practice_start)
        frame_prac_sl.pack(side='left', fill='both', expand=True)

        def prac_closing():
            res_prac_close = msgbox.askokcancel("경고", "정말 시험을 종료하시겠습니까?")
            if res_prac_close :
                root_practice_start.destroy()
            else :
                root_practice_start.focus_force()
            
        root_practice_start.protocol("WM_DELETE_WINDOW", prac_closing)

        label_prac_list = []
        entry_prac_list = []
        for i in range(20):
            label_prac_tmp = Label(frame_prac_sl, font=font.Font(size=12), text='{:03d}~{:03d}'.format(i*10+1, (i+1)*10))
            entry_prac_tmp = Entry(frame_prac_sl, font=font.Font(size=12))
            label_prac_list.append(label_prac_tmp)
            entry_prac_list.append(entry_prac_tmp)

        for i in range((prac_num-1)//10+1):
            label_prac_list[i].grid(row=(i%10)+1, column=0+(i//10)*2, padx=5, pady=5, sticky=N+E+W+S)
            entry_prac_list[i].grid(row=(i%10)+1, column=1+(i//10)*2, padx=5, pady=5, sticky=N+E+W+S)
            if i == (prac_num-1)//10 and (prac_num % 10 != 0):
                label_prac_list[i].configure(text='{:03d}~{:03d}'.format(i*10+1, i*10+(prac_num)%10))


        time_limit = time.time() + prac_time_h * 3600 + prac_time_m * 60 + prac_time_s
        now = time_limit - time.time() + 1

        def time_to_str(time):
            h = int(now // 3600)
            r = now - h * 3600
            m = int(r // 60)
            s = int(r - m * 60)
            return '{:02d}:{:02d}:{:02d}'.format(h,m,s)

        now_str = time_to_str(now)

        if prac_time_h == 0 and prac_time_m == 0 and prac_time_s == 0 :
            now_str = '시간 제한 없음'

        frame_prac_sr = Frame(root_practice_start)
        frame_prac_sr.pack(side='right', fill='both', expand=True)

        label_remain_text = Label(frame_prac_sr, text='남은 시간', font=font.Font(size=12))
        label_remain_text.pack(fill='both')

        label_remain_time = Label(frame_prac_sr, text=now_str, font=font.Font(size=20))
        label_remain_time.pack(fill='both')

        def update_timer():
            global now_str, now, prac_file, isgrading
            if isgrading :
                return
            if now_str != '시간 제한 없음' :
                now = time_limit - time.time() + 1
                now_str = time_to_str(now)
                if now <= 1 :
                    now_str = '시간 종료'
                    label_remain_time.configure(text=now_str, font=font.Font(size=15))
                    prac_file = False
                    while not prac_file :
                        prac_grading()
                    return
                label_remain_time.configure(text=now_str, font=font.Font(size=15))
                root_practice_start.update()
                root_practice_start.after(1000, update_timer)
            else :
                return

        # 채점
        def prac_grading():
            global prac_file
            aslist = []
            for i in range(20):
                aslist.append(entry_prac_list[i].get())
                entry_prac_list[i].configure(state='disabled')

            prac_file = filedialog.askopenfilename(title='정답 파일을 선택하세요', 
                    filetypes=(("텍스트 파일", "*.txt"), ("모든 파일", "*.*")),
                    initialdir=os.path.abspath("."))

            if prac_file :
                root_practice_start.destroy()
                root_practice_grade = Tk()
                root_practice_grade.title("결과")
                root_practice_grade.focus_force()
                root_practice_grade.geometry('+0+5')
                calist = []
                with open(prac_file, 'r', encoding='utf8') as f:
                    for line in f:
                        calist.append(line.rstrip())
                        
                nca = 0
                nq = 0
                d_total = []
                for i in range((prac_num-1)//10+1):
                    tmpframe = Frame(root_practice_grade, relief = 'solid', bd=1)
                    tmpframe.grid(row=(i%10), column=(i//10)*2, sticky=N+E+W+S)
                    Label(tmpframe, text='', font=font.Font(size=15)).pack()
                    if i == (prac_num-1)//10 and (prac_num % 10 != 0):
                        Label(tmpframe, text='{:03d}~{:03d}'.format(i*10+1,  i*10+(prac_num)%10), font=font.Font(size=15)).pack()
                    else :
                        Label(tmpframe, text='{:03d}~{:03d}'.format(i*10+1, (i+1)*10), font=font.Font(size=15)).pack()
                    Label(tmpframe, text='', font=font.Font(size=15)).pack()
                    
                for i in range((prac_num-1)//10+1):
                    if len(calist) <= i :
                        tmpframe2 = Frame(root_practice_grade, relief='solid', bd=1)
                        tmpframe2.grid(row=(i%10), column=(i//10)*2+1, sticky=N+E+W+S)
                        Label(tmpframe2, text='                        ', font=font.Font(size=15)).pack(fill='both', expand=True)
                        Label(tmpframe2, text='', font=font.Font(size=15)).pack(fill='both', expand=True)
                        Label(tmpframe2, text='', font=font.Font(size=8)).pack(fill='both', expand=True)
                    else :
                        d = ''
                        for j in range(len(calist[i])):
                            if j >= len(aslist[i]) :
                                d += 'X'
                                nq += 1
                            elif aslist[i][j] == calist[i][j] :
                                d += 'O'
                                nca += 1
                                nq += 1
                            else :
                                d += 'X'
                                nq += 1
                        d_total.append(d)
                        tmpframe2 = Frame(root_practice_grade, relief='solid', bd=1)
                        tmpframe2.grid(row=(i%10), column=(i//10)*2+1, sticky=N+E+W+S)
                        Label(tmpframe2, text=aslist[i], font=font.Font(size=15)).pack(fill='both', expand=True)
                        Label(tmpframe2, text=calist[i], font=font.Font(size=15)).pack(fill='both', expand=True)
                        Label(tmpframe2, text=d, font=font.Font(size=8)).pack(fill='both', expand=True)

                frame_tmp = Frame(root_practice_grade)
                frame_tmp.grid(row=9, column=4, sticky=N+E+W+S)
                Label(frame_tmp, text='          ').pack()

                # 결과 저장
                def prac_save():
                    f = filedialog.asksaveasfile(filetypes=[("텍스트 파일", "*.txt")])
                    if f is None:
                        return
                    f.write('* 제출한 답안 / 정답 / 정오(O/X) 순입니다.\n\n')
                    for i in range(len(d_total)):
                        f.write(aslist[i])
                        f.write('\n')
                        f.write(calist[i])
                        f.write('\n')
                        f.write(d_total[i])
                        f.write('\n')
                    f.write('맞은 개수 : '+str(nca)+'/'+str(nq)+', 정답률 : {:.2f}%'.format(nca/nq*100))
                    f.close()
                frame_practice_save = Frame(root_practice_grade)
                frame_practice_save.grid(row=8, column=5, sticky=N+E+W+S)
                Button(frame_practice_save, text='\n결과 저장\n', font=font.Font(size=10), command=prac_save).pack()

                frame_grade = Frame(root_practice_grade, relief='solid', bd=1)
                frame_grade.grid(row=9, column=5, sticky=N+E+W+S)
                Label(frame_grade, text='맞은 개수\n'+str(nca)+'/'+str(nq)+'\n{:.2f}%'.format(nca/nq*100),
                      font=font.Font(size=10)).pack(fill='both', expand=True)

                frame_prac_description = Frame(root_practice_grade, relief='solid', bd=1)
                frame_prac_description.grid(row=0, column=5, sticky=N+E+W+S)
                Label(frame_prac_description, text='제출한 답안', font=font.Font(size=15)).pack()
                Label(frame_prac_description, text='정답', font=font.Font(size=15)).pack()
                Label(frame_prac_description, text='정오(O/X)', font=font.Font(size=15)).pack()
                
                        
        # 답안 제출
        def prac_submit():
            global isgrading
            response = msgbox.askyesno("답안 제출", "답안을 제출하시겠습니까?\n예를 누르면 답안 수정이 불가능합니다.")
            if response :
                isgrading = True
                prac_grading()
            else :
                root_practice_start.focus_force()

                

        button_submit = Button(frame_prac_sr, text = '\n제출하기\n',font=font.Font(size=12), command=prac_submit)
        button_submit.pack(side='bottom', fill='x')
        update_timer()
        root_practice_start.mainloop()

    def prac_cancel():
        root_practice.destroy()

    button_prac_ok = Button(frame_practice2, text='확인', command=prac_ok)
    button_prac_ok.pack(side='left', fill='both', expand=True, padx=5, pady=5)
    button_prac_cancel = Button(frame_practice2, text='취소', command=prac_cancel)
    button_prac_cancel.pack(side='right', fill='both', expand=True, padx=5, pady=5)

    root_practice.mainloop()


# 모의고사
def test():
    global entry_test_list, isgrading
    isgrading = False
    sub_num = entry_num_subject.get()
    each_percent = entry_each.get()
    total_percent = entry_total.get()
    try :
        sub_num = int(sub_num)
        each_percent = int(each_percent)
        total_percent = int(total_percent)
    except :
        msgbox.showerror("오류", "알맞은 숫자를 입력해 주세요")
        root.focus_force()
        return

    if sub_num <= 0 or sub_num > 10 or each_percent < 0 or each_percent > 100 or total_percent < 0 or total_percent > 100 :
        msgbox.showerror("오류", "알맞은 숫자를 입력해 주세요")
        root.focus_force()
        return
    

    
    root_test = Tk()
    root_test.title("모의고사")
    root_test.focus_force()
    root_test.resizable(False, False)

    frame_test = Frame(root_test)
    frame_test.pack(fill='both', expand=True)

    label_test_list = []
    entry_test_list = []

    for i in range(sub_num):
        label_test_tmp = Label(frame_test, text='제{}과목 문항 수'.format(i+1), font=font.Font(size=12))
        label_test_tmp.grid(row=i, column=0, padx=5, pady=5, sticky=N+E+W+S)
        label_test_list.append(label_test_tmp)

        entry_test_tmp = Entry(frame_test, font=font.Font(size=12))
        entry_test_tmp.grid(row=i, column=1, columnspan=5, padx=5, pady=5, sticky=N+E+W+S)
        entry_test_list.append(entry_test_tmp)

    label_test_time = Label(frame_test, text='시간(시:분:초)', font=font.Font(size=12))
    label_test_time.grid(row=i+2, column=0, padx=3, pady=3, sticky=N+E+W+S)
    
    entry_test_time_h = Entry(frame_test, font=font.Font(size=12), width=2)
    entry_test_time_h.grid(row=i+2, column=1, padx=3, pady=3, sticky=N+E+W+S)

    label_test_time_c1 = Label(frame_test, text=':', font=font.Font(size=12))
    label_test_time_c1.grid(row=i+2, column=2, sticky=N+E+W+S)
    
    entry_test_time_m = Entry(frame_test, font=font.Font(size=12), width=2)
    entry_test_time_m.grid(row=i+2, column=3, padx=1, pady=3, sticky=N+E+W+S)
    
    label_test_time_c2 = Label(frame_test, text=':', font=font.Font(size=12))
    label_test_time_c2.grid(row=i+2, column=4, sticky=N+E+W+S)
    
    entry_test_time_s = Entry(frame_test, font=font.Font(size=12), width=2)
    entry_test_time_s.grid(row=i+2, column=5, padx=3, pady=3, sticky=N+E+W+S)

    label_test_time_c = Label(frame_test,
                              text='문항수는 과목 당 최대 200개입니다.'
                              +'\n시간을 0으로 설정하면 시간제한 없이 진행합니다.')
    label_test_time_c.grid(row=i+1, column=0, columnspan=6, padx=5, pady=5, sticky=N+E+W+S)

    frame_test2 = Frame(root_test)
    frame_test2.pack(fill='both', expand=True)

    def test_ok():
        global now_str, now, entry_test_list, numofsubject, numofsubject2
        test_num_list = []
        for x in range(sub_num):
            test_num_list.append(entry_test_list[x].get())
        
        test_time_h = entry_test_time_h.get()
        test_time_m = entry_test_time_m.get()
        test_time_s = entry_test_time_s.get()
        try :
            for x in range(sub_num) :
                test_num_list[x] = int(test_num_list[x])
            test_time_h = int(test_time_h)
            test_time_m = int(test_time_m)
            test_time_s = int(test_time_s)
        except :
            msgbox.showerror("오류", "알맞은 숫자를 입력해 주세요")
            root_test.focus_force()
            return

        if min(test_num_list) <= 0 or max(test_num_list) > 200 or test_time_h < 0 or test_time_m > 60 or test_time_m < 0 or test_time_s > 60 or test_time_s < 0:
            msgbox.showerror("오류", "알맞은 숫자를 입력해 주세요")
            root_test.focus_force()
            return

        root_test.destroy()
        
        # 시험 시작
        root_test_start = Tk()
        root_test_start.geometry("1000x450")
        root_test_start.title("모의고사")
        root_test_start.resizable(False, False)
        root_test_start.focus_force()

        def test_closing():
            res_test_close = msgbox.askokcancel("경고", "정말 시험을 종료하시겠습니까?")
            if res_test_close :
                root_test_start.destroy()
            else :
                root_test_start.focus_force()
            
        root_test_start.protocol("WM_DELETE_WINDOW", test_closing)

        frame_test_left_list = []
        label_test_list_list = []
        entry_test_list_list = []
        for i in range(sub_num):
            frame_test_sl = Frame(root_test_start)
            frame_test_left_list.append(frame_test_sl)

            label_test_list = []
            entry_test_list = []
            for j in range((test_num_list[i]-1)//10+1):
                if i == 0 :
                    label_test_tmp = Label(frame_test_sl, font=font.Font(size=12), text='{:03d}~{:03d}'.format(j*10+1, (j+1)*10))
                else :
                    label_test_tmp = Label(frame_test_sl, font=font.Font(size=12), text='{:03d}~{:03d}'.format(j*10+1+sum(test_num_list[:i]), (j+1)*10+sum(test_num_list[:i])))
                entry_test_tmp = Entry(frame_test_sl, font=font.Font(size=12))
                label_test_list.append(label_test_tmp)
                entry_test_list.append(entry_test_tmp)

            for j in range((test_num_list[i]-1)//10+1):
                label_test_list[j].grid(row=(j%10)+1, column=0+(j//10)*2, padx=5, pady=5, sticky=N+E+W+S)
                entry_test_list[j].grid(row=(j%10)+1, column=1+(j//10)*2, padx=5, pady=5, sticky=N+E+W+S)
                if j == (test_num_list[i]-1)//10 and (test_num_list[i] % 10 != 0):
                    label_test_list[j].configure(text='{:03d}~{:03d}'.format(j*10+1+sum(test_num_list[:i]), j*10+(test_num_list[i])%10+sum(test_num_list[:i])))

            label_test_list_list.append(label_test_list)
            entry_test_list_list.append(entry_test_list)
            
        frame_test_left_list[0].pack(side='left', fill='both', expand=True)


        time_limit = time.time() + test_time_h * 3600 + test_time_m * 60 + test_time_s
        now = time_limit - time.time() + 1

        def time_to_str(time):
            h = int(now // 3600)
            r = now - h * 3600
            m = int(r // 60)
            s = int(r - m * 60)
            return '{:02d}:{:02d}:{:02d}'.format(h,m,s)

        now_str = time_to_str(now)

        if test_time_h == 0 and test_time_m == 0 and test_time_s == 0 :
            now_str = '시간 제한 없음'

        frame_test_sr = Frame(root_test_start)
        frame_test_sr.pack(side='right', fill='both')

        label_remain_text = Label(frame_test_sr, text='남은 시간', font=font.Font(size=12))
        label_remain_text.pack(fill='both')

        label_remain_time = Label(frame_test_sr, text=now_str, font=font.Font(size=20))
        label_remain_time.pack(fill='both')

        numofsubject = 1

        label_subject_name = Label(frame_test_sr, text='\n제{}과목\n'.format(numofsubject), font=font.Font(size=12))
        label_subject_name.pack(fill='both')

        def left_button():
            global numofsubject
            numofsubject -= 1
            if numofsubject == 1 :
                button_left.configure(state='disabled')
            if numofsubject == sub_num-1 :
                button_right.configure(state='normal')
            frame_test_left_list[numofsubject].pack_forget()
            frame_test_left_list[numofsubject-1].pack(side='left', fill='both', expand=True)
            label_subject_name.configure(text='\n제{}과목\n'.format(numofsubject))

        def right_button():
            global numofsubject
            numofsubject += 1
            if numofsubject == sub_num :
                button_right.configure(state='disabled')
            if numofsubject == 2 :
                button_left.configure(state='normal')
            frame_test_left_list[numofsubject-2].pack_forget()
            frame_test_left_list[numofsubject-1].pack(side='left', fill='both', expand=True)
            label_subject_name.configure(text='\n제{}과목\n'.format(numofsubject))

        button_left = Button(frame_test_sr, text='<', font=font.Font(size=15), command=left_button)
        button_right = Button(frame_test_sr, text='>', font=font.Font(size=15), command=right_button)
        button_left.pack(side='left')
        button_right.pack(side='right')
        button_left.configure(state='disabled')
        if sub_num == 1 :
            button_right.configure(state='disabled')

        def update_timer():
            global now_str, now, file, isgrading
            if isgrading :
                return
            if now_str != '시간 제한 없음' :
                now = time_limit - time.time() + 1
                now_str = time_to_str(now)
                if now <= 1 :
                    now_str = '시간 종료'
                    label_remain_time.configure(text=now_str, font=font.Font(size=15))
                    file = False
                    while not file :
                        grading()
                    return
                label_remain_time.configure(text=now_str, font=font.Font(size=15))
                root_test_start.update()
                root_test_start.after(1000, update_timer)
            else :
                return
            
        def grading():
            global file, numofsubject2
            aslist = []
            for i in range(sub_num):
                aslist_tmp = []
                for j in range((test_num_list[i]-1)//10+1):
                    aslist_tmp.append(entry_test_list_list[i][j].get())
                    entry_test_list_list[i][j].configure(state='disabled')
                aslist.append(aslist_tmp)

            file = filedialog.askopenfilename(title='정답 파일을 선택하세요', 
                    filetypes=(("텍스트 파일", "*.txt"), ("모든 파일", "*.*")),
                    initialdir=os.path.abspath("."))

            if file :
                root_test_start.destroy()
                root_test_grade = Tk()
                root_test_grade.title("시험 결과")
                root_test_grade.geometry("825x925+0+5")
                root_test_grade.resizable(False,False)
                root_test_grade.focus_force()
                calist = []
                ca = ''
                with open(file, 'r', encoding='utf8') as f:
                    for line in f:
                        ca += line.rstrip()

                for i in range(sub_num):
                    ca_tmp_list = []
                    if i == 0 :
                        ca_tmp = ca[:test_num_list[i]]
                    else :
                        ca_tmp = ca[sum(test_num_list[:i]):sum(test_num_list[:i+1])]

                    while len(ca_tmp) > 10 :
                        ca_tmp_list.append(ca_tmp[:10])
                        ca_tmp = ca_tmp[10:]

                    ca_tmp_list.append(ca_tmp)
                    calist.append(ca_tmp_list)
                        
                nca_list = []
                d_total_list = []
                frame_result_list = []
                for i in range(sub_num):
                    frame_result = Frame(root_test_grade)
                    frame_result_list.append(frame_result)
                    for j in range((test_num_list[i]-1)//10+1):
                        tmpframe = Frame(frame_result, relief = 'solid', bd=1)
                        tmpframe.grid(row=(j%10), column=(j//10)*2, sticky=N+E+W+S)
                        Label(tmpframe, text='', font=font.Font(size=15)).pack()
                        if i == 0 and j == (test_num_list[i]-1)//10 and (test_num_list[i] % 10 != 0):
                            Label(tmpframe, text='{:03d}~{:03d}'.format(j*10+1, j*10+(test_num_list[i])%10), font=font.Font(size=15)).pack()
                        elif i == 0 :
                            Label(tmpframe, text='{:03d}~{:03d}'.format(j*10+1, (j+1)*10), font=font.Font(size=15)).pack()
                        elif j == (test_num_list[i]-1)//10 and (test_num_list[i] % 10 != 0):
                            Label(tmpframe, text='{:03d}~{:03d}'.format(j*10+1+sum(test_num_list[:i]),  j*10+(test_num_list[i])%10+sum(test_num_list[:i])), font=font.Font(size=15)).pack()
                        else :
                            Label(tmpframe, text='{:03d}~{:03d}'.format(j*10+1+sum(test_num_list[:i]), (j+1)*10+sum(test_num_list[:i])), font=font.Font(size=15)).pack()
                        Label(tmpframe, text='', font=font.Font(size=15)).pack()

                    nca = 0
                    d_total = []
                    for j in range((test_num_list[i]-1)//10+1):
                        if len(calist[i]) <= j :
                            tmpframe2 = Frame(frame_result, relief='solid', bd=1)
                            tmpframe2.grid(row=(j%10), column=(j//10)*2+1, sticky=N+E+W+S)
                            Label(tmpframe2, text='                        ', font=font.Font(size=15)).pack(fill='both', expand=True)
                            Label(tmpframe2, text='', font=font.Font(size=15)).pack(fill='both', expand=True)
                            Label(tmpframe2, text='', font=font.Font(size=15)).pack(fill='both', expand=True)
                        else :
                            d = ''
                            for k in range(len(calist[i][j])):
                                if k >= len(aslist[i][j]) :
                                    d += 'X'
                                elif aslist[i][j][k] == calist[i][j][k] :
                                    d += 'O'
                                    nca += 1
                                else :
                                    d += 'X'
                            d_total.append(d)
                            tmpframe2 = Frame(frame_result, relief='solid', bd=1)
                            tmpframe2.grid(row=(j%10), column=(j//10)*2+1, sticky=N+E+W+S)
                            Label(tmpframe2, text=aslist[i][j], font=font.Font(size=15)).pack(fill='both', expand=True)
                            Label(tmpframe2, text=calist[i][j], font=font.Font(size=15)).pack(fill='both', expand=True)
                            Label(tmpframe2, text=d, font=font.Font(size=15)).pack(fill='both', expand=True)
                            
                    nca_list.append(nca)
                    d_total_list.append(d_total)

            
                result_str = '합격'
                nca_total = sum(nca_list)
                qn = sum(test_num_list)
                for i in range(sub_num):
                    if ((nca_list[i] / test_num_list[i]) * 100 < each_percent)  :
                        result_str = '불합격\n(제{}과목 과락)'.format(i+1)
                        break
                if (nca_total / qn * 100 < total_percent) :
                    result_str = '불합격\n(종합 점수 부족)'
                            
                    

                frame_result_list[0].pack(side='left', fill='both', expand=True)

                frame_result_right = Frame(root_test_grade)
                frame_result_right.pack(side='right', fill='both')

                
                label_result = Label(frame_result_right, text=result_str, font=font.Font(size=20), relief='solid', bd=1)
                label_result.pack(side='bottom', fill='x', padx=10, pady=10)
                if result_str != '합격' :
                    label_result.configure(fg='red')
                else :
                    label_result.configure(fg='blue')

                label_total_result = Label(frame_result_right, text='전체\n맞은 개수\n{}/{}\n정답률\n{:.2f}%'.format(nca_total, qn, nca_total/qn*100), font=font.Font(size=15), relief='solid', bd=1)
                label_total_result.pack(side='bottom', fill='x', padx=10, pady=10)

                numofsubject2 = 1

                label_subject_result = Label(frame_result_right, text='제{}과목\n맞은 개수\n{}/{}\n정답률\n{:.2f}%'.format(numofsubject2, nca_list[0], test_num_list[0], nca_list[0]/test_num_list[0]*100),
                                             font=font.Font(size=15), relief='solid', bd=1)
                label_subject_result.pack(side='bottom', fill='x', padx=10, pady=10)

                def lb():
                    global numofsubject2
                    numofsubject2 -= 1
                    if numofsubject2 == 1 :
                        bl.configure(state='disabled')
                    if numofsubject2 == sub_num-1 :
                        br.configure(state='normal')
                    frame_result_list[numofsubject2].pack_forget()
                    frame_result_list[numofsubject2-1].pack(side='left', fill='both', expand=True)
                    label_subject_result.configure(text='제{}과목\n맞은 개수\n{}/{}\n정답률\n{:.2f}%'.format(numofsubject2, nca_list[numofsubject2-1], test_num_list[numofsubject2-1], nca_list[numofsubject2-1]/test_num_list[numofsubject2-1]*100))
                        
                def rb():
                    global numofsubject2
                    numofsubject2 += 1
                    if numofsubject2 == sub_num :
                        br.configure(state='disabled')
                    if numofsubject2 == 2 :
                        bl.configure(state='normal')
                    frame_result_list[numofsubject2-2].pack_forget()
                    frame_result_list[numofsubject2-1].pack(side='left', fill='both', expand=True)
                    label_subject_result.configure(text='제{}과목\n맞은 개수\n{}/{}\n정답률\n{:.2f}%'.format(numofsubject2, nca_list[numofsubject2-1], test_num_list[numofsubject2-1], nca_list[numofsubject2-1]/test_num_list[numofsubject2-1]*100))

                bl = Button(frame_result_right, text='<', font=font.Font(size=15), command=lb)
                br = Button(frame_result_right, text='>', font=font.Font(size=15), command=rb)
                bl.pack(side='left')
                br.pack(side='right')
                bl.configure(state='disabled')
                if sub_num == 1 :
                    br.configure(state='disabled')

                frame_description = Frame(frame_result_right, relief='solid', bd=1)
                frame_description.pack(side='top', fill='x')

                Label(frame_description, text='  제출한 답안  ', font=font.Font(size=15)).pack(fill='both', expand=True)
                Label(frame_description, text='정답', font=font.Font(size=15)).pack(fill='both', expand=True)
                Label(frame_description, text='정오(O/X)', font=font.Font(size=15)).pack(fill='both', expand=True)

                def save():
                    f = filedialog.asksaveasfile(filetypes=[("텍스트 파일", "*.txt")], defaultextension="*.txt")
                    if f is None:
                        return
                    
                    f.write('* 제출한 답안 / 정답 / 정오(O/X) 순입니다.\n\n')
                    for i in range(sub_num):
                        f.write('제{}과목\n'.format(i+1))
                        for j in range(len(d_total_list[i])) :
                            f.write(aslist[i][j])
                            f.write('\n')
                            f.write(calist[i][j])
                            f.write('\n')
                            f.write(d_total_list[i][j])
                            f.write('\n')
                        f.write('맞은 개수 : {}/{}, 정답률 : {:.2f}%\n\n'.format(nca_list[i], test_num_list[i], nca_list[i]/test_num_list[i]*100))
                    f.write('전체 맞은 개수 : {}/{}, 정답률 : {:.2f}%\n'.format(nca_total, qn, nca_total/qn*100))
                    f.write(result_str)
                    f.close()
                Button(frame_result_right, text='\n결과 저장\n', font=font.Font(size=10), command=save).pack(side='bottom', fill='x')
                
                
        def submit():
            global isgrading
            response = msgbox.askyesno("답안 제출", "답안을 제출하시겠습니까?\n예를 누르면 답안 수정이 불가능합니다.")
            if response :
                isgrading = True
                grading()
            else :
                root_test_start.focus_force()

                

        button_submit = Button(frame_test_sr, text = '\n제출하기\n',font=font.Font(size=12), command=submit)
        button_submit.pack(side='bottom', fill='x')
        update_timer()
        root_test_start.mainloop()

    def test_cancel():
        root_test.destroy()

    button_test_ok = Button(frame_test2, text='확인', command=test_ok)
    button_test_ok.pack(side='left', fill='both', expand=True, padx=5, pady=5)
    button_test_cancel = Button(frame_test2, text='취소', command=test_cancel)
    button_test_cancel.pack(side='right', fill='both', expand=True, padx=5, pady=5)

    root_test.mainloop()

button_practice = Button(frame_button, text='\n연습문제\n', command=practice, relief='groove', font=font.Font(size=12))
button_test = Button(frame_button, text='\n모의고사\n', command=test, relief='groove', font=font.Font(size=12))

button_practice.pack(fill='both', expand=True, padx=10, pady=10)
button_test.pack(fill='both', expand=True, padx=10, pady=5)

frame_option = LabelFrame(root, text='모의고사 옵션')
frame_option.pack(fill='both', expand=True, padx=10, pady=5)

Label(frame_option, text = '').grid(row=0, column=0)

label_num_subject = Label(frame_option, text='과목 수', font=font.Font(size=11))
label_num_subject.grid(row=0, column=1, sticky=N+E+W+S)

entry_num_subject = Entry(frame_option, width=3, font=font.Font(size=11))
entry_num_subject.grid(row=0, column=2, sticky=N+E+W+S)

label_caut_subject = Label(frame_option, text='※ 최대 10과목까지 설정 가능')
label_caut_subject.grid(row=1, column=1, columnspan=4, sticky=N+E+W+S)

label_each = Label(frame_option, text='과목별 정답률컷', font=font.Font(size=11))
label_each.grid(row=2, column=1, sticky=N+E+W+S)

entry_each = Entry(frame_option, width=3, font=font.Font(size=11))
entry_each.grid(row=2, column=2, sticky=N+E+W+S)

label_each_2 = Label(frame_option, text='%', font=font.Font(size=11))
label_each_2.grid(row=2, column=3, sticky=N+E+W+S)

label_total = Label(frame_option, text='전체 정답률컷', font=font.Font(size=11))
label_total.grid(row=3, column=1, sticky=N+E+W+S)

entry_total = Entry(frame_option, width=3, font=font.Font(size=11))
entry_total.grid(row=3, column=2, sticky=N+E+W+S)

label_total_2 = Label(frame_option, text='%', font=font.Font(size=11))
label_total_2.grid(row=3, column=3, sticky=N+E+W+S)

root.mainloop()
728x90
반응형