質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

button

HTMLで用いる<button>タグです。

Q&A

解決済

1回答

2430閲覧

tkinterでボタンの色を更新できない

sonai

総合スコア47

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

button

HTMLで用いる<button>タグです。

0グッド

0クリップ

投稿2020/05/01 15:18

前提・実現したいこと

tkinterでボタンを押すたびに色が変化するようにしたいのですが、
うまくいきません。

発生している問題・エラーメッセージ

Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\User\Anaconda3\lib\tkinter\__init__.py", line 1702, in __call__ return self.func(*args) File "<ipython-input-16-aa2d88e58cf3>", line 49, in startButtonClick self.button1["bg"] = "red" TypeError: 'NoneType' object does not support item assignment

該当のソースコード

Python3

1class Application(tk.Frame): 2 def __init__(self,master): 3 super().__init__(master) 4 self.pack() 5 6 master.geometry("300x150") 7 master.title("ストップウォッチ") 8 master.config(bg="black") 9 10 self.playTime=False 11 12 #ボタンを設置 13 self.button1 = tk.Button(master,text="Start",command=self.startButtonClick,width=10,bg="lightgreen").place(x=110, y=110) 14 self.button2 = tk.Button(master,text="Stop",command=self.stopButtonClick,width=10,bg="red").place(x=210, y=110) 15 16 master.after(50,self.update) 17 18 def startButtonClick(self): 19 if not self.playTime: 20 self.playTime=True 21 self.button1["bg"] = "red" 22 self.button2["bg"] = "lightgreen" 23 24 def stopButtonClick(self): 25 if self.playTime: 26 #測定終了 27 self.playTime=False 28 self.button1["bg"]="lightgreen" 29 self.button2["bg"] = "red" 30 31 def update(self): 32 self.master.after(50,self.update) 33 34def main(): 35 win = tk.Tk() 36 #win.resizable(width=False, height=False) #ウィンドウを固定サイズに 37 app = Application(master=win) 38 app.mainloop() 39 40if __name__ == "__main__": 41 main()

試したこと

self.button1["bg"] = "red"の代わりに
self.button1.config(bg = "red)やself.button1.widget["bg"] = "red"としても同じエラーが出たので、
self.button1の書き方が良くない気がします。
ボタンを押すたびにbutton1とbutton2が交互に緑と赤で入れ替わるようにしたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

原因:

self.button1の書き方が良くない気がします。

ボタンを押すたびにbutton1とbutton2が交互に緑と赤で入れ替わるようにしたいです。

place() 等のレイアウト関数は値を返さない為、self.button1 が None になってしまいます。

解決策:

python

1#ボタンを設置 2self.button1 = tk.Button(master,text="Start",command=self.startButtonClick,width=10,bg="lightgreen") 3self.button1.place(x=110, y=110) 4self.button2 = tk.Button(master,text="Stop",command=self.stopButtonClick,width=10,bg="red") 5self.button2.place(x=210, y=110)

恐らく、このようなコードが混乱の原因だと思うのですが、
戻り値を変数に受け取らない場合、以下の記法自体はよく使われるコードで、
標準ライブラリ内(idlelib)でも見かけられます。
(ボタンやラベル等で後から参照する必要がない場合)

tk.Button(master,text="Button",command=command).place(x=110, y=110)

解決策2: 名前を付けて nametowidget() 経由でアクセスする

お勧めという訳ではありませんが、別解として紹介。
nameを付けると、後から参照することもできます。

python

1import tkinter as tk 2 3class Application(tk.Frame): 4 def __init__(self,master): 5 super().__init__(master) 6 self.pack() 7 8 master.geometry("300x150") 9 master.title("ストップウォッチ") 10 master.config(bg="black") 11 12 self.playTime=False 13 14 #ボタンを設置 (name=を付ける。注意点は第一引数の親ウィジェット) 15 tk.Button(master,text="Start",name="button1",command=self.startButtonClick,width=10,bg="lightgreen").place(x=110, y=110) 16 tk.Button(master,text="Stop",name="button2",command=self.stopButtonClick,width=10,bg="red").place(x=210, y=110) 17 18 def __getattr__(self, key): 19 """ 20 self.button1 とアクセスされた場合、name="button1" と作成した tk.Button を返します。 21 22 今回は簡単な例なので関係ありませんが、 23 nameの部分は、実際には親ウィジェットからのpathになる点に注意。 24 例えば、第一引数の親が master ではなく self だった場合は、self.nametowidget(key) 25 """ 26 return self.master.nametowidget(key) 27 28 def startButtonClick(self): 29 if not self.playTime: 30 self.playTime=True 31 self.button1["bg"] = "red" 32 self.button2["bg"] = "lightgreen" 33 34 def stopButtonClick(self): 35 if self.playTime: 36 #測定終了 37 self.playTime=False 38 self.button1["bg"]="lightgreen" 39 self.button2["bg"] = "red" 40 41def main(): 42 win = tk.Tk() 43 app = Application(master=win) 44 app.mainloop() 45 46if __name__ == "__main__": 47 main()

追記: 解決策2の案を お勧めしない理由は、nametowidgetでは、動的に探索される為
dir(app) としても属性に button1, button2 は列挙されません。=> IDE等で補完候補に出ない
また、静的解析ツール等にとっても型の解らない属性になるので、デメリットになります。
本当に必要な時以外は、記述が楽になるという理由だけでは採用しない方が良いです。

紹介の意図としては、他にこのような(直接 pack/grid/placeを呼んでいる)コードを見かけた時に、
後々参照の必要がないか、nametowidget()を通じて参照できるという点に留意して、
参考にして頂けたらと思います。

投稿2020/05/01 18:02

編集2020/05/01 19:49
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sonai

2020/05/02 00:55

ご回答ありがとうございます。 また、別解とその短所まで教えていただき感謝いたします。 解決策1で動かすことができました。非常に助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問