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

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

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

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

Q&A

解決済

2回答

1587閲覧

python tkinter canvas 画像の配置について

Platycerium

総合スコア34

Python 3.x

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

0グッド

1クリップ

投稿2018/12/03 16:58

pythonのtkinterのcanvas上に、プリントスクリーンした画像をウインドウサイズに合わせて配置できるコードを書きました。
画像も表示され、目的は達成できているのですが少し気になるところがあります。

配置を実行した後のコードid_list.append(im)のところで
(NameError: name 'id_list' is not defined)のエラーが出ています。
id_listが定義されていないのかと思い、id_list = []を追加すると、
エラーは無くなりますが画像が表示できなくなります。

方法を調べながら作成したものですが、このid_list.append(im)の意味がよくわかっておらず、このコードがないと画像表示ができないため残しています。
エラー表示なく画像を表示するには、どのようにしたら良いでしょうか?

import tkinter as tk from tkinter import * from PIL import Image, ImageTk,ImageGrab import tkinter.messagebox as mb import tkinter.filedialog #id_list = [] def readpic(): haba=window_width.get() im = ImageGrab.grabclipboard() if isinstance(im, Image.Image): width, height = im.size hiritu = int(haba)/width xx =int(width*hiritu) yy =int(height*hiritu) im_resize = im.resize((xx,yy)) im_resize.save('tmp.jpg', 'JPEG', quality=100, optimize=True) img = Image.open("tmp.jpg") new_img = Image.new("RGBA", (width, height), (255, 255, 255)) new_img.paste(img, (0, 0)) image = ImageTk.PhotoImage(new_img) im=cvs.create_image(0, 0, image=image, anchor = tk.NW,tag="gazou") id_list.append(im) else: mb.showinfo("", "クリップボードにデータがありません。") def show_width(event): window_width.delete(0, tk.END) window_width.insert(0, event.width) window = tk.Tk() window.title('サンプル') frame1 = tk.Frame(window,bd=1,relief="ridge") frame1.grid(row=0, column=0,sticky='news') frame2 = tk.Frame(window,bd=1,relief="ridge") frame2.grid(row=2, column=0,sticky='news') btn = tk.Button(frame1, text='クリップボード貼付', command=readpic) btn.pack(side=LEFT) cvs = tk.Canvas(frame2, height=600, width=1000, bg='white',bd=1,relief="ridge") cvs.grid(row=0, column=0,sticky='news') cvs.bind("<Configure>", show_width) window_width = tk.Entry(frame1) window_width.pack(side=RIGHT) frame2.grid_columnconfigure(0,weight=1) frame2.grid_rowconfigure(0,weight=1) window.grid_columnconfigure(0,weight=1) window.grid_rowconfigure(2,weight=1) window.mainloop()

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

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

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

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

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

guest

回答2

0

ベストアンサー

このid_list.append(im)の意味

以下の回答中の「create_imageの仕様の罠」の部分を参照ください。

https://teratail.com/questions/155640#reply-233844

ご質問のコードは何かのサンプルを参考にされたのかも知れません。元のコードがどのような意図でid_listを用いていたかははっきりわかりませんが、少なくともご質問のコードは次のようにすれば期待通りの動作となります。

Python

1...省略 2 3id_list = [] # これは必要。 4 5 6def readpic(): 7 haba = window_width.get() 8 ...省略 9 image = ImageTk.PhotoImage(new_img) 10 im = cvs.create_image(0, 0, image=image, anchor=tk.NW, tag="gazou") 11 # id_list.append(img) # imgの参照を保持する必要はない 12 id_list.append(image) # create_imageの仕様によりimageの参照を保持しておく必要がある。

上記コードでのid_listの目的は「PhotoImageインスタンスの参照を保持しておくためのもの」なので、変数名を例えばphotoimage_referenceなどにしておいた方がよいかも知れません。とはいえcreate_imageの肝心の仕様を把握していないと変数名だけで意図を把握するのは困難です。このわかりにくいコードを書かねばならないならやはり目的をコメントで
# create_imageの仕様によりimageの参照を保持しておく必要がある。
のように書いておいた方がよいと思います。


追記: 言い忘れてましたが、元のコードでid_listが未定義の状態で画像が表示された理由は多分、
(1) readpic関数で例外が発生
(2) Tkinterがコールバック関数での例外を捕捉してエラー内容をレポートする
(3) Tkinterは発生した例外の情報をsysモジュールに「最後に発生した例外」として記録する
(4) (3)により例外発生時のreadpic関数の実行スタックの参照が消えずに残る
(5) (4)によりreadpic関数の全てのローカル変数が消えずに残る
(6) ローカル変数imageの値であるPhotoImageインスタンスの参照が残る
となるからだと思います。要するに「Tkinterの例外処理によりPhotoImageインスタンスの参照が消えずに残る結果となったためたまたま画像が表示された」といえましょう。

投稿2018/12/04 02:05

編集2018/12/04 12:21
KSwordOfHaste

総合スコア18392

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

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

Platycerium

2018/12/04 12:13

とても丁寧にご説明いただきありがとうございました。 おかげでエラーなく動かせることができました。 原因の解説もとても勉強になりました。
hayataka2049

2018/12/04 12:22 編集

>追記 なるほど、納得しました。奥が深い…… # ところで、そういうことなら「global image」とか宣言しておく方がlistに入れるより理にかなっているのでは?
guest

0

id_listは使用されている形跡がありませんが、単にid_list.append(im)を消せば動作したりはしませんか?

奇怪ですが、何かしら例外を投げると動くようですね。単純に消してしまうと駄目で、たとえばraise Exceptionと置き換えると動きます。id_list.append(im)自体に意味はありませんが、NameErrorを投げることでコードを動作させています。

理由はよくわかりませんが、正常な動作ではなさそう。

投稿2018/12/03 20:55

編集2018/12/04 12:44
hayataka2049

総合スコア30933

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

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

Platycerium

2018/12/04 12:16

投稿いただきありがとうございました。 エラーの原因はKSwordOfHasteさんの解説で理解することができました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問