【Python GUI tkinterサンプル】Tkinterを使って周期表を作成してみよう!

<tkinterトップページに戻る>

周期表とは

周期表(しゅうきひょう、英: the periodic table)は、物質を構成する基本単位である元素を、それぞれが持つ物理的または化学的性質が似たもの同士が並ぶように決められた規則(周期律)に従って配列した表である。「周期律表」や「元素周期表」などとも呼ばれる。周期表(しゅうきひょう、英: the periodic table)は、物質を構成する基本単位である元素を、それぞれが持つ物理的または化学的性質が似たもの同士が並ぶように決められた規則(周期律)に従って配列した表である。「周期律表」や「元素周期表」などとも呼ばれる。

Wikipedia

 

作成したいもの

周期表と、選択した原子の情報が表示されるアプリケーション

periodicTable

開発環境

Python3系(私は3.6)

Windows10

 

使用するライブラリ

tkinter

tkinter.ttk

tkinterとttkはPythonでGUIを作成するためのライブラリでクロスプラットフォームに対応しています!

また上記のライブラリはPythonに標準で搭載されています。

 

実践

①まず下準備をしよう

適当な場所にperiodicTableSample.pyを作成しましょう。

そして下記コードを追加してください。

from tkinter import *
from tkinter import ttk

class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()


if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    PeriodicTableApp(master)
    master.geometry("1400x400")
    master.mainloop()

Tkinterの基本的なウィンドウを表示する手順と、

追加で今回のGUIをまとめるFrameのPeriodicTableAppを作成します。

super().__init__(master,borderwidth=10)

Frameに対してborderwidthを指定している理由は、

ウィンドウのバー(タイトルや縮小、拡大、閉じるボタンがあるバー)に、

Widget群(ラベルやボタン)が近すぎることを防ぐためです。

 

②ttk.Frameを使用して情報表示部分と、周期表部分を作成しよう!

periodicTableFrame

情報表示部分と周期表はそれぞれFrameで作成します。

周期表には複数のWidgetを付け加える必要があるので、

新たにFrameのサブクラスを作成してその中で管理するようにしましょう。

from tkinter import *
from tkinter import ttk

class PeriodicTable(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=5)
        self.pack()

class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()
        PeriodicTable(self)


if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)
    master.mainloop()

atomInfoFrameが情報表示用のFrameで、PeriodicTableが周期表を管理するFrameです。

③情報表示部分のWidgetを作成しよう

・原子番号(整数)

・原子名(文字列)

・質量(浮動小数点数)

を作成します。

下記コードをatomInfoFrame.pack()の後に追加してください。

atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
atomNumlabel.pack(side="left")
atomNumentry = ttk.Entry(atomInfoFrame)
atomNumentry.pack(side="left")
label = ttk.Label(atomInfoFrame,text="Name:")
label.pack(side="left")
entry = ttk.Entry(atomInfoFrame)
entry.pack(side="left")
masslabel = ttk.LabelatomInfoFrame,text="Mass:")
masslabel.pack(side="left")
massentry = ttk.Entry(atomInfoFrame)
massentry.pack(side="left")

side=”left”を指定することで、atomInfoFrame内で左詰めにWidgetがセットされます。

periodictablesample

追加後のコード

from tkinter import *
from tkinter import ttk

class PeriodicTable(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=5)
        self.pack()

class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        self.create_widgets()



    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()

        atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
        atomNumlabel.pack(side="left")
        atomNumentry = ttk.Entry(atomInfoFrame)
        atomNumentry.pack(side="left")
        label = ttk.Label(atomInfoFrame,text="Name:")
        label.pack(side="left")
        entry = ttk.Entry(atomInfoFrame)
        entry.pack(side="left")
        masslabel = ttk.Label(atomInfoFrame,text="Mass:")
        masslabel.pack(side="left")
        massentry = ttk.Entry(atomInfoFrame)
        massentry.pack(side="left")

        PeriodicTable(self)

if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)

    master.mainloop()

④周期表に10×18(周期×族)のボタンテーブルを作成しよう!

周期は7ですが、ランタノイド系、アクチノイド系、周期とそれらを分けるセパレータを含めて10とします。

ひとまずはボタンを要素分作成します。

下記の関数のコードをPeriodicTableクラス内に追加してください。

def create_widgets(self):
        for vr in range(0,10):
            for hr in range(0,18):
                button = ttk.Button(self,text="ele")
                button.grid(column=hr,row=vr,sticky=(N, W, E, S))

packでなくgridを使うことで格子状にWidgetを配置することが可能になります。

また

・colomun = 横のindex

・row = 縦のindex

を指定することで配置する箇所を設定することができます。

今回は横1列ごとにボタンを作成しています。

 

periodictablesample

追加後のコード

from tkinter import *
from tkinter import ttk

class PeriodicTable(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=5)
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        for vr in range(0,10):
            for hr in range(0,18):
                button = ttk.Button(self,text="ele")
                button.grid(column=hr,row=vr,sticky=(N, W, E, S))

class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        # self.init_variables()
        self.create_widgets()



    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()

        atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
        atomNumlabel.pack(side="left")
        atomNumentry = ttk.Entry(atomInfoFrame)
        atomNumentry.pack(side="left")
        label = ttk.Label(atomInfoFrame,text="Name:")
        label.pack(side="left")
        entry = ttk.Entry(atomInfoFrame)
        entry.pack(side="left")
        masslabel = ttk.Label(atomInfoFrame,text="Mass:")
        masslabel.pack(side="left")
        massentry = ttk.Entry(atomInfoFrame)
        massentry.pack(side="left")

        PeriodicTable(self)





