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

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

新規登録して質問してみよう
ただいま回答率
85.30%
Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2941閲覧

画像がボタンに表示されない

bell-chako

総合スコア12

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/02/21 23:01

Pythonを始めたばかりの初心者です。自分で作った画像をボタンにはめ込みたいのですが、ボタン枠のみしか表示されず、画像が表示されません。アドバイス、よろしくお願いいたします。

class

1 2 def __init__(self, parent, controller): 3 tk.Frame.__init__(self, parent) 4 self.controller = controller 5 self.configure(bg="#014cc4") 6 7 button_Sw = tk.Button(self,bg="white",width=40, height=40) 8 button_Sw.pack() 9 switch_button_image = tk.PhotoImage(file="./switch.png") 10 button_Sw.configure(image=switch_button_image) 11 button_Sw.place(x=19, y=10) 12 13 14 button_Se = tk.Button(self,bg="white", width=40, height=40) 15 button_Se.pack() 16 setting_button_image = tk.PhotoImage(file="./setting.png") 17 button_Se.config(image=setting_button_image) 18 button_Se.place(x=250, y=10) 19 20コード

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

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

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

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

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

stdio

2019/02/22 00:38

switch_button_image = tk.PhotoImage(file="./switch.png") のファイル名を間違えている可能性がありますね。 switch_button_image = tk.PhotoImage(file="..\switch.png") もし違っていたらすみません。ですが一回、switch_button_imageの中身を確認した方が良さそうです。
guest

回答1

0

ベストアンサー

python

1... 2switch_button_image = tk.PhotoImage(file="./switch.png") 3button_Sw.configure(image=switch_button_image) 4...

tkinterのPhotoImageは「画像を表示しつづけている間、アプリケーションでPhotoImageインスタンスの参照をどこかにキープしておかなければならない」というちょっとわかりにくい仕様があったと思います。今のコードでインスタンスの参照を保持しているのはswitch_button_image変数ですが、この変数は__init__メソッドのローカル変数なのでメソッド完了後はなくなってしまいます。つまりその時点でPhotoImageインスタンスの参照を保持している変数がなくなりtkinterが画像を表示する前提がくずれてしまうのではないかと想像します。

対処として

python

1... 2self.switch_button_image = tk.PhotoImage(file="./switch.png") 3button_Sw.configure(image=self.switch_button_image) 4...

のようにインスタンス変数に格納してはいかがでしょうか?
こうしておけばこのクラス(おそらくFrameの派生クラス)のインスタンスがなくならない限りPhotoImageインスタンスの参照がずっと残るので期待どおりに画像が表示されるのではないかと想像します。

すみませんが、今、自分で確認する時間がないので違ってたらごめんなさい。


追記:

実際にやってみましたが元の回答で書いたことは正しそうです。しかしながらご質問のコードは一部しか書かれておらず、書き方によって上記の問題以前にボタン自体が表示されないという不具合がおきそうです。以下のコードで確認してみました。

Python

1import tkinter as tk 2 3 4class MyFrame(tk.Frame): 5 # 問題とは無関係な冗長な記述をより短い記述に書き換えてます 6 def __init__(self, parent, controller): 7 tk.Frame.__init__(self, parent, bg='#014cc4') 8 self.controller = controller 9 10 switch_button_image = tk.PhotoImage(file="./switch.png") 11 button_Sw = tk.Button(self, image=switch_button_image, bg="white", width=40, height=40) 12 button_Sw.pack() 13 button_Sw.place(x=19, y=10) 14 15 setting_button_image = tk.PhotoImage(file="./setting.png") 16 button_Se = tk.Button(self, image=setting_button_image, bg="white", width=40, height=40) 17 button_Se.pack() 18 button_Se.place(x=250, y=10) 19 20 21def report(ev): 22 w = ev.widget 23 print(f'widget:{w}, width={w.winfo_width()}, height={w.winfo_height()}') 24 25 26root = tk.Tk() 27root.bind_all('<Configure>', report) 28root.geometry('400x400') 29frame = MyFrame(root, object()) 30frame.pack() 31root.mainloop()

上記を実行するとMyFrameの大きさは1x1にしかならず、配置した2つのボタンはMyFrameの領域外に位置付けられてしまいボタン自体が見えなくなることがわかります。こうなる原因はウィジェットのレイアウト方法がおかしいからです。

MyFrameの画面構成を決めているのはMyFrameの__init__メソッドですが、MyFrameのレイアウト方法は次のいずれかの方針とすべきです。(gridも選択肢になりますがその方法については言及しません)

(1) MyFrameの大きさを明示的に指定しておき、その上で各Buttonなどをplaceで配置
(2) 子供をpackで配置してMyFrameの大きさは子供の位置や大きさに応じて自動的に決める

元のコードでは(1),(2)のどちらでもなくpackとplaceを両方使ってます。placeを呼び出すとpackの効果はなくなりますのでpackしてないことと同義になります。
レイアウトのしかたは慣れないと混乱しがちです。例えば
http://www.shido.info/py/tkinter2.html
のような解説をよく読むとよいとおもいます。


「なぜうまくいかないか」について説明を試みましたがちょっと難しいかも知れませんので、最後に「うまく表示される簡単なコード例」を示しておきます。

python

1import tkinter as tk 2 3 4class MyFrame(tk.Frame): 5 def __init__(self, parent, controller): 6 # Frameのサイズを明示的に指定する 7 tk.Frame.__init__(self, parent, width=400, height=400, bg='#014cc4') 8 self.controller = controller 9 10 switch_button_image = tk.PhotoImage(file="./switch.png") 11 button_Sw = tk.Button(self, image=switch_button_image, bg="white", width=40, height=40) 12 button_Sw.place(x=19, y=10) 13 self.switch_button_image = switch_button_image # 画像インスタンスの参照を覚えておく 14 15 setting_button_image = tk.PhotoImage(file="./setting.png") 16 button_Se = tk.Button(self, image=setting_button_image, bg="white", width=40, height=40) 17 button_Se.place(x=250, y=10) 18 self.setting_button_image = setting_button_image # 画像インスタンスの参照を覚えておく 19 20 21root = tk.Tk() 22frame = MyFrame(root, object()) 23frame.pack() 24root.mainloop()

投稿2019/02/22 05:17

編集2019/02/22 13:40
KSwordOfHaste

総合スコア18404

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

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

bell-chako

2019/02/22 15:56

ご丁寧な解説とコード例の添付、ありがとうございました。こちらのコード例で無事に画像とボタンが表示されました。レイアウトの仕方をもっと勉強します。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問