0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python: Tkinterを用いたMac用appの作成(タブ・表・TeX数式)(2024.11.03)

Last updated at Posted at 2024-11-03

はじめに

Tkinter の使い方に慣れるため、もう一つGUIアプリを作ってみた、テクニック的には以下のものを織り込んだ。

  • タブを使う
  • 表を使う
  • matplotlib 経由で TeX 数式を canvas に描画
  • 計算結果は messagebox に表示

参考にしたサイトは以下の通り。

(タブの使い方)
【Tkinter】【コピペ可】ボタン、タブ、表の使い方をざっくり説明
https://kazuwo-blog.com/python-tkinter/#index_id10

(matplotlibのcanvasへの埋め込み)
Embedding in Tk
https://matplotlib.org/3.1.0/gallery/user_interfaces/embedding_in_tk_sgskip.html

(matplotlibで余白の調整)
【python】matplotlibで図の余白を調整する
https://hayataka2049.hatenablog.jp/entry/2018/10/11/030103

(表の作成)
⑨ 表(テーブル)の作成【python tkinter sqlite3で家計簿を作る】
https://memopy.hatenadiary.jp/entry/2017/06/02/230723

動作中写真

2つのタブ(Concrete と Rock)のうち、Concrete での計算実行結果画面。
何に出力するか考えたが、このアプリでは計算結果の数値が確認できればいいので、messagebox に出力することとした。
タブの中に入力用の参考として小さな表を表示している。

IMG_0111.jpeg

使っている計算式を表示したもの。普通に matplotlib での描画コマンドを打ち、canvas に表示させているもの。これを表示すると、メイン画面の左上の x を押しても、画面は閉じるが Python が終了しない事態に見舞われたため、Quit により Python そのものを終了させるようにした。

IMG_0115.jpeg

2つのタブ(Concrete と Rock)のうち、Rock での計算実行結果画面。
ここでもタブの中に入力用の参考として小さな表を表示している。
matplotlib での描画後、messagebox に表示されるアイコンが変わってしまっている。icon='info' で明示してもアイコンが変化してしまう。本質に影響はないので未解決のまま。

IMG_0116.jpeg

コード

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


def end_q():
    quit()


def plot():
    fsz=11
    xmin,xmax,dx=0, 5, 1
    ymin,ymax,dy=0, 10, 1
    fig = plt.figure(figsize = (3,3),dpi = 100)
    plt.rcParams['font.size']=fsz
    plt.rcParams['font.family']='sans-serif'
    plt.subplots_adjust(left=0.1,right=0.95,bottom=0.1,top=0.95)
    plt.xlim([xmin,xmax])
    plt.ylim([ymin,ymax])
    plt.axis('off')
    ss=[]
    ss.append(r'$\sigma_c$: compressive strength (positive)')
    ss.append(r'$\sigma_t$: tensile strength (positive)')
    ss.append(r'$\phi$: internal friction angle')
    ss.append(r'$c$: cohesion')
    ss.append('For Concrete')
    ss.append(r'$\sigma_t=0.23\cdot (\sigma_c)^{2/3}$')
    ss.append(r'$\phi=\sin^{-1}\left(\frac{\sigma_c-\sigma_t}{\sigma_c+\sigma_t}\right)$')
    ss.append(r'$c=\frac{\sigma_c\cdot \sigma_t}{\cos\phi\cdot (\sigma_c+\sigma_t)}$')
    ss.append('For Rock')
    ss.append(r'$\sigma_c=\frac{2\cdot c\cdot \cos\phi}{1-\sin\phi}$')
    ss.append(r'$\sigma_t=\frac{2\cdot c\cdot \cos\phi}{1+\sin\phi}$')
    xy=np.array([
        [0,9.5-0*0.6],
        [0,9.5-1*0.6],
        [0,9.5-2*0.6],
        [0,9.5-3*0.6],
        [0,6.5-0*1.0], # For Concrete
        [1,6.5-1*1.0],
        [1,6.5-2*1.0],
        [1,6.5-3*1.0],
        [0,6.5-4*1.0], # For Rock
        [1,6.5-5*1.0],
        [1,6.5-6*1.0]
    ])
    for i in range(len(ss)):
        plt.text(xy[i,0],xy[i,1],ss[i],ha='left',va='center',fontsize=fsz)
    return fig


def show_eqs():
    sub_win=tk.Toplevel()
    sub_win.title('Equations')
    fig=plot()
    canvas = FigureCanvasTkAgg(fig,master=sub_win)
    canvas.draw() 
    canvas.get_tk_widget().pack()
    sub_win.mainloop()


def click_t1():
    global entry_t1a
    # Concrete
    sigc=float(entry_t1a.get()) # compressive strength
    sigt=0.23*sigc**(2/3) # tensile strength
    sn=(sigc-sigt)/(sigc+sigt) # sin(phi)
    cs=np.sqrt(1-sn**2) # cos(phi)
    phi=np.degrees(np.arcsin(sn)) # internal friction angle
    cc=(1+sn)/2/cs*sigt # cohesion
    s0='Concrete'
    s1='sigc (MPa)={0:6.3f}'.format(sigc)
    s2='sigt (MPa)={0:6.3f}'.format(sigt)
    s3='cc   (MPa)={0:6.3f}'.format(cc)
    s4='phi  (deg)={0:6.3f}'.format(phi)
    ss=s0+'\n'+s1+'\n'+s2+'\n'+s3+'\n'+s4
    if messagebox.showinfo('Concrete',ss)=='ok': entry_t1a.focus_set()


