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

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

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

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

Python

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

Q&A

解決済

1回答

1902閲覧

[Python]Tkinterとpynputによる左クリックの検出

lunacommer

総合スコア6

Tkinter

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

Python

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

0グッド

0クリップ

投稿2020/04/14 04:57

編集2020/04/14 08:42

[Python]Tkinterとpynputによる左クリックの検出

Tkinterによって作られたボタンを押すと、クリック検出関数が呼び出されて画面上のクリックを検出(クリックされた座標)したいです。

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

追記:行いたいことは、プログラムは起動したままでの、pynputでのクリック検出の停止です。 スタートボタンとストップボタンによりクリック検出を操作したいです。 スレッドに投げてクリックの検出をしようとしたところ、スレッドの終了方法がわからずにプログラムを正常終了させることができない。 以下のプログラムを実行するとクリックの検出はできている。しかし、作成したウィンドウを消してもスレッドが生きているためプログラムを終了させることができない。Ctrl+Cを押しても無反応です。

該当のソースコード

Python

1import tkinter as tk 2import time 3import threading 4from pynput import mouse 5 6class Application(tk.Frame): 7 thread=None 8 def __init__(self,master): 9 super().__init__(master) 10 self.pack() 11 12 master.geometry("300x150") 13 master.title("クリック検出") 14 15 self.canvas = tk.Canvas(master,width=290,height=80,bg="skyblue") 16 self.canvas.place(x=3,y=10) 17 18 tk.Button(master,text="スタート",command=self.startButtonClick,width=10).place(x=110, y=110) 19 tk.Button(master,text="ストップ",command=self.stopButtonClick,width=10).place(x=210, y=110) 20 21 22 23 def startButtonClick(self): 24 self.alive=True 25 self.started=threading.Event() 26 if self.thread == None: 27 self.thread = threading.Thread(target=click_listen) 28 self.thread.start() 29 30 def stopButtonClick(self): 31 #ここに終了処理をさせる関数を書きたい 32 pass 33 34 35def on_click(x, y, button, pressed): 36 print('{0} at {1}'.format('Pressed' if pressed else 'Released',(int(x), int(y)))) 37 38 39def click_listen(): 40 41 while(True): 42 with mouse.Listener(on_click=on_click) as listener: 43 listener.join() 44 45def main(): 46 win = tk.Tk() 47 app = Application(master=win) 48 app.mainloop() 49 50if __name__ == "__main__": 51 main()

試したこと

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

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

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

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

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

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

t_obara

2020/04/14 07:00

問題は正常終了させることですか?クリックを検出することですか?
lunacommer

2020/04/14 07:28

上記のプログラムを実行すると、クリックの検出はできますが正常終了させることができません。 言葉足らずで申し訳ありません。
teamikl

2020/04/14 08:01

同じ疑問を持ったのですが、 プロセス自体の正常終了でよいのですか? (プログラムは起動したまま) pynput での検出の停止?
lunacommer

2020/04/14 08:43

teamikl様 プログラムは起動したままでのクリック検出の停止です。 上の質問は回答になっておらず、失礼いたしました。
guest

回答1

0

ベストアンサー

ウィンドウを閉じてもスレッドが残り続ける問題

簡単な解決策: daemon=True オプションで、メインスレッドと同時に終了します。

self.thread = threading.Thread(target=click_listen, daemon=True)

公式doc スレッドベースの並列処理

(追記2)
注意点は、強制終了に近いので、終了時に何らかの処理が必要な場合は daemonスレッドにはぜず、
Event 等を通じてスレッドを安全に終了する。


pynput の停止

stopButtonClick内で

  • listener.stop() を呼び出す。クリック検出の停止。
  • self.thread = None (再スタートを出来るようにする為)

問題は、外のclick_listen関数内にある listener をどのように参照するか。
グローバル変数にする、もしくは、click_listen関数はメソッドにして
インスタンス変数経由でアクセスする。

追記:

  • click_listen() の while (True): は取り除きます

ストップした後にまた次のリスナが起動してしまう為。

投稿2020/04/14 08:15

編集2020/04/14 09:06
teamikl

総合スコア8664

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

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

lunacommer

2020/04/14 08:51

大変申し訳ないです。 listener.stop() を呼び出す。クリック検出の停止。 self.thread = None (再スタートを出来るようにする為) こちらはstopButtonClick内に記述するものですか?
teamikl

2020/04/14 09:00

そうです>stopButtonClick内に記述 あと、click_listen() 内の while(True): は取り除きます。 stop() しても、また次のリスナーが起動してしまうので。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問