Pythonで研究に役立つツールを自作したい。そんな思いから、何か簡単なアプリを作って見ようということで、電卓の作成練習を通してツールの作成方法を学んだことをアウトプットします。
参考ページ丸写しでは勉強にならないため、自分で+αの機能の搭載を試みて、改良を行いました。
電卓の作成練習をする目的
研究のデータ解析などで、やはり「目的に合わせた自作の補助ツールが欲しい」と思うので最終的にはそれを作るスキルを身に着けるということが最終目標です。
それに当たって、まずツールといえば、アプリを立ち上げて画面が出てきて、ボタンをクリックしたり、何か入力したり、読み込んだりというものをイメージしますね。
この形を作ってみたいということで、電卓アプリの作成練習を行いました。
今回の学習で学べる要素としては次の通りだと思います。
- ツールのウィンドウのレイアウト設定
- ボタンの配置
- ウィンドウのサイズ変更に合わせてボタンのサイズが変わる
- ボタンをクリックして応答
- 計算する
参考にさせていただいたページ
今回の学習は下記のページを参考にさせていただきました。
Tkinterで簡易電卓を作るシリーズ、Narito Blogさん
このページは、Tkinterを用いた電卓の作成を手取り足取りとても詳しく解説されていて、非常にわかりやすく学習させてもらうことができました。
興味のある方は、ぜひ参考にさせていただいてはいかがでしょうか。
学習環境
OS:Mac
使用環境:Python3.7、VS Code
使用ライブラリ:tkinter
実際に書いたコード
赤色部分が本学習で自分でいじった部分です。
from tkinter import ttk from tkinter import Tk from tkinter import StringVar #レイアウトを作成するために下記のようにすると楽だそうです LAYOUT = [ ['7', '8', '9', '/',], ['4', '5', '6', '*',], ['1', '2', '3', '-', 'C'], ['0', '.', '=', '+', 'AC'], ] #記号をまとめた定数、if char in CAlC_SYMBOLS:…のように使うために定義しておく CAlC_SYMBOLS = ('+', '-', '', '/', '*', '//') class CalcApp(ttk.Frame): """ 電卓アプリ """def __init__(self, master=None):super().__init__(master)self.exp_list =['0']self.create_style()self.create_widgets()def create_style(self):"""ボタン、ラベルのスタイルを変更"""style = ttk.Style()style.theme_use('default')#ラベルのスタイルを上書きstyle.configure('TLabel', font=('Helvetica', 20), background='black', foreground='white')#ボタンのスタイルを上書きstyle.configure('TButton', font=('Helvetica', 20))def create_widgets(self): #ウィジェットの作成と配置#計算結果の表示ラベルself.display_var = StringVar()self.display_var.set('0') #初期値を0にするdispay_label = ttk.Label(self, textvariable=self.display_var)dispay_label.grid(column=0, row=0, columnspan=5, sticky='N, S, E, W')#レイアウトの作成for y, row in enumerate(LAYOUT, 1):for x, char in enumerate(row):button = ttk.Button(self, text=char)button.grid(column=x, row=y, sticky='N, S, E, W')button.bind('<Button-1>', self.calc)self.grid(column=0, row=0, sticky='N, S, E, W') #これを忘れると表示されないので注意#各列の引き伸ばし設定self.columnconfigure(0, weight=1)self.columnconfigure(1, weight=1)self.columnconfigure(2, weight=1)self.columnconfigure(3, weight=1)#各行の引き伸ばし設定self.rowconfigure(0, weight=0)self.rowconfigure(1, weight=1)self.rowconfigure(2, weight=1)self.rowconfigure(3, weight=1)self.rowconfigure(4, weight=1)#トップレベルのウィジェットも引き伸ばしに対応させるself.master.columnconfigure(0, weight=1)self.master.rowconfigure(0, weight=1) def calc(self, event):#押されたボタンのテキストを取得char = event.widget['text']#最後に押したボタンの内容last = self.exp_list[-1]#=を押した時if char == '=':if last in CAlC_SYMBOLS:self.exp_list.pop()exp = eval(''.join(self.exp_list))self.exp_list = [str(exp)]#ACを押した場合elif char == 'AC':self.exp_list = ['0']#Cを押した場合elif char == 'C':if len(self.exp_list) == 1:self.exp_list = ['0']else:self.exp_list = self.exp_list[:-1]#各演算記号を押した場合elif char in CAlC_SYMBOLS:if last == char == '/':self.exp_list[-1] += '/'elif last == char == '*':self.exp_list[-1] += '*'elif last in CAlC_SYMBOLS:self.exp_list[-1] = charelse:self.exp_list.append(char)#数値のボタンを押した場合else:if last == '0':self.exp_list[-1] = charelif last in CAlC_SYMBOLS:self.exp_list.append(char)else:self.exp_list[-1] += charself.display_var.set(''.join(self.exp_list))def main(): root = Tk() root.title('簡易電卓') CalcApp(root) root.mainloop() if __name__ == '__main__': main()


