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

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

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

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

Tkinter

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

Python

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

Q&A

解決済

tag_bindで関数内関数を呼び出した後、外側の関数が機能しなくなってしまう。

ppap
ppap

総合スコア68

Anaconda

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

Tkinter

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

Python

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

1回答

0グッド

0クリップ

244閲覧

投稿2022/09/01 02:37

前提

pythonのtkinterおよびpillowを用いて、クリックにより画像を回転させるコードを作成しています。
画面をクリックすることで画像が無限に左回転を続け、再度クリックをすると画面の回転がストップします。

実現したいこと

2度目のクリックで画像の回転を止めた後、3度目のクリックでは画像の回転を再開させたいと考えています。
(奇数回目のクリックで画像を回転させ、偶数回目のクリックでは回転をストップさせたい。)

しかし、現状のコードでは、3度目のクリックを行っても何も動作しません。
エラーメッセージはなく、他の方法が分からないためアドバイスをいただけないでしょうか。

該当のソースコード

python

1#---測定コード--- 2 3import tkinter as tk 4from PIL import Image, ImageTk 5 6 7#画面サイズの指定 8WIDTH = 1300 9HEIGHT = 800 10 11 12#新規ウィンドウを作成 13root = tk.Tk() 14root.title("SVV測定") 15root.attributes("-fullscreen", True) 16 17 18#ウィンドウ上にフレームを作成 19frame = tk.Frame(root) 20frame.pack() 21 22 23#フレーム上に、キャンバスを作成 24canvas = tk.Canvas(frame, width = WIDTH, height = HEIGHT, bg = "black") 25canvas.pack() 26 27 28#画像のプリセット角を"cs"として定義 29cs = 0 30 31 32#キャンバスにSVV画像を貼り付け 33img = Image.open("D:\EXPERIMENT\programming\Python\SVV\svv_bar.png") 34img = img.rotate(cs) 35tkimg = ImageTk.PhotoImage(img, width = WIDTH, height = HEIGHT) 36canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg, anchor="center", tags="img") 37 38 39#キャンバスに、透明な画像を貼り付け 40img_snow = Image.open("D:\EXPERIMENT\programming\Python\SVV\svv_snow.png") 41tkimg_snow = ImageTk.PhotoImage(img_snow, width = WIDTH, height = HEIGHT) 42canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg_snow, anchor="center", tags="img_snow") 43 44 45#"c"の初期値を定義 46c = 0 47 48 49#イベントが発生したときの処理 50def press_L(event): 51 #左クリックの回数によって、左回転させる 52 global img 53 global tkimg 54 global c 55 global id 56 c = c + 0.1 57 IMG = img.rotate(c) 58 tkimg = ImageTk.PhotoImage(IMG) 59 canvas.create_image(WIDTH/2, HEIGHT/2, image = tkimg, anchor = "center", tags = "img") 60 canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg_snow, anchor = "center", tags="img_snow") 61 id = root.after(1, press_L, None) 62 def stop_L(event): 63 #左クリックで、左回転をストップする 64 root.after_cancel(id) 65 canvas.tag_bind("img_snow", "<ButtonPress-1>", stop_L) 66 67 68def press_R(event): 69 #右クリックの回数によって、右回転させる 70 global img 71 global tkimg 72 global c 73 global id 74 c = c - 0.1 75 IMG = img.rotate(c) 76 tkimg = ImageTk.PhotoImage(IMG) 77 canvas.create_image(WIDTH/2, HEIGHT/2, image = tkimg, anchor = "center", tags = "img") 78 canvas.create_image(WIDTH/2, HEIGHT/2, image=tkimg_snow, anchor = "center", tags="img_snow") 79 id = root.after(1, press_R, None) 80 def stop_R(event): 81 #右クリックで、右回転をストップする 82 root.after_cancel(id) 83 canvas.tag_bind("img_snow", "<ButtonPress-3>", stop_R) 84 85 86def finish(event): 87 #Enterキーを押すことで全画面表示を終了し、回転角度を取得する 88 root.destroy() 89 print(c) 90 91 92#左クリックで呼び出すイベント 93canvas.tag_bind("img_snow", "<ButtonPress-1>", press_L) 94 95 96#右クリックで呼び出すイベント 97canvas.tag_bind("img_snow", "<ButtonPress-3>", press_R) 98 99 100#Enterキーで呼び出すイベント 101root.bind("<Return>", finish) 102 103 104#メインループ 105root.mainloop() 106