def click_t2():
    global entry_t2a,entry_t2b
    # Rock
    cc =float(entry_t2a.get()) # cohesion
    phi=float(entry_t2b.get()) # internal friction angle
    sigc=2*cc*np.cos(np.radians(phi))/(1-np.sin(np.radians(phi)))
    sigt=2*cc*np.cos(np.radians(phi))/(1+np.sin(np.radians(phi)))
    s0='Rock'
    s1='cc   (MPa)={0:6.3f}'.format(cc)
    s2='phi  (deg)={0:6.3f}'.format(phi)
    s3='sigc (MPa)={0:6.3f}'.format(sigc)
    s4='sigt (MPa)={0:6.3f}'.format(sigt)
    ss=s0+'\n'+s1+'\n'+s2+'\n'+s3+'\n'+s4
    if messagebox.showinfo('Rock',ss)=='ok': entry_t2a.focus_set()


def ini_t1():
    global entry_t1a
    entry_t1a.delete(0,tk.END)
    entry_t1a.insert(tk.END,'25')


def ini_t2():
    global entry_t2a,entry_t2b
    entry_t2a.delete(0,tk.END)
    entry_t2b.delete(0,tk.END)
    entry_t2a.insert(tk.END,'3.506')
    entry_t2b.insert(tk.END,'58.666')


def main():
    global entry_t1a,entry_t2a,entry_t2b
    root =tk.Tk()
    root.title('Shear strength')

    button_eqs=tk.Button(root,text='Show Equations',command=show_eqs)
    button_eqs.pack()

    nb = ttk.Notebook(root)
    tab1 = tk.Frame(nb)
    tab2 = tk.Frame(nb)
    nb.add(tab1, text='Concrete')
    nb.add(tab2, text='Rock')
    nb.pack()

    label_t1a=tk.Label(tab1,text='sigc (MPa)')
    entry_t1a=tk.Entry(tab1,justify=tk.CENTER,width=7,bg='#000080')
    button_t1a=tk.Button(tab1,text='Calculcation',command=click_t1)
    button_t1b=tk.Button(tab1,text='(Initial value)',command=ini_t1)
    label_t1a.grid(row=0,column=0)
    entry_t1a.grid(row=0,column=1)
    button_t1a.grid(row=1,column=0,columnspan=2)
    button_t1b.grid(row=2,column=0,columnspan=2)
    ini_t1() # initial value

    label_t1c=tk.Label(tab1,text='sigc = cylinder strehgth')
    label_t1c.grid(row=4,column=0,columnspan=2)
    s1='Cube (MPa)'
    s2='Cylinder (MPa)'
    bs=np.array([15,20,25,30,35,40,45,50]) # BS
    en=np.array([12,16,20,25,29,32,35,40]) # EN
    tree = ttk.Treeview(tab1)
    tree['columns']=(1,2)
    tree['show']='headings'
    tree['height']=len(bs)
    tree.column(1,anchor='center',width=80)
    tree.column(2,anchor='center',width=80)
    tree.heading(1,text=s1,anchor='center')
    tree.heading(2,text=s2,anchor='center')
    for i in range(0,len(bs)):
        tree.insert(parent='',index='end',values=(bs[i],en[i]))
    tree.grid(row=5,column=0,columnspan=2)


    label_t2a=tk.Label(tab2,text='cc (MPa)')
    entry_t2a=tk.Entry(tab2,justify=tk.CENTER,width=7,bg='#000080')
    label_t2b=tk.Label(tab2,text='phi (deg)')
    entry_t2b=tk.Entry(tab2,justify=tk.CENTER,width=7,bg='#000080')
    button_t2a=tk.Button(tab2,text='Calculation',command=click_t2)
    button_t2b=tk.Button(tab2,text='(Initial value)',command=ini_t2)
    label_t2a.grid(row=0,column=0)
    entry_t2a.grid(row=0,column=1)
    label_t2b.grid(row=1,column=0)
    entry_t2b.grid(row=1,column=1)
    button_t2a.grid(row=2,column=0,columnspan=2)
    button_t2b.grid(row=3,column=0,columnspan=2)
    ini_t2() # initial value

    label_t2c=tk.Label(tab2,text='Rock Shear Strength\n(Upper limit)')
    label_t2c.grid(row=4,column=0,columnspan=2)
    s1='Class'
    s2='c (MPa)'
    s3='phi (deg)'
    rock=['B','CH','CM','CL','D']
    cc_r=np.array([6.0,4.0,2.4,1.0,0.4])
    ph_r=np.array([65,55,45,10,30])
    tree = ttk.Treeview(tab2)
    tree['columns']=(1,2,3)
    tree['show']='headings'
    tree['height']=len(rock)
    tree.column(1,anchor='center',width=50)
    tree.column(2,anchor='center',width=50)
    tree.column(3,anchor='center',width=50)
    tree.heading(1,text=s1,anchor='center')
    tree.heading(2,text=s2,anchor='center')
    tree.heading(3,text=s3,anchor='center')
    for i in range(0,len(rock)):
        tree.insert(parent='',index='end',values=(rock[i],cc_r[i],ph_r[i]))
    tree.grid(row=5,column=0,columnspan=2)


    q_button=tk.Button(root,text='Quit',command=end_q)
    q_button.pack()

    root.mainloop()


if __name__ == '__main__': main()

以 上

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?