if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)

    master.mainloop()

 

 

⑤周期表の原子記号を登録しよう!

周期表の族番号と、原子記号を各周期ごとに分けて登録します。

下記コードをimport文のあとに追加してください。

PERIODIC_TABLE_LIST=[
{1:"H",18:"He"},
{1:"Li",2:"Be",13:"B",14:"C",15:"N",16:"O",17:"F",18:"Ne"},
{1:"Na",2:"Mg",13:"Al",14:"Si",15:"P",16:"S",17:"Cl",18:"Ar"},
{1:"K",2:"Ca",3:"Sc",4:"Tl",5:"V",6:"Cr",7:"Mn",8:"Fe",
9:"Co",10:"Ni",11:"Cu",12:"Zn",13:"Ga",14:"Ge",15:"As",16:"Se",17:"Br",18:"Kr"},
{1:"Rb",2:"Sr",3:"Y",4:"Zr",5:"Nb",6:"Mo",7:"Tc",8:"Ru",
9:"Rh",10:"Pd",11:"Ag",12:"Cd",13:"In",14:"Sn",15:"Sb",16:"Te",17:"I",18:"Xe"},
{1:"Cs",2:"Ba",4:"Hf",5:"Ta",6:"W",7:"Re",8:"Os",
9:"Ir",10:"Pt",11:"Au",12:"Hg",13:"Tl",14:"Pb",15:"Bi",16:"Po",17:"At",18:"Rn"},
{1:"Fr",2:"Ra",4:"Rf",5:"Db",6:"Sg",7:"Bh",8:"Hs",
9:"Mt",10:"Ds",11:"Rg",12:"Cn",13:"Nh",14:"Fl",15:"Mc",16:"Lv",17:"Ts",18:"Og"},
{},
{4:"La",5:"Ce",6:"Pr",7:"Nd",8:"Pm",
9:"Sm",10:"Eu",11:"Gd",12:"Tb",13:"Dy",14:"Ho",15:"Er",16:"Tm",17:"Yb",18:"Lu"},
{4:"Ac",5:"Ta",6:"Pa",7:"U",8:"Np",
9:"Pu",10:"Am",11:"Cm",12:"Bk",13:"Cf",14:"Es",15:"Fm",16:"Md",17:"No",18:"Lr"}
]

※今回の例では{}はセパレータを意味しています。

⑥各ボタンに原子番号と原子記号を割り当てよう

ボタン作成部分を下記コードに変更してください。

def create_widgets(self):
    #vrが周期、hrが族
    for vr in range(0,10):
        for hr in range(0,18):
            #族は1~18なのでhr(0~17)に1を加算することで族番号となる
            name = PERIODIC_TABLE_LIST[vr].get(hr + 1)
            #原子記号が取得できない場合はボタンではなく、ラベルを作成する 
            if name is None:
                label = ttk.Label(self)
                label.grid(column=hr,row=vr,sticky=(N, W, E, S))
            else:
                button = ttk.Button(self,text=name)
                button.grid(column=hr,row=vr,sticky=(N, W, E, S))

・原子記号の取得

name = PERIODIC_TABLE_LIST[vr].get(hr + 1)

先ほど定義したPERIODIC_TABLE_LISTは周期事にデータを登録したので、

indexを指定することで指定された周期のデータを取得することができます。

・ボタンとラベルの切り替え

if name is None:
        label = ttk.Label(self)
        label.grid(column=hr,row=vr,sticky=(N, W, E, S))
    else:
         button = ttk.Button(self,text=name)
         button.grid(column=hr,row=vr,sticky=(N, W, E, S))

取得した原子記号をButtonのtextに指定します。

また不必要なボタンを付け加えないために、原子記号が取得できなかった族には空のラベルを作成し、gridでセットしています。

では実際に起動してみましょう。

 

periodictablesample

なかなかそれらしくなってきたのではないでしょうか。

 

ここまでのサンプルコード

from tkinter import *
from tkinter import ttk

PERIODIC_TABLE_LIST=[
{1:"H",18:"He"},
{1:"Li",2:"Be",13:"B",14:"C",15:"N",16:"O",17:"F",18:"Ne"},
{1:"Na",2:"Mg",13:"Al",14:"Si",15:"P",16:"S",17:"Cl",18:"Ar"},
{1:"K",2:"Ca",3:"Sc",4:"Tl",5:"V",6:"Cr",7:"Mn",8:"Fe",
9:"Co",10:"Ni",11:"Cu",12:"Zn",13:"Ga",14:"Ge",15:"As",16:"Se",17:"Br",18:"Kr"},
{1:"Rb",2:"Sr",3:"Y",4:"Zr",5:"Nb",6:"Mo",7:"Tc",8:"Ru",
9:"Rh",10:"Pd",11:"Ag",12:"Cd",13:"In",14:"Sn",15:"Sb",16:"Te",17:"I",18:"Xe"},
{1:"Cs",2:"Ba",4:"Hf",5:"Ta",6:"W",7:"Re",8:"Os",
9:"Ir",10:"Pt",11:"Au",12:"Hg",13:"Tl",14:"Pb",15:"Bi",16:"Po",17:"At",18:"Rn"},
{1:"Fr",2:"Ra",4:"Rf",5:"Db",6:"Sg",7:"Bh",8:"Hs",
9:"Mt",10:"Ds",11:"Rg",12:"Cn",13:"Nh",14:"Fl",15:"Mc",16:"Lv",17:"Ts",18:"Og"},
{},
{4:"La",5:"Ce",6:"Pr",7:"Nd",8:"Pm",
9:"Sm",10:"Eu",11:"Gd",12:"Tb",13:"Dy",14:"Ho",15:"Er",16:"Tm",17:"Yb",18:"Lu"},
{4:"Ac",5:"Ta",6:"Pa",7:"U",8:"Np",
9:"Pu",10:"Am",11:"Cm",12:"Bk",13:"Cf",14:"Es",15:"Fm",16:"Md",17:"No",18:"Lr"}
]
class PeriodicTable(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=5)
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        for vr in range(0,10):
            for hr in range(0,18):
                name = PERIODIC_TABLE_LIST[vr].get(hr + 1)
                if name is None:
                    label = ttk.Label(self)
                    label.grid(column=hr,row=vr,sticky=(N, W, E, S))
                else:
                    button = ttk.Button(self,text=name)
                    button.grid(column=hr,row=vr,sticky=(N, W, E, S))


