以下は、キャンバスの周りで正方形を移動するためのコードです。矢印キーの押下イベントをキャプチャし、正方形を上下左右に移動します。一度に2つの矢印(たとえば、上下)を押しても、正方形は対角線上に移動しません。代わりに、必要な2つの方向のうちの1つだけに移動します。
このコードを変更して、正方形のスムーズな斜めの動きを可能にするにはどうすればよいですか。お時間をいただきありがとうございます。
from tkinter import *
x = 10
y = 10
a = 100
b = 100
direction = None
def move():
global x_vel
global y_vel
global direction
if direction is not None:
canvas1.move(rect, x_vel,y_vel)
window.after(33,move)
def on_keypress(event):
global direction
global x_vel
global y_vel
direction, x_vel, y_vel = dir_vel[event.keysym]
def on_keyrelease(event):
global direction
direction = None
dir_vel = {
"Left": ("left", -5, 0),
"Right": ('right', 5, 0),
"Down": ('down', 0, 5),
"Up": ('up', 0, -5),}
window = Tk()
window.geometry("400x200")
move()
#canvas and drawing
canvas1=Canvas(window, height = 200, width = 400)
canvas1.grid(row=0, column=0, sticky=W)
coord = [x, y, a, b]
rect = canvas1.create_rectangle(*coord, outline="#fb0", fill="#fb0")
#capturing keyboard inputs and assigning to function
window.bind_all('<KeyPress>', on_keypress)
window.bind_all('<KeyRelease>', on_keyrelease)
プログラム部分: Tkinterは、UIの「前」で実際に外部刺激が発生することなく、それ自体でUIイベントを生成できます。したがって、「イベントをプログラムするにはどうすればよいですか」の部分は、次の方法で実行されます。
self.event_generate( <eventNameId>, **args ) # fire STIMULUS without User-interaction
# # triggers <eventNameId>
# # **args allow to set <keyword>=<value>
# # pairs for Event-fields,
# # that are passed to anEventHANDLER
# # via an-<Event>-object ...
# # ref below ( not the system-assigned ones, sure )
同時性の問題:
原則として、Tkinter / Pythonコードは順番に実行されます。2つのイベントを同時にインスタンス化する簡単な方法はありません。簡単に言えば、コードは本質的にシーケンシャルプロセッサであるため、ほぼ同時のイベントを何らかの形で模倣/検出する必要があります。
Bryan Oakleyが他の投稿で十分に説明しているように、UI検出は、ArrowUpおよび/またはを保持するとArrowLeft、実際には自動生成されたUI- *イベントのシーケンスにつながる可能性があることに留意する必要があります。キーボードのタイプマティックレート設定。キーボードがキーが押されていることを検出すると、キーストロークを自動的に繰り返す役割を果たします...終了していません...)
Tkinterには、.event_generate()
イベントを処理するための強力なMVC-Controller-Partメソッドのセットがあります(自然にUIで検出され、人工的に「注入」されます)。これは、タスクの他の側面にとって重要になります。
# eventInstanceMethods() bear many details about click/key/time/.widget()
# <event>.char on-{ <KeyPress> | <KeyRelease> }
# .keysym on-{ <KeyPress> | <KeyRelease> }
# .keysym_num on-{ <KeyPress> | <KeyRelease> }
# .num on-{ <Mouse-1> | <Mouse-2> | ... } ? 4,5 == <MouseWheel>
# .height on-{ <Configure> }
# .width on-{ <Configure> }
# .serial <-- system-assigned Integer
# .time <-- system-assigned Integer ( .inc each msec )
# .widget <-- system-assigned <widget>-instance
# .x <-- system-assigned <Event>-in-<widget>-mouse-location.x
# .y <-- system-assigned <Event>-in-<widget>-mouse-location.y
# .x_root <-- system-assigned <Event>-on-<Screen>-mouse-location.x
# .y_root <-- system-assigned <Event>-on-<Screen>-mouse-location.y
このようなイベントを検出するために、Tkinterには次のメソッドが用意されています。
# |<<_aNamedEVENT_>>|<<______________________________aHANDLER>>|
# |or | |
# |<<_VirtualEVENT>>| |
# | | |
.bind( "<KeyPress-Left>", self.__doWidgetBoundTaskSpecificHANDLER )
.bind_class( "Button", "<KeyPress-Left>", self.__doClass_BoundTaskSpecificHANDLER )
.bind_all( "<KeyPress-Left>", self.__doApplicBoundTaskSpecificHANDLER )
これはグリーンフィールドの問題であり、MVC-Model-Partで辞書の使用に制限されている場合は、そこに行きます。上記の問題の後、方向の有限状態オートマトン(FSA)(ブラインド状態遷移のトリガーの{ <KeyPress>
| <KeyRelease>
}ペアだけでなく、TimeDOMAIN近接処理と拡張されたキーのシーケンスに基づく)単一キーとデュアル・キーの押し状態文法{nilを、Left、Up、Right、Down、Left&&
Up、Left&&
Dn、Right&&
Up、Right&&
Dn}とハンドリングは)少し複雑な成長しますが、最初のプロトタイプのために、あなただけの辞書割り当てルールを変更することができ、このような何かで始まります:
def on_keypress( event ): # keeping the Globals-style,
global direction # however shall be rather
global x_vel # implemented in a Class-based
global y_vel # manner
direction = dir_vel[event.keysym][0] # ref. remark on more complex FSA
x_vel += dir_vel[event.keysym][1]
y_vel += dir_vel[event.keysym][2]
def on_keyrelease( event ):
global direction
global x_vel
global y_vel
x_vel -= dir_vel[event.keysym][1]
y_vel -= dir_vel[event.keysym][2]
if abs( x_vel * y_vel ) < 0.1:
direction = None # ref. remark on more complex FSA
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加