ステップアップ

Udemy用演習課題(tkinterでデスクトップアプリを作ってみよう!)

Udemy演習課題:tkinterで電卓アプリを作ろう

こちらは、Udemyで公開中のPythonコース「ゼロからはじめる独学プログラミング講座|目的別に効果的な学習方法を学ぶ|Python × PyCharm開発環境構築」の演習課題用の記事です。

このコースは、独学でPythonを学習できることを目的にしています。

この演習では、練習として「ブログ記事を見ながらコードを入力して必要なインポートを行い、実行する」ことを目的にしています。

(解答解説の動画はUdemy本編をご覧ください。)

では、始めましょう!

この課題のゴール

この記事は、Python初心者向けにGUI(Graphical User Interface)アプリの作り方を紹介する実践型のチュートリアルです。

今回は、2つの数字と演算子を指定して計算できる「シンプル電卓アプリ」を一緒に作っていきます。

プログラミングを始めたばかりでも、手を動かしながら進めれば理解が深まります。

各ステップではコードとその解説を丁寧に記載しているので、初心者の方も焦らずじっくり取り組んでみてください。

(完成見本)

このように、2つの入力ボックスに値を入れ、ドロップダウンから演算子を選択し、最後に計算するボタンをクリックしたら計算結果が表示されるものです。

なお、開発環境は特に指定しませんので、ご自身の好きな環境でやってみてください。

(Google Colabでは実行できません。)

ステップ1:基本のウィンドウを作る

まずは、アプリのウィンドウを作成するところから始めましょう。

すべてのGUIアプリの土台となる部分で、画面そのものを生成するために必要な処理です。

import tkinter as tk

root = tk.Tk()
root.title("電卓アプリ")
root.geometry("300x250")
root.configure(bg="white")

root.mainloop()

実行してみると、何もないウィンドウが表示されます。

このコードで何をしているのか?というと、

  • tkinterライブラリをインポートします
  • tk.Tk():アプリのウィンドウ(本体)を作成します
  • title():ウィンドウの上部に表示されるタイトルを設定します
  • geometry():ウィンドウの幅と高さを指定します
  • configure():背景色を白に設定します
  • mainloop():ウィンドウを表示し、ユーザー操作を待機するループを開始します

というように、GUIアプリ(デスクトップアプリ)を構成するために必要な部品を用意し、設定をしています。

GUIアプリでは、まず「ウィンドウ=入れ物」を作る必要があります。

tk.Tk()はその役割を果たします。

その中に部品(ボタンや入力欄など)を追加していくことで、アプリが完成していきます。

なお、tkinterでは入力ボックスやボタンなどの部品のことをウィジェットと呼びます。

ステップ2:入力欄を作る

次に、ユーザーが数字を入力できる欄を2つ作ります。

これは足し算や引き算などを行うときに必要な、左辺と右辺の数字を入力するためのものです。

entry1 = tk.Entry(root, width=10)
entry1.pack()

entry2 = tk.Entry(root, width=10)
entry2.pack()

実行してみると、入力フォームが2つ追加されました。

このコードで何をしているかというと、

  • Entry:ユーザーの入力を受け取るための部品です
  • width=10:入力欄の横幅を文字数で指定します
  • pack():ウィンドウ内に部品を配置します

というように、ユーザーが数字を打ち込む場所を作ります。

Entryウィジェットを使えば、キーボードからの入力を簡単に受け付けられます。

部品は作っただけでは表示されないので、pack()で配置することが重要です。

tkinterでパーツを配置する方法は主に3つありますが、今回は単純に縦に並べるだけで良いので、pack()を使っています。

ステップ3:演算子を選ぶドロップダウン

次に、ユーザーが「どの計算をしたいか」を選べるように、演算子の選択メニューを用意します。

ドロップダウンは、機能名では「コンボボックス」といいます。

tkinterでコンボボックスウィジェットを利用するには、ttkを追加でインポートする必要があります。

