「日経ソフトウェア2022年9月号 特集2 Python デスクトップアプリを作ろう」をやってみた その2

日経ソフトウェア2022年9月号 特集2 Python デスクトップアプリを作ろう」を実行してみました。

 

サンプルプログラム

サンプルプログラムは日経ソフトウェアのWebからダウンロードできます。

以下URLから「本誌バックナンバーを見る」→「2022年9月号」→「「特集2 Pythonでデスクトップアプリを作ろう 前編」(t22209.zip)

 

nkbp.jp

 

PART2 「BMI計算機」アプリを作ろう

BMIは体重÷(身長x身長)で求める肥満度を表す計算式です。

BMIの値が18.5未満であれば低体重、18.5以上25.0未満であれば普通体重、25.0以上30.0未満なら肥満度1と判定します。

 

Buttonウィジェットの使い方

前回のlabel部分をButtonに変更することでボタンが実装できます。

前回の記述:label = tk.Label(root,text='ここをクリック',foreground='red')

今回:             btn = tk.Button(root, text='表示', command=click)

click関数は前回同様、左クリックされたらtxtをゲットしてメッセージボックスで表示します。

import tkinter as tk
from tkinter import messagebox

root = tk.Tk()
root.title('ボタンテスト')
root.geometry('300x150')

txt = tk.Entry(width=20)
txt.pack(pady=50)

# ハンドラ関数
def click():
  messagebox.showinfo('メッセージ', txt.get())

# Buttonウィジェットの生成と配置
btn = tk.Button(root, text='表示', command=click)
btn.pack()

root.mainloop()

 

実行結果

テキストボックスに文字を記入してボタンを押すと、メッセージボックスが起動し、テキストの内容を表示します。

Button

 

glid関数でウィジェットを格子状に配置する

grid関数を使用するとウィジェットを格子状に配置できます。

Labelウィジェットを8個生成し、grid関数を8回実行します。

 

import tkinter as tk

root = tk.Tk()
root.title('Grid Test')
root.geometry('400x200')

WIDGET_MAX = 8

# Labelウィジェットのリストを生成
labels = [tk.Label(root, text='NO_'+str(num),
                   relief=tk.SOLID)
          for num in range(WIDGET_MAX)]

# grid関数で配置
for num in range(WIDGET_MAX):
  labels[num].grid()

root.mainloop()

 

実行結果

8個の格子状のLabel表示ができました。

grid01

gridに引数を与えることで所望の場所に配置できます。

columnは列、rowは行を表します。

最初のラベルは0列0行、次のラベルは1列0行・・と表示されます。

import tkinter as tk

root = tk.Tk()
root.title('Grid Test')
root.geometry('400x200')

WIDGET_MAX = 8

# Labelウィジェットのリストを生成
labels = [tk.Label(root, text='NO_'+str(num),
                   relief=tk.SOLID)
          for num in range(WIDGET_MAX)]

# grid関数で配置
labels[0].grid(column=0, row=0)
labels[1].grid(column=1, row=0)
labels[2].grid(column=2, row=0)
labels[3].grid(column=3, row=0)
labels[4].grid(column=0, row=1)
labels[5].grid(column=1, row=1)
labels[6].grid(column=2, row=1)
labels[7].grid(column=3, row=1)

root.mainloop()

 

実行結果

grid02

 

"columnconfigure"と"rowconfigure"関数を使用すると行と行の間隔、列と列の間隔を調整できます。

import tkinter as tk

root = tk.Tk()
root.title('Grid Test')
root.geometry('400x200')

WIDGET_MAX = 8

labels = [tk.Label(root, text='NO_'+str(num),
                   relief=tk.SOLID)
          for num in range(WIDGET_MAX)]

# 各列の割合を指定
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

# 各行の割合を指定
root.rowconfigure(0, weight=1)
root.rowconfigure(1, weight=1)

# grid関数で配置
labels[0].grid(column=0, row=0)
labels[1].grid(column=1, row=0)
labels[2].grid(column=2, row=0)
labels[3].grid(column=3, row=0)
labels[4].grid(column=0, row=1)
labels[5].grid(column=1, row=1)
labels[6].grid(column=2, row=1)
labels[7].grid(column=3, row=1)

root.mainloop()

 

実行結果

grid03

引数のweightを1に設定しているため、均等に表示されています。

適当に値をかえて実行してみると

# 各列の割合を指定
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=4)
root.columnconfigure(2, weight=4)
root.columnconfigure(3, weight=1)

# 各行の割合を指定
root.rowconfigure(0, weight=5)
root.rowconfigure(1, weight=1)

 

実行結果

columnconfigureでweightを4に変えてみました。4つの列のうちNO_1とNO_2の領域の割合が4割づつとなっています。

行のほうは、rowconfigureでweightを5対1に設定してみた結果です。

grid04

 

grid関数の引数にstickyをさらに領域内のどの辺に指定するかを設定できます。