class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        self.create_widgets()



    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()

        atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
        atomNumlabel.pack(side="left")
        atomNumentry = ttk.Entry(atomInfoFrame)
        atomNumentry.pack(side="left")

        label = ttk.Label(atomInfoFrame,text="Name:")
        label.pack(side="left")
        entry = ttk.Entry(atomInfoFrame)
        entry.pack(side="left")
        masslabel = ttk.Label(atomInfoFrame,text="Mass:")
        masslabel.pack(side="left")
        massentry = ttk.Entry(atomInfoFrame)
        massentry.pack(side="left")

        PeriodicTable(self)





if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)

    master.mainloop()

⑦原子ごとの情報を登録しよう

原子記号をキーに各原子の情報をtupleで作成します。

・原子番号

・原子名

・質量

今回は簡単に上記3つを情報として登録します。

 

下記コードをimport文のあとに追加してください。

# 原子の情報(原子名をキーに原子番号、原子名、質量を取得できる)
ATOMS_INFO ={
"H":(1,"水素",1.00794),"He":(2,"ヘリウム",4.002602),"Li":(3,"リチウム",6.941),"Be":(4,"ベリリウム",9.012182),"B":(5,"ホウ素",10.811)
,"C":(6,"炭素",12.0107),"N":(7,"窒素",14.00674),"O":(8,"酸素",15.9994),"F":(9,"フッ素",18.9984032),"Ne":(10,"ネオン",20.1797),"Na":(11,"ナトリウム",22.989770)
,"Mg":(12,"マグネシウム",24.3050),"Al":(13,"アルミニウム",26.981538),"Si":(14,"ケイ素",28.0855),"P":(15,"リン",30.973761),"S":(16,"硫黄",32.066)
,"Cl":(17,"塩素",35.453),"Ar":(18,"アルゴン",39.948),"K":(19,"カリウム",39.0983),"Ca":(20,"カルシウム",40.078),"Sc":(21,"スカンジウム",44.955910),
"Ti":(22,"チタン",47.867),"V":(23,"バナジウム",50.9415),"Cr":(24,"クロム",51.9961),"Mn":(25,"マンガン",54.938049),"Fe":(26,"鉄",55.8457),
"Co":(27,"コバルト",58.933200),"Ni":(28,"ニッケル",58.6934),"Cu":(29,"銅",63.546),"Zn":(30,"亜鉛",65.409),"Ga":(31,"ガリウム",69.723)
,"Ge":(32,"ゲルマニウム",72.64),"As":(33,"ヒ素",74.92160),"Se":(34,"セレン",78.96),"Br":(35,"臭素",79.904),"Kr":(36,"クリプトン",83.798),
"Rb":(37,"ルビジウム",85.4678),"Sr":(38,"ストロンチウム",87.62),"Y":(39,"イットリウム",88.90585),"Zr":(40,"ジルコニウム",91.224)
,"Nb":(41,"ニオブ",92.90638),"Mo":(42,"モリブデン",95.94),"Tc":(43,"テクネチウム",98),"Ru":(44,"ルテニウム",101.07),
"Rh":(45,"ロジウム",102.90550),"Pd":(46,"パラジウム",106.42),"Ag":(47,"銀",107.8682),"Cd":(48,"カドミウム",112.411),
"In":(49,"インジウム",114.818),"Sn":(50,"スズ",118.710),"Sb":(51,"アンチモン",121.760),"Te":(52,"テルル",127.60)
,"I":(53,"ヨウ素",126.90447),"Xe":(54,"キセノン",131.293),"Cs":(55,"セシウム",132.90545),"Ba":(56,"バリウム",137.327)
,"La":(57,"ランタン",138.9055),"Ce":(58,"セリウム",140.116),"Pr":(59,"プラセオジム",140.90765),"Nd":(60,"ネオジム",144.24),
"Pm":(61,"プロメチウム",145),"Sm":(62,"サマリウム",150.36),"Eu":(63,"ユウロピウム",151.964),
"Gd":(64,"ガドリニウム",157.25),"Tb":(65,"テルビウム",158.92534),"Dy":(66,"ジスプロシウム",162.500),"Ho":(67,"ホルミウム",164.93032)
,"Er":(68,"エルビウム",167.93032),"Tm":(69,"ツリウム",168.93421),"Yb":(70,"イッテルビウム",173.04),"Lu":(71,"ルテチウム",174.967)
,"Hf":(72,"ハフニウム",178.49),"Ta":(73,"タンタル",180.9479),"W":(74,"タングステン",183,84),"Re":(75,"レニウム",186.207),
"Os":(76,"オスミウム",190.23),"Ir":(77,"イリジウム",192.217),"Pt":(78,"プラチナ(白金)",195.078),"Au":(79,"金",196.96655),"Hg":(80,"水銀",200.59)
,"Tl":(81,"タリウム",204.3833),"Pb":(82,"鉛",207.2),"Bi":(83,"ビスマス",208.98038),"Po":(84,"ポロニウム",209),"At":(85,"アスタチン",210)
,"Rn":(86,"ラドン",222),"Fr":(87,"フランシウム",223),"Ra":(88,"ラジウム",226),"Ac":(89,"アクチニウム",227),
"Th":(90,"トリウム",232.0381),"Pa":(91,"プロトアクチニウム",231.03588),"U":(92,"ウラン",238.02891),"Np":(93,"ネプツニウム",237)
,"Pu":(94,"プルトニウム",244),"Am":(95,"アメリシウム",243),"Cm":(96,"キュリウム",247),"Bk":(97,"バークリウム",247),
"Cf":(98,"カリホルニウム",251),"Es":(99,"アインスタイニウム",252),"Fm":(100,"フェルミウム",257,),"Md":(101,"メンデレビウム",258)
,"No":(102,"ノーベリウム",259),"Lr":(103,"ローレンシウム",262),"Rf":(104,"ラザホージウム",261),"Db":(105,"ドブニウム",262),"Sg":(106,"シーボーギウム",266)
,"Bh":(107,"ボーリウム",264),"Hs":(108,"ハッシウム",269),"Mt":(109,"マイトネリウム",268),"Ds":(110,"ダームスタチウム",271),"Rg":(111,"レントゲニウム",272)
,"Cn":(112,"コペルニシウム",285),"Nh":(113,"ニホニウム",286),"Fl":(114,"フレロビウム",289),"Mc":(115,"モスコビウム",290),"Lv":(116,"リバモリウム",293)
,"Ts":(117,"テネシン",294),"Og":(118,"オガネソン",294)}

 

