tkinterで業務効率化Python GUIアプリを作った

概要

最近はKaplan Schweserというe-learningプラットフォームを使い、CFAの勉強をしている。

Kaplanの練習問題はCFAの本番試験と同じ3択式であるが、間違えた問題だけを解く機能がなかったり、外出先で手軽に問題を解こうと思ってもログインが必要だったりで何かと不便。

そこで、間違えた問題・まぐれで正解した問題をQuizletという暗記カード作成Webサイトに登録し、出先や、自宅で効率的に勉強をしている。

問題をそのままコピーすると以下のようになるが

Ashok Jain is assessing the [...] Lutina's currency would:

A)

excessively appreciate in the long-term.

Incorrect Answer

B)

excessively depreciate in the long-term.

Incorrect Answer

C)

excessively appreciate in the short-term.

Correct Answer

Explanation

Dornbusch overshooting model. This model assumes that prices are sticky (inflexible) in the short term and, hence, do not immediately reflect changes in monetary policy.

これを毎回手作業で以下のように問題文ブロックと答え&解説ブロックの2つに分ける必要があった

問題文ブロック

Ashok Jain is assessing the [...] Lutina's currency would:

A) excessively appreciate in the long-term.

B) excessively depreciate in the long-term.

C) excessively appreciate in the short-term.

答え&解説ブロック

C

Dornbusch overshooting model. This model assumes that prices are sticky (inflexible) in the short term and, hence, do not immediately reflect changes in monetary policy.

ただ、この分ける作業が面倒くさかったので、tkinterを使い以下のことをするアプリを作成した。

  1. クリップボードの内容を読み取り
  2. 読み取った内容を処理して、問題文ブロックをクリップボードに保存
  3. 次のボタンを押すと、答え&解説ブロックをクリップボードに保存

使用デモ

コード

import re
import pyperclip
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.scrolledtext import ScrolledText

class Application(ttk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.master.title("Title")
        # self.master.geometry("300x400")
        self.create_widgets()

    def create_widgets(self):
        self.btn1 = tk.Button(self.master, 
                                   text='① Load Text and Copy Question',
                                   command=self.process_text(),
                                   height=2)
        self.btn1.pack(fill = 'x')
        
        self.text1 = ScrolledText(root,
                                  font=("Arial", 9), 
                                  height=10,
                                  width=40)
        self.text1.pack(fill = 'x')
        
        self.btn2 = tk.Button(root,
                                   text='② Copy Answer & Explanation',
                                   height=2, command=self.copy_ans())
        self.btn2.pack(fill = 'x')
        
        self.text2 = ScrolledText(root, font=("Arial", 9), height=15, width=40)
        self.text2.pack(fill = 'x')

    def process_text(self):
        def inner():
            try:
                self.text1.delete("1.0","end")
                self.text2.delete("1.0","end")
                t = pyperclip.paste()

                # find the answer
                splitted = re.split('A\)\r\n|B\)|C\)', t)
                if 'Correct Answer' in splitted[1]:
                    self.correct_ans = 'A'
                elif 'Correct Answer' in splitted[2]:
                    self.correct_ans = 'B'
                elif 'Correct Answer' in splitted[3]:
                    self.correct_ans = 'C'
                else:
                    raise Exception("Can't find the correct answer choice")
                out = t.replace('Incorrect Answer\r\n', '')
                out = out.replace('Correct Answer\r\n', '')
                for alph in ('A', 'B', 'C'):
                    out = out.replace(alph+')\r\n', alph+') ')
                out = re.sub(' \(Module .*\)', '', out)
                self.mondai_txt, self.ans_txt = out.split('\r\nExplanation\r\n')
                self.ans_txt = self.correct_ans + '\n\n' + self.ans_txt
                # print(self.mondai_txt, self.ans_txt)
                self.text1.insert('1.0', self.mondai_txt)
                self.text2.insert('1.0', self.ans_txt)
                pyperclip.copy(self.mondai_txt)
            except Exception:
                self.text1.insert('1.0', Exception)
        return inner
    
    def copy_ans(self):
        def inner():
            pyperclip.copy(self.ans_txt)
        return inner

if __name__ == '__main__':
    root = tk.Tk()
    app = Application(master=root)
    app.mainloop()

これをワンクリックで走らせるために、以下のbatファイルも作成している

D:\projects\venvd\Scripts\activate.bat && python D:\projects\tools\kaplan2quizlet.py