上記の処理に使用した画像を作成するコード

python

1#---SVV測定に使用する画像の作成--- 2 3from PIL import Image, ImageDraw 4 5#背景色が黒色のキャンパスを作成。 6im = Image.new('RGB', (500, 500), (0, 0, 0)) 7draw = ImageDraw.Draw(im) 8 9 10#中央に線を描画 11draw.line((50, 250, 450, 250), fill=(255, 255, 255), width=10) 12 13 14#同じサイズの画像を作成 15im_clear = Image.new("RGBA", im.size, (0, 0, 0, 0)) 16width = im.size[0] 17height = im.size[1] 18 19 20#色ごとに処理 21for x in range(width): 22 for y in range(height): 23 pixel = im.getpixel( (x, y) ) 24 25 # 黒なら処理しない 26 if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0: 27 continue 28 29 # 黒以外なら、用意した画像にピクセルを書き込み 30 im_clear.putpixel( (x, y), pixel ) 31 32 33#SVVで表示させるバーをpng形式で保存 34im_clear.save("D:\EXPERIMENT\programming\Python\SVV\svv_bar.png", quality=100) 35 36 37 38#---透明なpng画像の作成--- 39 40#画像サイズの指定 41WIDTH = 1500 42HEIGHT = 1000 43 44 45#新しい画像を作成 46im_snow = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) 47 48 49#新しい画像をもう一つ作成 50im_snow2 = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) 51 52 53#色ごとに処理 54for x in range(width): 55 for y in range(height): 56 pixel = im_snow2.getpixel( (x, y) ) 57 58 # 黒なら処理しない 59 if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0: 60 continue 61 62 # 黒以外なら、用意した画像にピクセルを書き込み 63 im_snow.putpixel( (x, y), pixel ) 64 65 66#透明な画像をpng形式で保存 67im_snow.save("D:\EXPERIMENT\programming\Python\SVV\svv_snow.png", quality=100) 68

試したこと

現在、"press_L"というイベントの中に"stop_L"というイベントを設置しています。
"stop_L"を呼び出すtag_bindを関数外に記述したところ、画像の回転を止めることができませんでした。
むしろ、クリックするごとに回転のスピードが上昇する結果に。。

また、ボタンウィジェットを用いて回転をストップさせる方法を試しましたが、
ボタンウィジェットを透明にすることができなかったため、ボタンは使用していません。

補足情報(FW/ツールのバージョンなど)

AnacondaでPythonを使用しています。

・Anacondaのバージョン:conda 4.12.0
・Pythonのバージョン:Python 3.9.12
・Windowsのバージョン:version 21H2

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

1

ベストアンサー

状況やイベント発生で、<ButtonPress-1>に何が設定されているか考えればわかると思います。

起動後: <ButtonPress-1>にpress_L が設定されている

左クリック: press_L が実行される
-> root.after(1, press_L, None) 設定 > 回転開始
-> <ButtonPress-1>にstop_L が設定される。 press_L は消えてしまう。

さらに左クリック: stop_L が実行される。
-> stop_Lが実行される。 回転が止まる。

これだけです。

現象だけみれば、問題の原因は、<ButtonPress-1>にstop_Lがbindされ続けているためです。

対応としては、状況によッて<ButtonPress-1>のときに起きる処理を切り替えることのはずなので、

  1. ボタンを押したら、バインドされている関数をちゃんと切り替える。 stop_Lを押して止めたら、<ButtonPress-1>にpress_L を再設定する。
  2. 関数は1つだけ用意して、その関数で今の状況(回転中かどうか)を確認して、適切な処理を行なうようにする。

のいずれかでしょう。 右回転中に左クリックしたときとかあるので、結果として2がいいんじゃないかな。

あと、id がglobalだけど、LとR で違うオブジェクトにアサインしているので、よくないでしょう。

投稿2022/09/01 04:58

編集2022/09/01 05:14
TakaiY

総合スコア10557

ppap👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

ppap

2022/09/01 05:34

ありがとうございます! 作成したコードだと途中でpress_Lが消えてしまっているんですね。。 2通りの解決方法アイデアに加え、"id"に関する助言までいただき、ありがとうございます。

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Anaconda

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

Tkinter

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

Python

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