⑧Widget変数を設定しよう

ボタンを押したときに原子の情報を表示するために、

原子番号、原子名、質量用の変数を作成します。

下記関数をPeriodicTableAppに作成し、_init_のself.create_widgets()の前で呼び出しましょう。

def init_variables(self):
        self.number = IntVar()
        self.name = StringVar()
        self.mass = DoubleVar()

また、各Widget用変数を対象のWidgetに与えましょう。

追加後のサンプルコード

from tkinter import *
from tkinter import ttk


PERIODIC_TABLE_LIST=[
{1:"H",18:"He"},
{1:"Li",2:"Be",13:"B",14:"C",15:"N",16:"O",17:"F",18:"Ne"},
{1:"Na",2:"Mg",13:"Al",14:"Si",15:"P",16:"S",17:"Cl",18:"Ar"},
{1:"K",2:"Ca",3:"Sc",4:"Tl",5:"V",6:"Cr",7:"Mn",8:"Fe",
9:"Co",10:"Ni",11:"Cu",12:"Zn",13:"Ga",14:"Ge",15:"As",16:"Se",17:"Br",18:"Kr"},
{1:"Rb",2:"Sr",3:"Y",4:"Zr",5:"Nb",6:"Mo",7:"Tc",8:"Ru",
9:"Rh",10:"Pd",11:"Ag",12:"Cd",13:"In",14:"Sn",15:"Sb",16:"Te",17:"I",18:"Xe"},
{1:"Cs",2:"Ba",4:"Hf",5:"Ta",6:"W",7:"Re",8:"Os",
9:"Ir",10:"Pt",11:"Au",12:"Hg",13:"Tl",14:"Pb",15:"Bi",16:"Po",17:"At",18:"Rn"},
{1:"Fr",2:"Ra",4:"Rf",5:"Db",6:"Sg",7:"Bh",8:"Hs",
9:"Mt",10:"Ds",11:"Rg",12:"Cn",13:"Nh",14:"Fl",15:"Mc",16:"Lv",17:"Ts",18:"Og"},
{},
{4:"La",5:"Ce",6:"Pr",7:"Nd",8:"Pm",
9:"Sm",10:"Eu",11:"Gd",12:"Tb",13:"Dy",14:"Ho",15:"Er",16:"Tm",17:"Yb",18:"Lu"},
{4:"Ac",5:"Ta",6:"Pa",7:"U",8:"Np",
9:"Pu",10:"Am",11:"Cm",12:"Bk",13:"Cf",14:"Es",15:"Fm",16:"Md",17:"No",18:"Lr"}
]
class PeriodicTable(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=5)
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        for vr in range(0,10):
            for hr in range(0,18):
                name = PERIODIC_TABLE_LIST[vr].get(hr + 1)
                if name is None:
                    label = ttk.Label(self)
                    label.grid(column=hr,row=vr,sticky=(N, W, E, S))
                else:
                    button = ttk.Button(self,text=name)
                    button.grid(column=hr,row=vr,sticky=(N, W, E, S))


class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        self.init_variables()
        self.create_widgets()

    def init_variables(self):
        self.number = IntVar()
        self.name = StringVar()
        self.mass = DoubleVar()


    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()

        atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
        atomNumlabel.pack(side="left")
        atomNumentry = ttk.Entry(atomInfoFrame,textvariable=self.number)
        atomNumentry.pack(side="left")

        label = ttk.Label(atomInfoFrame,text="Name:")
        label.pack(side="left")
        entry = ttk.Entry(atomInfoFrame,textvariable=self.name)
        entry.pack(side="left")
        masslabel = ttk.Label(atomInfoFrame,text="Mass:")
        masslabel.pack(side="left")
        massentry = ttk.Entry(atomInfoFrame,textvariable=self.mass)
        massentry.pack(side="left")

        PeriodicTable(self)