from tkinter import ttk

operator_var = tk.StringVar()
operator_menu = ttk.Combobox(root, textvariable=operator_var, state="readonly", width=5)
operator_menu["values"] = ("+", "-", "×", "÷")
operator_menu.current(0)
operator_menu.pack()

実行してみると、ドロップダウンが追加されています。

このコードで何をしているかというと、

  • StringVar():選ばれた演算子の値を保持する変数です
  • ttk.Combobox:選択式のドロップダウンメニューです
  • values:選択肢として表示する演算子を指定します
  • current(0):初期状態でどの演算子を選んでおくかを指定します

というように、四則演算(+−×÷)の中から好きなものを選べるようにすることで、より電卓らしくなります。

このような「選択する」UIパーツを使うと、ユーザーにとって操作しやすいアプリになります。

ステップ4:結果を表示するラベル

計算結果を画面上に表示するためのラベル(文字を出力するパーツ)を追加します。

label_result = tk.Label(root, text="結果:", fg="blue", bg="white")
label_result.pack()

実行してみると、結果を表示する場所ができました。

ただし、計算結果はまだ表示されません。(計算の処理がまだありません。)

このコードで何をやっているかというと、

  • Label:文字列を画面に表示するための部品です
  • text:初期表示のテキストを指定します
  • fg:文字色
  • bg:背景色

によってユーザーに計算結果を伝えるためには、結果を表示するエリアが必要です。

こではラベルを使って画面に文字を表示します。

結果はあとで上書きされるので、初期値は「結果:」だけにしています。

ステップ5:計算ボタンを作る

パーツの最後は「計算する」ボタンを作り、押されたら実際に計算して結果を表示する処理を作成します。

btn = tk.Button(root, text="計算する", command=10)
btn.pack(pady=10)

ただし、現時点ではまだ計算の処理がないので、一時的に変数commandには「10」など適当な値を入れておきましょう。

このコードで何をやっているかというと、

  • Button:クリック可能なボタンを作成する部品です
  • text="計算する":ボタンに表示する文字列を設定します
  • command=calculate:ボタンがクリックされたときに呼び出す関数を指定します
  • pack(pady=10):上下に10ピクセルの余白をつけて配置します

というように、これまでに作成した入力欄・演算子メニュー・結果表示ラベルをつなぐ役割を担うのがこのボタンです。

「計算する」ボタンを押すと、calculate()という関数が呼び出され、計算結果が表示されるようにしたいのですが、現在はまだ関数がないので「10」を入れている状態です。

ボタンの配置も、見た目を整えるために重要な要素です。

(補足)初心者向けの事前知識

関数定義の基本

ここで、初心者の方に向けて「関数を定義する」という基本を紹介しておきます。

不要な方は飛ばしてください。

関数とは「処理のまとまり」に名前をつけたものです。

たとえば「こんにちは」と表示する処理を何度も書くのは大変ですよね。

そんなときに「hello()」のような関数を作っておけば、必要なときに呼び出すだけで同じ処理ができます。

def hello():
    print("こんにちは!")

hello()  # → "こんにちは!" と表示される

これが関数の基本です。

今回の電卓アプリでも「計算処理」を関数にまとめておくことで、ボタンが押されたときに簡単に呼び出せるようにしています。

「hello()」は関数を呼び出しています。

こうすることで、関数を呼び出すたびに関数内に記述した処理が行われます。

この例は処理が少ないですが、何十行の処理を一つの関数に定義すると、それを1行で呼び出す(実行する)ことができるので便利です。

例:計算処理を行う関数を定義

では実際に、計算する処理を関数で作って呼び出してみましょう。

今回はシンプルに足し算か引き算かを条件分岐できるようにしています。

値をinput()で入力してもらい、関数を呼び出してその結果をprint()で出力するだけです。

