Python(tkinter001: ラジオボタン, after他)

■tkinterのサンプルコードの改修(ラジオボタン、after追加)
もう少しtkinterを触ってみる。前回のサンプルコードに次の修正を入れる。
1.前回、グラフを画像ファイルに保存してからtkinterで参照したので、データで受け渡すようにする。
2.2次関数の定数a, b, cをランダムに決めるパターンを追加し、ラジオボタンで切りかえれるようにする。
3.tkinterのafterを使って、ランダムに決めるパターンが自動的に更新されるようにする。

では、まず1から。
前回は、matplotlibでグラフをプロットしてから「sample017.png」という名前のファイルに保存し、その後、tkinterのPhotoImage(ファイル名)でファイルを読み込み表示させた。ディスクへの保存のプロセスが入るので、パフォーマンス的にも良くなさそうだし、余計なファイルは作らないようにしたい。そのため、matplotlibのグラフをtkinterへデータとして受け渡したい。

matplotlibからImageオブジェクトを作成して、PhotoImageで読み込むといったことができないか、いろいろ調べて試してみたけど、PhotoImageはImageを読み込むようになっていないようで、うまくいかない。最終的に、io.BytesIOでグラフの画像データをバイト列のデータに変換し、それをPhotoImageで読みこませることで対応できた。PhotoImageは、ファイル名で画像ファイルを読み込むほか、データでの読み込みもできるよう。

次に2。
ラジオボタンで、a, b, cをテキストボックスから入れるパターンとランダムに決めるパターンを切りかえれるようにする。
ラジオボタンのコードは下の通り。varでラジオボタンのチェックが入っている場所を決め、ボタンを押したときのメソッド(button1_method)の中でどちらにチェックが入っているかで場合分けする。

        self.var = ttk.IntVar()
        self.widgtRadiobut01 = ttk.Radiobutton(self.frame, value=0, variable=self.var, text='Input')
        self.widgtRadiobut02 = ttk.Radiobutton(self.frame, value=1, variable=self.var, text='Random(-10~10)')
        self.var.set(value=0)
    def button1_method(self):
        var = self.var.get()
        if var == 0:
     処理1
        elif var == 1:
     処理2

実行すると、下のような表示となる。

最後にtkinterの機能after。
これを使うと、afterの中の(ミリ秒、メソッド)で指定した通り、特定の時間を待ってからメソッドを実行する。
func1.after(2000, self.button1_method)

button1_methodの中でafterを使ったので、再帰的に呼び出され自動的に更新され続ける。tkinterのチュートリアルでは、タイマーのサンプルが紹介されていたけど自然な使い方だった。

今回修正したコードは下の通り。
次回ももう少しtkinterをさわるかも。

import tkinter as ttk
import matplotlib.pyplot as plt
from PIL import Image
import io
import random

START_VAR = -20
END_VAR = 20

class Function(ttk.Tk):
    def __init__(self):
        super().__init__()
        self.title('Function')
        self.geometry("400x400")
        self.resizable(0, 0)
        self.frame = ttk.Frame(self, borderwidth=10)
        self.frame.grid(column=8, row=8)
        self.widgt1 = ttk.Label(self.frame, text="y = a * x^2 + b * x + c")
        self.widgt2 = ttk.Entry(self.frame, text="a", width=10)
        self.widgt3 = ttk.Entry(self.frame, text="b", width=10)
        self.widgt4 = ttk.Entry(self.frame, text="c", width=10)
        self.widgt5 = ttk.Button(self.frame, text="Show", bg="white")
        self.widgt5['command'] = self.button1_method
        self.widgt6 = ttk.Label(self.frame)
        self.var = ttk.IntVar()
        self.widgtRadiobut01 = ttk.Radiobutton(self.frame, value=0, variable=self.var, text='Input')
        self.widgtRadiobut02 = ttk.Radiobutton(self.frame, value=1, variable=self.var, text='Random(-10~10)')
        self.var.set(value=0)

        self.widgt1.grid(column=0, row=1, columnspan=8)
        self.widgt2.grid(column=0, row=2)
        self.widgt3.grid(column=1, row=2)
        self.widgt4.grid(column=2, row=2)
        self.widgt5.grid(column=3, row=2)
        self.widgt6.grid(column=0, row=3, columnspan=4)
        self.widgtRadiobut01.grid(column=0, row=0)
        self.widgtRadiobut02.grid(column=2, row=0)

    def button1_method(self):
        var = self.var.get()
        if var == 0:
            imgdata = get_graph_data(self.widgt2.get(), self.widgt3.get(), self.widgt3.get())
            img = ttk.PhotoImage(data=imgdata)
            self.widgt6.configure(image=img)
            self.widgt6.image = img
        elif var == 1:
            num1 = random.randint(-10, 10)
            num2 = random.randint(-10, 10)
            num3 = random.randint(-10, 10)
            imgdata = get_graph_data(num1, num2, num3)
            img = ttk.PhotoImage(data=imgdata)
            self.widgt6.configure(image=img)
            self.widgt6.image = img
            func1.after(2000, self.button1_method)


##############################

##############################
def get_graph_data(var_a, var_b, var_c):
    x = []
    y = []
    plt.figure(figsize=(3.2, 2))
    for i in range(START_VAR, END_VAR):
        x.append(i)
        y.append(int(var_a) * (i ** 2) + int(var_b) * i + int(var_c))
    print(x)
    print(y)
    plt.plot(x, y)
    plt.tight_layout()

    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    buffdata = buf.getvalue()
    return buffdata
##############################

if __name__ == "__main__":
    func1 = Function()
    func1.mainloop()