if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)

    master.mainloop()

 

⑨ボタンにイベントを登録しよう!

・まずWidget変数を周期表から参照できるように、PeriodicTableの__init__の引数を増やします。

PeriodicTableの__init__を下記のように変更してください。

def __init__(self,master,number,name,mass):
        super().__init__(master,borderwidth=5)
        self.pack()
        self.number =number
        self.name  = name
        self.mass = mass
        self.create_widgets()

またPeriodicTable呼び出しも下記に修正してください

PeriodicTable(self,self.number,self.name,self.mass)

・次に、Button名をキーにして原子の情報を取得するため、bind(event,func)関数を使用してeventを登録します。

下記の関数をPeriodicTableに追加してください

def selectAtom(self,event):
        symname =event.widget["text"]
        number,name,mass = ATOMS_INFO.get(symname)
        self.number.set(number)
        self.name.set(name)
        self.mass.set(mass)

bind関数を使うことで、対象のイベントを登録したWidgetを取得できます。(第2引数のeventに情報が入ります)

event.widget[“text”]でボタンの名前を取得しています。

またbuttonの作成部分も下記に修正してください

else:
     button = ttk.Button(self,text=name)
     button.bind("<Button-1>",self.selectAtom)
     button.grid(column=hr,row=vr,sticky=(N, W, E, S))

“<Button-1>”はボタンを左クリックするときに起きるイベントです。

今回の場合、左クリックをすることでselectAtomが実行されます。

では実行してみましょう。

periodictablesample_3

試しにどこかをクリックしてみてください。情報が表示されていると思います。

追加後のサンプルコード

from tkinter import *
from tkinter import ttk