def keisan():
    if operator == '+':
        return num1 + num2
    elif operator == '-':
        return num1 - num2

num1 = int(input('1つ目の値:'))
num2 = int(input('2つ目の値:'))
operator = '+'

kekka = keisan()
print(kekka)

実行してみると、最初にinput文で入力し、その後「合計」が表示されます。

演算子(変数operator)には「+」が入っているので、現時点では足し算しかできません。

なんとなく、関数が何をやっているのか?理解できましたでしょうか。

ステップ6:計算処理を作る

ステップ5までで、見た目の部分は一通りできました。

ここでは、中身の計算処理や結果をラベルに渡して表示するための処理を行います。

計算するボタンが押下されたとき、関数を呼び出すようにするため、計算を行う「関数」を定義します。

ちなみに、Pythonはインタプリタ言語のため、原則「上から順に実行」されます。

関数定義はコードの上の方に記述しておきましょう。

def calculate():
    num1 = float(entry1.get())
    num2 = float(entry2.get())
    operator = operator_var.get()

    if operator == "+":
        result = num1 + num2
    elif operator == "-":
        result = num1 - num2
    elif operator == "×":
        result = num1 * num2
    elif operator == "÷":
        if num2 == 0:
            raise ZeroDivisionError
        result = num1 / num2
    else:
        raise ValueError("不明な演算子")

    label_result["text"] = f"結果:{result:.2f}"

関数を定義しただけでは、実行しても何も起きません。

関数は、呼び出されないとその処理が行われないためです。

関数内では何が行われているかというと、

  • calculate():計算処理全体をまとめた関数です
  • float(entry.get()):入力された文字列を取得し数値に変換します
  • operator_var.get():選択された演算子を取得します
  • label_result["text"]:結果を表示するラベルに出力します

データの流れがややこしいので、矢印で説明します。

ステップ2とステップ3では、それぞれ変数を用意しました。

その値を取得するため、get()を使っています。

最終的に、計算結果は変数「result」に入り、それを結果のラベル「label_result」に渡しています。

なお、ここは難しければ覚えなくても良いですが、条件分岐の中でraiseという部分がありますが、これはエラーが発生したときにプログラムが終了せず「処理」ができるように記述しています。

後ほど解説しますが、難しいようなら無視しても良いです。

ステップ7:計算するボタンに関数を割り当てる

ここまで、表示部分と内部的な計算処理を作ってきました。

しかし、このままでは関数を呼び出すことができません。

そこで、ステップ5で用意した「計算する」ボタンを押下したとき、ステップ6で定義した関数calcurateを呼び出すように修正します。

(仮の値「10」を入れていたところです。)

btn = tk.Button(root, text="計算する", command=calculate)
btn.pack(pady=10)

これにより、ボタンを押下したとき、calculate関数を呼び出すことができるようになります。

実際に、値を入れて動かしてみましょう。

計算するボタンを押下すると、結果が表示されます。

いかがでしょうか。

なお、計算結果が小数値になっているのは、get()するときにfloat()で型変換をしているためです。

ステップ8:不正な値が入力された際のエラー対策

計算アプリでは、数値(整数、小数値)を入れる前提でプログラミングしています。

しかし、人によっては文字を入れてしまったり、0で割ったりしてしまう人がいます。

そこで、プログラムでは「例外処理」という対策を行います。

例外処理については、こちらの記事を参考にしてください。

ここでは詳しい解説は省略しますが、先ほどの関数を書き直し、try/exceptを追加します。

from tkinter import messagebox

def calculate():
    try:
        num1 = float(entry1.get())
        num2 = float(entry2.get())
        operator = operator_var.get()

        if operator == "+":
            result = num1 + num2
        elif operator == "-":
            result = num1 - num2
        elif operator == "×":
            result = num1 * num2
        elif operator == "÷":
            if num2 == 0:
                raise ZeroDivisionError
            result = num1 / num2
        else:
            raise ValueError("不明な演算子")

        label_result["text"] = f"結果:{result:.2f}"

    except ValueError:
        messagebox.showerror("入力エラー", "数値を正しく入力してください")
    except ZeroDivisionError:
        messagebox.showerror("ゼロ除算", "0で割ることはできません")