改造したところ
エラーが出た部分
「sticky=(N, S, E, W)」で「name ‘N’ is not defined」のエラーが出た
ttk.Button(self, text='横0, 縦0').grid(column=0, row=0, sticky=(N, S, E, W))
いう文があるがN、S、E、Wが定義されていないとエラーが出てしまいました。
色々調べてみると、下のように”で囲まれている表記をすることが必要そうです。
frame.grid(row=0, column=0, sticky='nwse')
試しに
ttk.Button(self, text='横0, 縦0').grid(column=0, row=0, sticky='N, S, E, W')
と入力するとちゃんと進みました。
StringVarでエラーが出る
こんな感じのエラーでした。
name 'stringvar' is not defined tkinter
Tkinter StringVar error
上記のページを参考にさせていただくと、
from tkinter import StringVar
とあるので、インポートしてみると、見事に動きました!
おそらく見本にさせていただいているものは
from tkinter import *
*で全てを読み込んでいるからこれをしなくても問題が出ていないものと思います。
私の環境だと上記のインポートの仕方はなぜかエラーが出てしまうので、分けてインポートしている状態になっています。
計算部分のbackgroundが黒くならない
表記通りにするとなぜか図のように計算部分が黒くなりません。

これについては、試してみると、どうもスタイルが「aqua」だと反映されないそうです。
私の環境は何も表記しないデフォルトの状態が「aqua」だったため反映されなかったっぽい。
というわけで、
style.theme_use('default')
と記載するとしっかり黒くなりました!
追加機能をつけた部分
「AC」と「C」の二つのクリアボタンの搭載
今回参考にさせていただいた電卓では「C」を押すと計算部分が全消去になるボタンが一つついているだけととてもシンプルなものでした。
普段の電卓では、「AC」で全消去、「C」で一つ消去となっていると思いますが、今回それがついていないということは、「自分で勉強してカスタマイズしてみてね」ということか!と解釈して、トライしてみました。
ものすごく試行錯誤した結果、下記のように
#ACを押した場合elif char == 'AC':self.exp_list = ['0']#Cを押した場合elif char == 'C':if len(self.exp_list) == 1:self.exp_list = ['0']else:self.exp_list = self.exp_list[:-1]
記載すると、「AC」を押すと全て消去して0になり、「C」を押すと一文字消去という感じで実装できました。


原理として、self.exp_listというものが計算部分に表記されているもので、これは文字列という認識をしているようです。
そこで、if len(self.exp_list) == 1:のように「文字列の数が1の場合のみ0を表記する」
と、self.exp_list = self.exp_list[:-1]のように「それ以外の時は1文字消去」
という感じで記載すると、狙い通りに「AC」と「C」についてそれぞれ機能を追加することができました。
上記の機能の追加には下記のページを参考にさせていただきました。
・【Python】tkinterの使い方入門。計算機GUIアプリの作成に挑戦!

反省点
エラーが出た部分について、
参考にさせていただいたページ通りだとエラーが出てしまう事が「なぜそれだとエラーがでてしまうのか」というところの大半が理解できていないところが今回の反省点です。
この「なぜ?」を説明できるようになれば大きく成長できると思うので、これからも精進します!



コメント