# 原子の情報(原子名をキーに原子番号、原子名、質量を取得できる)
ATOMS_INFO ={
"H":(1,"水素",1.00794),"He":(2,"ヘリウム",4.002602),"Li":(3,"リチウム",6.941),"Be":(4,"ベリリウム",9.012182),"B":(5,"ホウ素",10.811)
,"C":(6,"炭素",12.0107),"N":(7,"窒素",14.00674),"O":(8,"酸素",15.9994),"F":(9,"フッ素",18.9984032),"Ne":(10,"ネオン",20.1797),"Na":(11,"ナトリウム",22.989770)
,"Mg":(12,"マグネシウム",24.3050),"Al":(13,"アルミニウム",26.981538),"Si":(14,"ケイ素",28.0855),"P":(15,"リン",30.973761),"S":(16,"硫黄",32.066)
,"Cl":(17,"塩素",35.453),"Ar":(18,"アルゴン",39.948),"K":(19,"カリウム",39.0983),"Ca":(20,"カルシウム",40.078),"Sc":(21,"スカンジウム",44.955910),
"Ti":(22,"チタン",47.867),"V":(23,"バナジウム",50.9415),"Cr":(24,"クロム",51.9961),"Mn":(25,"マンガン",54.938049),"Fe":(26,"鉄",55.8457),
"Co":(27,"コバルト",58.933200),"Ni":(28,"ニッケル",58.6934),"Cu":(29,"銅",63.546),"Zn":(30,"亜鉛",65.409),"Ga":(31,"ガリウム",69.723)
,"Ge":(32,"ゲルマニウム",72.64),"As":(33,"ヒ素",74.92160),"Se":(34,"セレン",78.96),"Br":(35,"臭素",79.904),"Kr":(36,"クリプトン",83.798),
"Rb":(37,"ルビジウム",85.4678),"Sr":(38,"ストロンチウム",87.62),"Y":(39,"イットリウム",88.90585),"Zr":(40,"ジルコニウム",91.224)
,"Nb":(41,"ニオブ",92.90638),"Mo":(42,"モリブデン",95.94),"Tc":(43,"テクネチウム",98),"Ru":(44,"ルテニウム",101.07),
"Rh":(45,"ロジウム",102.90550),"Pd":(46,"パラジウム",106.42),"Ag":(47,"銀",107.8682),"Cd":(48,"カドミウム",112.411),
"In":(49,"インジウム",114.818),"Sn":(50,"スズ",118.710),"Sb":(51,"アンチモン",121.760),"Te":(52,"テルル",127.60)
,"I":(53,"ヨウ素",126.90447),"Xe":(54,"キセノン",131.293),"Cs":(55,"セシウム",132.90545),"Ba":(56,"バリウム",137.327)
,"La":(57,"ランタン",138.9055),"Ce":(58,"セリウム",140.116),"Pr":(59,"プラセオジム",140.90765),"Nd":(60,"ネオジム",144.24),
"Pm":(61,"プロメチウム",145),"Sm":(62,"サマリウム",150.36),"Eu":(63,"ユウロピウム",151.964),
"Gd":(64,"ガドリニウム",157.25),"Tb":(65,"テルビウム",158.92534),"Dy":(66,"ジスプロシウム",162.500),"Ho":(67,"ホルミウム",164.93032)
,"Er":(68,"エルビウム",167.93032),"Tm":(69,"ツリウム",168.93421),"Yb":(70,"イッテルビウム",173.04),"Lu":(71,"ルテチウム",174.967)
,"Hf":(72,"ハフニウム",178.49),"Ta":(73,"タンタル",180.9479),"W":(74,"タングステン",183,84),"Re":(75,"レニウム",186.207),
"Os":(76,"オスミウム",190.23),"Ir":(77,"イリジウム",192.217),"Pt":(78,"プラチナ(白金)",195.078),"Au":(79,"金",196.96655),"Hg":(80,"水銀",200.59)
,"Tl":(81,"タリウム",204.3833),"Pb":(82,"鉛",207.2),"Bi":(83,"ビスマス",208.98038),"Po":(84,"ポロニウム",209),"At":(85,"アスタチン",210)
,"Rn":(86,"ラドン",222),"Fr":(87,"フランシウム",223),"Ra":(88,"ラジウム",226),"Ac":(89,"アクチニウム",227),
"Th":(90,"トリウム",232.0381),"Pa":(91,"プロトアクチニウム",231.03588),"U":(92,"ウラン",238.02891),"Np":(93,"ネプツニウム",237)
,"Pu":(94,"プルトニウム",244),"Am":(95,"アメリシウム",243),"Cm":(96,"キュリウム",247),"Bk":(97,"バークリウム",247),
"Cf":(98,"カリホルニウム",251),"Es":(99,"アインスタイニウム",252),"Fm":(100,"フェルミウム",257,),"Md":(101,"メンデレビウム",258)
,"No":(102,"ノーベリウム",259),"Lr":(103,"ローレンシウム",262),"Rf":(104,"ラザホージウム",261),"Db":(105,"ドブニウム",262),"Sg":(106,"シーボーギウム",266)
,"Bh":(107,"ボーリウム",264),"Hs":(108,"ハッシウム",269),"Mt":(109,"マイトネリウム",268),"Ds":(110,"ダームスタチウム",271),"Rg":(111,"レントゲニウム",272)
,"Cn":(112,"コペルニシウム",285),"Nh":(113,"ニホニウム",286),"Fl":(114,"フレロビウム",289),"Mc":(115,"モスコビウム",290),"Lv":(116,"リバモリウム",293)
,"Ts":(117,"テネシン",294),"Og":(118,"オガネソン",294)}
#
PERIODIC_TABLE_LIST=[
{1:"H",18:"He"},
{1:"Li",2:"Be",13:"B",14:"C",15:"N",16:"O",17:"F",18:"Ne"},
{1:"Na",2:"Mg",13:"Al",14:"Si",15:"P",16:"S",17:"Cl",18:"Ar"},
{1:"K",2:"Ca",3:"Sc",4:"Tl",5:"V",6:"Cr",7:"Mn",8:"Fe",
9:"Co",10:"Ni",11:"Cu",12:"Zn",13:"Ga",14:"Ge",15:"As",16:"Se",17:"Br",18:"Kr"},
{1:"Rb",2:"Sr",3:"Y",4:"Zr",5:"Nb",6:"Mo",7:"Tc",8:"Ru",
9:"Rh",10:"Pd",11:"Ag",12:"Cd",13:"In",14:"Sn",15:"Sb",16:"Te",17:"I",18:"Xe"},
{1:"Cs",2:"Ba",4:"Hf",5:"Ta",6:"W",7:"Re",8:"Os",
9:"Ir",10:"Pt",11:"Au",12:"Hg",13:"Tl",14:"Pb",15:"Bi",16:"Po",17:"At",18:"Rn"},
{1:"Fr",2:"Ra",4:"Rf",5:"Db",6:"Sg",7:"Bh",8:"Hs",
9:"Mt",10:"Ds",11:"Rg",12:"Cn",13:"Nh",14:"Fl",15:"Mc",16:"Lv",17:"Ts",18:"Og"},
{},
{4:"La",5:"Ce",6:"Pr",7:"Nd",8:"Pm",
9:"Sm",10:"Eu",11:"Gd",12:"Tb",13:"Dy",14:"Ho",15:"Er",16:"Tm",17:"Yb",18:"Lu"},
{4:"Ac",5:"Ta",6:"Pa",7:"U",8:"Np",
9:"Pu",10:"Am",11:"Cm",12:"Bk",13:"Cf",14:"Es",15:"Fm",16:"Md",17:"No",18:"Lr"}
]
class PeriodicTable(ttk.Frame):

    def __init__(self,master,number,name,mass):
        super().__init__(master,borderwidth=5)
        self.pack()
        self.number =number
        self.name  = name
        self.mass = mass
        self.create_widgets()

    def create_widgets(self):
        for vr in range(0,10):
            for hr in range(0,18):
                name = PERIODIC_TABLE_LIST[vr].get(hr + 1)
                if name is None:
                    label = ttk.Label(self)
                    label.grid(column=hr,row=vr,sticky=(N, W, E, S))
                else:
                    button = ttk.Button(self,text=name)
                    button.bind("<Button-1>",self.selectAtom)
                    button.grid(column=hr,row=vr,sticky=(N, W, E, S))

    def selectAtom(self,event):
        symname =event.widget["text"]
        number,name,mass = ATOMS_INFO.get(symname)
        self.number.set(number)
        self.name.set(name)
        self.mass.set(mass)


class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        self.init_variables()
        self.create_widgets()

    def init_variables(self):
        self.number = IntVar()
        self.name = StringVar()
        self.mass = DoubleVar()


    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()

        atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
        atomNumlabel.pack(side="left")
        atomNumentry = ttk.Entry(atomInfoFrame,textvariable=self.number)
        atomNumentry.pack(side="left")

        label = ttk.Label(atomInfoFrame,text="Name:")
        label.pack(side="left")
        entry = ttk.Entry(atomInfoFrame,textvariable=self.name)
        entry.pack(side="left")
        masslabel = ttk.Label(atomInfoFrame,text="Mass:")
        masslabel.pack(side="left")
        massentry = ttk.Entry(atomInfoFrame,textvariable=self.mass)
        massentry.pack(side="left")

        PeriodicTable(self,self.number,self.name,self.mass)