さらに、tkinterの機能でメッセージボックスを表示する機能を追加しました。

エラーがでたとき、ユーザにはprint文が見えないため、エラーが出ても見えません。

上の例では、0で割ろうとしていますが、アプリ上には何も表示されず、ユーザは気づきません。

しかし、内部的にはエラーが出ているのでコンソールにはエラーが表示されています。

何が悪かったか?を知らせるために、メッセージボックスを表示し、エラーを提示します。

この機能を使うために、1行目にインポートを追加しています。

上の図は、割り算の場合に0で割ろうとしてエラーが出たところです。

ステップ9:仕上げ

最後に、見た目を整えて完成させましょう。

アプリらしく、タイトルを入れます。

# タイトル
tk.Label(root, text="電卓アプリ", font=("Arial", 14), bg="white").pack(pady=10)

各パーツの間にスペースを空ける場合、

btn = tk.Button(root, text="計算する", command=calculate)
btn.pack(pady=20)

のようにpadyの値を入れるとスペースを入れることができます。

下の比較は、右側の各ウィジェットのpadyをすべて20にしています。
(違いを見るため、あえて大きめの値にしています。)

今回の説明は以上です。

ここまでのコード全文を載せておきます。

うまく行かなかった場合は参考にしてください。

import tkinter as tk
from tkinter import ttk

def calculate():
    num1 = float(entry1.get())
    num2 = float(entry2.get())
    operator = operator_var.get()

    if operator == "+":
        result = num1 + num2
    elif operator == "-":
        result = num1 - num2
    elif operator == "×":
        result = num1 * num2
    elif operator == "÷":
        if num2 == 0:
            raise ZeroDivisionError
        result = num1 / num2
    else:
        raise ValueError("不明な演算子")

    label_result["text"] = f"結果:{result:.2f}"

root = tk.Tk()
root.title("電卓アプリ")
root.geometry("300x250")
root.configure(bg="white")

# タイトル
tk.Label(root, text="電卓アプリ", font=("Arial", 14), bg="white").pack(pady=10)

entry1 = tk.Entry(root, width=10)
entry1.pack()

operator_var = tk.StringVar()
operator_menu = ttk.Combobox(root, textvariable=operator_var, state="readonly", width=5)
operator_menu["values"] = ("+", "-", "×", "÷")
operator_menu.current(0)
operator_menu.pack(pady=5)

entry2 = tk.Entry(root, width=10)
entry2.pack()

btn = tk.Button(root, text="計算する", command=calculate)
btn.pack(pady=10)

label_result = tk.Label(root, text="結果:", fg="blue", bg="white")
label_result.pack()

root.mainloop()

配置について、pack以外にもgridやplaceなどの方法があります。

下のように、左右に並べるレイアウトをするにはgridがお勧めです。

今後も便利なアプリを紹介しますので、Pythonのプログラミングを一緒に楽しみましょう!

まとめ

いかがだったでしょうか。

今回はUdemyの演習用にtkinterを使った電卓アプリを作ってみました。

このように、ブログ記事やnoteで手順を紹介しているものがたくさんあります。

それを見ながら、コース内で構築した環境で実際に手を動かせるというのが、このコースの大きな魅力です。

すぐにコードを試せる環境が整っているため、初心者でもつまずきにくく、自分のペースで学び進めることができます。

ぜひ、他の演習にもチャレンジしてみてくださいね。

今後も初心者向けにプログラミングの情報をお届けします。

以下のメルマガにご登録頂くと、不定期に配信をお届けします。

ぜひ購読してください!

それでは、ステキなPythonライフを!

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です