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

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

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

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

Q&A

解決済

2回答

20762閲覧

Pythonでキーが押されたことを判定したい

yoko4401

総合スコア9

Python 3.x

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

0グッド

0クリップ

投稿2018/06/01 10:32

前提・実現したいこと

Python初心者です。2択クイズゲームを作ろうと思っています。マウス操作に慣れていない方でも使えるようにキーボードからの入力で回答させたいので、とりあえずキーを判定する部分を作ってみました。aキーかbキーが押されたことを確認するためにprint(key)でkeyの値を取り出そうとしているのですがうまくいきません。
最終的にprint(key)でkeyの値を取り出したいのですがどうすればよいですか。

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

def keyA(event):でaキーを押されたときkey="A"を代入するようにしておき、frame.bind("a",keyA)でaキーが押された時にkeyAを呼び出して、それをprint(key)で取り出したいが取り出し方がわからない。

該当のソースコード

Python3.6

-- coding: utf8 --

import tkinter as tk
import winsound

root = tk.Tk()
frame = tk.Canvas(root, width=800, height=600)
pimg = tk.PhotoImage(file="wall.png")
frame.place(x=0, y=0)
frame.create_image(400, 300, image=pimg)

imgA = tk.PhotoImage(file = 'pressed_A.png')
imgB = tk.PhotoImage(file = 'Pressed_B.png')

def keyA(event):
<indent> global key
<indent> key="A"
<indent> frame.place(x=0, y=0)
<indent> frame.create_image(320, 220, image=imgA, tag="illust")
<indent> root.update()
<indent> winsound.PlaySound("pressed_A.wav", winsound.SND_FILENAME)

def keyB(event):
<indent> global key
<indent> key="B"
<indent> frame.place(x=0, y=0)
<indent> frame.create_image(320, 220, image=imgB, tag="illust")
<indent> root.update()
<indent> winsound.PlaySound("pressed_B.wav", winsound.SND_FILENAME)

frame.bind("a", keyA)
frame.focus_set()
frame.pack()

frame.bind("b", keyB)
frame.focus_set()
frame.pack()

print(key)

root.mainloop()

試したこと

keyイベント内でprint(key)を表示させることはできるが、メインの実行時にキーを判定できない。タイマーイベントで対応するときはどうすればよいでしょうか。
または、キー判定のためにまったく別の良い方法があれば教えてください。

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

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答2

0

ベストアンサー

tkinterの動作モデルは所謂イベント駆動型になっており、ウィンドウはroot.mainloop()を実行したときに初めて表示されそれ以降はウィンドウの操作をしている間中ずっとこのmainloop関数から返ってこないという特徴を持ってます。

このイベント駆動型の制御方式はGUIプログラミングではおなじみなので、プログラムの制御方法を「上から下へ順番に実行する」という発想から「何か操作されたら個々の関数が呼び出される」という発想に切り替える必要があります。

ではありますが、Pythonでtkinterを用いる場合、次のようなコードで非イベント駆動型の制御論理を書くこともできてしまうようです。これが常に適切に動作してくれるかどうか少々自身ないですが・・・

Python

1import tkinter as tk 2import threading 3import time 4 5 6root = tk.Tk() 7canvas = tk.Canvas(root, width=800, height=600) 8canvas.place(x=0, y=0) 9 10 11def keyA(event): 12 global key 13 key="A" 14 # root.update() 15 16def keyB(event): 17 global key 18 key="B" 19 # root.update() 20 21canvas.bind("a", keyA) 22canvas.bind("b", keyB) 23canvas.focus_set() 24canvas.pack() 25 26def main(): 27 # 制御論理を無理やり逐次実行的に書いてみる 28 global key 29 30 while not stop: 31 time.sleep(0.1) # 最初この行を入れ忘れてました!!! 32 if key is not None: 33 print('pressed {}'.format(key)) 34 if key == 'A': 35 color = '#FF0000' 36 elif key == 'B': 37 color = '#00FF00' 38 canvas.create_rectangle((10, 10), (20, 20), width=0, fill=color) 39 key = None 40 41key, stop = None, False 42game_thread = threading.Thread(target=main) 43game_thread.start() 44 45root.mainloop() 46 47stop = True 48game_thread.join() 49print('end of execution')

ポイントはmainloopの実行前に主たる制御論理(上の例ではmain関数)を別のスレッドで動かすことです。メインスレッドではtkinterの通常の動作(イベント駆動型)が行われておりずっとmainloop関数が動きっぱなしになります。それとは別のスレッドでmain関数が実行され、keyA, keyBで押されたキーをグローバル変数に格納するとmain関数の中でそれを検出して何かするという感じですね。
実験のためメインスレッドと別のスレッドでtkinterのキャンバス上に描画してみましたが、動くように見えました。他の言語のGUIライブラリーだと複数のスレッドから画面を触るのは「いけません」てことになっているのですが、PythonのGIL(Global Interpreter Lock)の仕様のためそのあたりの制限はゆるーくなっているのかも知れません(もしかたしたらダメなのかも知れません。自身ないです)

しかし、上のように書くことはできますがこう書いたからといってプログラミングしやすいかは少々疑問です。普通にイベント駆動型でプログラミングしてもよい気がするのですが・・・どうでしょうか?

投稿2018/06/01 11:25

編集2018/06/01 14:10
KSwordOfHaste

総合スコア18394

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

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

KSwordOfHaste

2018/06/01 14:20

すみません、最初のコード例でwhile文のところにsleep入れるのを忘れておりました。それだとCPUを使いまくるのでよくない例だと思います。sleepを追加しておきました。
guest

0

キー判定のためにまったく別の良い方法 -> keyboardパッケージ

python

1import keyboard 2keyboard.on_press_key("a", print) 3keyboard.on_press_key("b", print)

pipでkeyboardパッケージをインストールしてから、上記を実行してaキーやbキーを打ってみてください。ドキュメントはココです。

投稿2018/06/01 11:17

YouheiSakurai

総合スコア6142

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

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

yoko4401

2018/06/01 14:17

ありがとうございました。特にプログラムにこだわりはなく、シンプルなほうが大歓迎なのですが、 keyboardパッケージをインストールした後、実行したのですが何も起こりませんでした。 当方のスキル不足かと思われますので、教えていただいた解説を参考にもう少し勉強したいと思います。 上手く動けば、もしかしたらこちらのほうを採用するかもしれません。もう少し頑張ってみます。 アドバイスがあればまた、ご教唆ください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問