if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)

    master.mainloop()

⑩原子記号も情報表示に追加しよう!

下記の手順で作成してみてください。

1.原子記号用Labelと、原子記号表示Entryを作成(親にはatomInfoFrameを指定する)

2.ボタンが押されたときに原子記号を取得するため、Widget変数を作成設定する。

3.PeriodicTableの__init__の引数を追加する。

4.selectAtomでATOMS_INFOのキーに使用しているボタン名を原子記号表示用のWidget変数に設定する

 

実装後

periodictablesample_4

サンプルコード

from tkinter import *
from tkinter import ttk

# 原子の情報(原子名をキーに原子番号、原子名、質量を取得できる)
ATOMS_INFO ={
"H":(1,"水素",1.00794),"He":(2,"ヘリウム",4.002602),"Li":(3,"リチウム",6.941),"Be":(4,"ベリリウム",9.012182),"B":(5,"ホウ素",10.811)
,"C":(6,"炭素",12.0107),"N":(7,"窒素",14.00674),"O":(8,"酸素",15.9994),"F":(9,"フッ素",18.9984032),"Ne":(10,"ネオン",20.1797),"Na":(11,"ナトリウム",22.989770)
,"Mg":(12,"マグネシウム",24.3050),"Al":(13,"アルミニウム",26.981538),"Si":(14,"ケイ素",28.0855),"P":(15,"リン",30.973761),"S":(16,"硫黄",32.066)
,"Cl":(17,"塩素",35.453),"Ar":(18,"アルゴン",39.948),"K":(19,"カリウム",39.0983),"Ca":(20,"カルシウム",40.078),"Sc":(21,"スカンジウム",44.955910),
"Ti":(22,"チタン",47.867),"V":(23,"バナジウム",50.9415),"Cr":(24,"クロム",51.9961),"Mn":(25,"マンガン",54.938049),"Fe":(26,"鉄",55.8457),
"Co":(27,"コバルト",58.933200),"Ni":(28,"ニッケル",58.6934),"Cu":(29,"銅",63.546),"Zn":(30,"亜鉛",65.409),"Ga":(31,"ガリウム",69.723)
,"Ge":(32,"ゲルマニウム",72.64),"As":(33,"ヒ素",74.92160),"Se":(34,"セレン",78.96),"Br":(35,"臭素",79.904),"Kr":(36,"クリプトン",83.798),
"Rb":(37,"ルビジウム",85.4678),"Sr":(38,"ストロンチウム",87.62),"Y":(39,"イットリウム",88.90585),"Zr":(40,"ジルコニウム",91.224)
,"Nb":(41,"ニオブ",92.90638),"Mo":(42,"モリブデン",95.94),"Tc":(43,"テクネチウム",98),"Ru":(44,"ルテニウム",101.07),
"Rh":(45,"ロジウム",102.90550),"Pd":(46,"パラジウム",106.42),"Ag":(47,"銀",107.8682),"Cd":(48,"カドミウム",112.411),
"In":(49,"インジウム",114.818),"Sn":(50,"スズ",118.710),"Sb":(51,"アンチモン",121.760),"Te":(52,"テルル",127.60)
,"I":(53,"ヨウ素",126.90447),"Xe":(54,"キセノン",131.293),"Cs":(55,"セシウム",132.90545),"Ba":(56,"バリウム",137.327)
,"La":(57,"ランタン",138.9055),"Ce":(58,"セリウム",140.116),"Pr":(59,"プラセオジム",140.90765),"Nd":(60,"ネオジム",144.24),
"Pm":(61,"プロメチウム",145),"Sm":(62,"サマリウム",150.36),"Eu":(63,"ユウロピウム",151.964),
"Gd":(64,"ガドリニウム",157.25),"Tb":(65,"テルビウム",158.92534),"Dy":(66,"ジスプロシウム",162.500),"Ho":(67,"ホルミウム",164.93032)
,"Er":(68,"エルビウム",167.93032),"Tm":(69,"ツリウム",168.93421),"Yb":(70,"イッテルビウム",173.04),"Lu":(71,"ルテチウム",174.967)
,"Hf":(72,"ハフニウム",178.49),"Ta":(73,"タンタル",180.9479),"W":(74,"タングステン",183,84),"Re":(75,"レニウム",186.207),
"Os":(76,"オスミウム",190.23),"Ir":(77,"イリジウム",192.217),"Pt":(78,"プラチナ(白金)",195.078),"Au":(79,"金",196.96655),"Hg":(80,"水銀",200.59)
,"Tl":(81,"タリウム",204.3833),"Pb":(82,"鉛",207.2),"Bi":(83,"ビスマス",208.98038),"Po":(84,"ポロニウム",209),"At":(85,"アスタチン",210)
,"Rn":(86,"ラドン",222),"Fr":(87,"フランシウム",223),"Ra":(88,"ラジウム",226),"Ac":(89,"アクチニウム",227),
"Th":(90,"トリウム",232.0381),"Pa":(91,"プロトアクチニウム",231.03588),"U":(92,"ウラン",238.02891),"Np":(93,"ネプツニウム",237)
,"Pu":(94,"プルトニウム",244),"Am":(95,"アメリシウム",243),"Cm":(96,"キュリウム",247),"Bk":(97,"バークリウム",247),
"Cf":(98,"カリホルニウム",251),"Es":(99,"アインスタイニウム",252),"Fm":(100,"フェルミウム",257,),"Md":(101,"メンデレビウム",258)
,"No":(102,"ノーベリウム",259),"Lr":(103,"ローレンシウム",262),"Rf":(104,"ラザホージウム",261),"Db":(105,"ドブニウム",262),"Sg":(106,"シーボーギウム",266)
,"Bh":(107,"ボーリウム",264),"Hs":(108,"ハッシウム",269),"Mt":(109,"マイトネリウム",268),"Ds":(110,"ダームスタチウム",271),"Rg":(111,"レントゲニウム",272)
,"Cn":(112,"コペルニシウム",285),"Nh":(113,"ニホニウム",286),"Fl":(114,"フレロビウム",289),"Mc":(115,"モスコビウム",290),"Lv":(116,"リバモリウム",293)
,"Ts":(117,"テネシン",294),"Og":(118,"オガネソン",294)}
#
PERIODIC_TABLE_LIST=[
{1:"H",18:"He"},
{1:"Li",2:"Be",13:"B",14:"C",15:"N",16:"O",17:"F",18:"Ne"},
{1:"Na",2:"Mg",13:"Al",14:"Si",15:"P",16:"S",17:"Cl",18:"Ar"},
{1:"K",2:"Ca",3:"Sc",4:"Tl",5:"V",6:"Cr",7:"Mn",8:"Fe",
9:"Co",10:"Ni",11:"Cu",12:"Zn",13:"Ga",14:"Ge",15:"As",16:"Se",17:"Br",18:"Kr"},
{1:"Rb",2:"Sr",3:"Y",4:"Zr",5:"Nb",6:"Mo",7:"Tc",8:"Ru",
9:"Rh",10:"Pd",11:"Ag",12:"Cd",13:"In",14:"Sn",15:"Sb",16:"Te",17:"I",18:"Xe"},
{1:"Cs",2:"Ba",4:"Hf",5:"Ta",6:"W",7:"Re",8:"Os",
9:"Ir",10:"Pt",11:"Au",12:"Hg",13:"Tl",14:"Pb",15:"Bi",16:"Po",17:"At",18:"Rn"},
{1:"Fr",2:"Ra",4:"Rf",5:"Db",6:"Sg",7:"Bh",8:"Hs",
9:"Mt",10:"Ds",11:"Rg",12:"Cn",13:"Nh",14:"Fl",15:"Mc",16:"Lv",17:"Ts",18:"Og"},
{},
{4:"La",5:"Ce",6:"Pr",7:"Nd",8:"Pm",
9:"Sm",10:"Eu",11:"Gd",12:"Tb",13:"Dy",14:"Ho",15:"Er",16:"Tm",17:"Yb",18:"Lu"},
{4:"Ac",5:"Ta",6:"Pa",7:"U",8:"Np",
9:"Pu",10:"Am",11:"Cm",12:"Bk",13:"Cf",14:"Es",15:"Fm",16:"Md",17:"No",18:"Lr"}
]
class PeriodicTable(ttk.Frame):

    def __init__(self,master,number,symbol,name,mass):
        super().__init__(master,borderwidth=5)
        self.pack()
        self.number =number
        self.symbol =symbol
        self.name  = name
        self.mass = mass
        self.create_widgets()

    def create_widgets(self):
        for vr in range(0,10):
            for hr in range(0,18):
                name = PERIODIC_TABLE_LIST[vr].get(hr + 1)
                if name is None:
                    label = ttk.Label(self)
                    label.grid(column=hr,row=vr,sticky=(N, W, E, S))
                else:
                    button = ttk.Button(self,text=name)
                    button.bind("<Button-1>",self.selectAtom)
                    button.grid(column=hr,row=vr,sticky=(N, W, E, S))
    def selectAtom(self,event):
        symname =event.widget["text"]
        number,name,mass = ATOMS_INFO.get(symname)
        self.number.set(number)
        self.symbol.set(symname)
        self.name.set(name)
        self.mass.set(mass)