NSEWで設定します。Nは上方向、Sは下方向、Eは右方向、Wは左方向に配置します。

NE、SWなどを指定すると左上方向、右下方向に配置されます。

NSEWすべてを指定すると領域全体に配置されます。

 

import tkinter as tk

root = tk.Tk()
root.title('Grid Test')
root.geometry('400x200')

WIDGET_MAX = 8

labels = [tk.Label(root, text='NO_'+str(num),
                   relief=tk.SOLID)
          for num in range(WIDGET_MAX)]

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

root.rowconfigure(0, weight=1)
root.rowconfigure(1, weight=1)

# grid関数で配置
labels[0].grid(column=0, row=0, sticky=tk.N)
labels[1].grid(column=1, row=0, sticky=tk.S)
labels[2].grid(column=2, row=0, sticky=tk.E)
labels[3].grid(column=3, row=0, sticky=tk.W)
labels[4].grid(column=0, row=1, sticky=tk.NS)
labels[5].grid(column=1, row=1, sticky=tk.SE)
labels[6].grid(column=2, row=1, sticky=tk.EW)
labels[7].grid(column=3, row=1, sticky=tk.NSEW)

root.mainloop()

 

実行結果

NO_0、NO_1、NO_2、NO_3がまず同じ行にweight=1なので均等に配置されます。

その後。stickyで「上」「下」「右」「左」と指定しているので、各自の領域の中でそれぞれ指定された部分に格子状に配置されています。

NO_4、NO_5、NO_6、NO_7は「上下」「右下」、「左右」、「上下左右」に配置されています。

stick

 

rowやcolumnの複数の領域に一つのウィジェットを割り当てる場合は、rowspanやcolumnpanを使用します。

 

NO_0はrowspan=2で2行、NO_1はcolumnspan=2で2列、NO_3はcolumnspan=3で3列分の領域をとります。

 

import tkinter as tk

root = tk.Tk()
root.title('Grid Test')
root.geometry('400x200')

WIDGET_MAX = 4

labels = [tk.Label(root, text='NO_'+str(num),
                   relief=tk.SOLID)
          for num in range(WIDGET_MAX)]

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)
root.columnconfigure(3, weight=1)

root.rowconfigure(0, weight=1)
root.rowconfigure(1, weight=1)

# grid関数で配置
labels[0].grid(column=0, row=0, rowspan=2)
labels[1].grid(column=1, row=0, columnspan=2)
labels[2].grid(column=3, row=0)
labels[3].grid(column=1, row=1, columnspan=3)

root.mainloop()

 

実行結果

 

span

 

 

最後に、BMI計算機の各ウィジェットの配置を考慮したプログラムを実行すると、

以下のアプリが起動します。

BMI計算機
import tkinter as tk

# BMI計算関数
def calc(weight, height):
  return weight / (height**2)

# 肥満度判定関数
def check(bmi):
  if bmi < 18.5:
    result = '低体重'
  elif bmi < 25.0:
    result = '普通体重'
  elif bmi < 30.0:
    result = '肥満度1'
  elif bmi < 35.0:
    result = '肥満度2'
  elif bmi < 40.0:
    result = '肥満度3'
  else:
    result = '肥満度4'
  return result

root = tk.Tk()
root.title('肥満度チェック')
root.geometry('250x150')

# Labelウィジェットの生成
label_1 = tk.Label(root, text='体重')
label_2 = tk.Label(root, text='kg')
label_3 = tk.Label(root, text='身長')
label_4 = tk.Label(root, text='cm')
label_5 = tk.Label(root, text='体重と身長を入力してください。')

# Entryウィジェットの生成
weight = tk.Entry(width=5)
height = tk.Entry(width=5)

# Buttonのハンドラ関数
def judgement():
  w = float(weight.get())
  h = float(height.get()) / 100
  s = check(calc(w, h))
  label_5['text'] = '肥満度:' + str(s)

# Buttonウィジェットの生成
button = tk.Button(root, text='BMI判定', command=judgement)

root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.columnconfigure(2, weight=1)

root.rowconfigure(0, weight=1)
root.rowconfigure(1, weight=1)
root.rowconfigure(2, weight=1)
root.rowconfigure(3, weight=1)

# grid関数でウィジェットを配置
label_1.grid(column=0, row=0, sticky=tk.E)
weight.grid(column=1, row=0)
label_2.grid(column=2, row=0, sticky=tk.W)
label_3.grid(column=0, row=1, sticky=tk.E)
height.grid(column=1, row=1)
label_4.grid(column=2, row=1, sticky=tk.W)
button.grid(column=0, row=2, columnspan=3)
label_5.grid(column=0, row=3, columnspan=3)

root.mainloop()


 

身長と体重を入力し、ボタンをクリックすると、肥満度が表示されます。

BMI計算結果

 

 

 

 

 

 

 

 

 

/* -----codeの行番号----- */