Raspberry Pi Python GUI アプリケーション 06:簡易電卓

ボタンやテキストボックスを表示できるようになったので、簡易電卓を作ってみました。

あまり気の利いた機能はなく、計算自体は「eval」関数任せ。

画面下部のボタンで計算式を入力、「=」ボタンクリックで計算してくれます。

画面上部のテキストボックスに直接数式を入力しての計算もできます。

 

今回は以下の内容で処理を書いてみました。

・外部ライブラリは使用しない。標準のみ。

・GU部品のライブラリは、前回のものをそのまま利用。(使用しない関数もそのまま)

・フレームを上下2つにし、グリッドを別にした。

・ボタン配置はグリッドレイアウトを利用。ラクチン

・ボタンのクリックイベントでの処理の実行。クリックされたボタンのテキストで処理分岐。

 

# -*- coding: utf-8 -*-
# 日本語コメントをエラーとしないように、UTF-8で保存

# 使用するライブラリのインポート
import tkinter as Tk

class Window(Tk.Tk):
    """
    TKクラスを継承、Windowクラスとする
    """
    
    def __init__(self, text):
        """
        ウィンドウを生成する(タイトルを指定)
        """
        Tk.Tk.__init__(self)
        self.title(text)

    def setSize(self, width, height, isCenter = True):
        """
        サイズを指定、ディスプレイ中央に表示する
        """
        # サイズを指定した文字列
        geometry = "{0}x{1}".format(width, height)

        if isCenter:    # ディスプレイ中央に表示する            
            # ディスプレイの幅と高さを取得
            s_width = self.winfo_screenwidth()
            s_height = self.winfo_screenheight()
            # 表示する左上の座標を算出        
            win_left = int((s_width - width) / 2)
            win_top = int((s_height - height) / 2)
            # 表示位置を指定した文字列を追加
            geometry += "+{0}+{1}".format(win_left, win_top)

        # サイズと表示位置を中央に指定(幅 x 高さ + 左位置 + 上位置)
        self.geometry(geometry)
    
    def disableMaximum(self):
        """
        最大化を制限する
        """
        self.resizable(False, False)

class guiParts():
    """
    GUI部品を追加表示する
    すべてグリッド、左寄せで表示
    """

    def addLabel(self, row, column, text):
        """
        ラベルを追加表示する
        """
        lbl = Tk.Label(self, text = text)
        lbl.grid(row = row, column = column, pady = 5, padx = 20, sticky = Tk.W)

        return lbl

    def addTextBox(self, row, column, width, text = None):
        """
        テキストボックスを追加表示する
        """
        textbox = Tk.Entry(self, width = width)
        textbox.grid(row = row, column = column, sticky = Tk.W)
        if text != None:
            textbox.insert(Tk.END, text)
        
        return textbox

    def addCheckBox(self, row, column, text, valiable = None):
        """
        チェックボックスを追加表示する
        """
        if valiable == None:
            valiable = Tk.BooleanVar()
        checkBox = Tk.Checkbutton(self, text = text, variable = valiable)
        checkBox.grid(row = row , column = column, sticky = Tk.W)

        return (checkBox, valiable)

    def addRadioButton(self, row, column, text, onValue, valiable = None):
        """
        ラジオボタンを追加表示する
        """
        if valiable == None:
            valiable = Tk.IntVar()
        rbn = Tk.Radiobutton(self, text = text, value = onValue, variable = valiable)
        rbn.grid(row = row, column = column, sticky = Tk.W)

        return (rbn, valiable)

    def addButton(self, row, column, text, width = None):
        """
        ボタンを追加表示する
        """
        btn = Tk.Button(self, text = text, width = width)
        btn.grid(row = row, column = column, sticky = Tk.W)

        return btn

    def addListBox(self, row, column, items):
        """
        リストボックスを追加表示する
        """
        lbx = Tk.Listbox(self, height = len(items))
        lbx.grid(row = row, column = column, sticky = Tk.W + Tk.N)
        lbx.insert(Tk.END, *items)

        return lbx

    def addMenu(self, text, items, commands, mbar = None):
        """
        メニューを追加する
        """
        if mbar == None:
            mbar = Tk.Menu(self)
        mnu = Tk.Menu(mbar)
        for index, item in enumerate(items):
            label = item
            command = commands[index]
            if label == '':
                mnu.add_separator()
            else:
                mnu.add_command(label = label, command = command)
        mbar.add_cascade(label = text, menu = mnu)
        w.config(menu = mbar)
        return mbar
 
# 継承した場合など、実行されないようにする(現状、意味は特にない)
if __name__ == "__main__":
    # ウィンドウを生成、各設定
    w = Window('超簡易電卓')
    w.setSize(500, 160)
    w.disableMaximum()

    # フレームを生成(入力内容、回答表示用)
    f1 = Tk.Frame(w)
    txtAns = guiParts.addTextBox(f1, 0, 0, 40, '')
    f1.pack()

    # フレームを生成(電卓ボタン部)
    f = Tk.Frame(w)

    def clickButton(event):
        """
        入力内容を制御
        """

        # 計算不能エラーメッセージ
        ERROR_MESSAGE = 'ERROR : '
        
        # クリックされたボタンのテキストを取得
        inputVal = event.widget['text']
        # テキストボックスの内容を取得
        resultVal = txtAns.get()

        # 直近の操作が計算不能エラーの場合はクリアする
        if str(resultVal).startswith(ERROR_MESSAGE):
            txtAns.delete(0, Tk.END)

        # ボタンごとに分岐
        if inputVal == '=':
            # 計算、表示
            try:
                result = eval(resultVal)
                txtAns.delete(0, Tk.END)
                txtAns.insert(Tk.END, result)
            except:
                # 計算できなかった場合は先頭に計算不能エラーメッセージを表示
                txtAns.insert(0, ERROR_MESSAGE)

        elif inputVal == 'CL':
            # 入力内容クリア
            txtAns.delete(0, Tk.END)

        elif (inputVal in ['+', '-', '*', '/']):
            # 算術記号の場合は前後に半角スペースを開ける
            txtAns.insert(Tk.END, f' {inputVal} ')

        else:
            # 以外の場合(数字ボタンが押された)
            txtAns.insert(Tk.END, inputVal)

    # 部品を追加、表示、左クリックイベントをバインド
    guiParts.addButton(f, 3, 0, '0', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 2, 0, '1', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 2, 1, '2', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 2, 2, '3', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 1, 0, '4', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 1, 1, '5', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 1, 2, '6', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 0, 0, '7', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 0, 1, '8', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 0, 2, '9', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 0, 3, '+', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 1, 3, '-', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 2, 3, '*', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 3, 3, '/', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 3, 2, '=', 10).bind('<1>', clickButton)
    guiParts.addButton(f, 3, 1, 'CL', 10).bind('<1>', clickButton)

    f.pack()
    w.mainloop()