class PeriodicTableApp(ttk.Frame):

    def __init__(self,master):
        super().__init__(master,borderwidth=10)
        self.pack()
        self.init_variables()
        self.create_widgets()

    def init_variables(self):
        self.number = IntVar()
        self.symbol = StringVar()
        self.name = StringVar()
        self.mass = DoubleVar()


    def create_widgets(self):
        atomInfoFrame = ttk.Frame(self)
        atomInfoFrame.pack()

        atomNumlabel = ttk.Label(atomInfoFrame,text="Number:")
        atomNumlabel.pack(side="left")
        atomNumentry = ttk.Entry(atomInfoFrame,textvariable=self.number)
        atomNumentry.pack(side="left")

        atomSymlabel = ttk.Label(atomInfoFrame ,text="Symbol:")
        atomSymlabel.pack(side="left")
        atomSymentry = ttk.Entry(atomInfoFrame ,textvariable=self.symbol)
        atomSymentry.pack(side="left")

        label = ttk.Label(atomInfoFrame,text="Name:")
        label.pack(side="left")
        entry = ttk.Entry(atomInfoFrame,textvariable=self.name)
        entry.pack(side="left")

        masslabel = ttk.Label(atomInfoFrame,text="Mass:")
        masslabel.pack(side="left")
        massentry = ttk.Entry(atomInfoFrame,textvariable=self.mass)
        massentry.pack(side="left")

        PeriodicTable(self,self.number,self.symbol,self.name,self.mass)





if __name__ == '__main__':
    master = Tk()
    master.title("PeriodicTable Sample")
    master.geometry("1400x400")
    PeriodicTableApp(master)

    master.mainloop()

 

あわせて読みたい