【Python/tkinter】ドラッグ操作による図形の移動の実現方法

ドラッグ操作による図形の移動の実現方法解説ページのアイキャッチ

このページにはプロモーションが含まれています

このページでは、Python の tkinter における「ドラッグ操作による図形の移動の実現方法」について解説していきます!

tkinter では、下のアニメのように、キャンバスに描画した図形をドラッグ操作によって移動させることが可能です。

図形をドラッグ操作で移動させる様子を示すアニメ

結構アプリやゲームなどではドラッグ操作でオブジェクトを移動させることが多いので、tkinter を使っているのであればドラッグ操作での図形の移動方法も知っておいて損はないと思います。

例えばペイントアプリやプレゼン作成アプリだと図形をドラッグ操作で移動させるようなことも多いですよね!こういった操作も自身が開発したアプリで簡単に実現することができるようになります。

それでは、ドラッグ操作による図形の移動の実現方法について解説していきたいと思います。

図形をドラッグ操作で移動させるサンプルスクリプト

今回は、最初にドラッグ操作で図形を移動させるサンプルスクリプトを紹介しておきたいと思います。

そのサンプルスクリプトが下記になります。実行すれば、ページの最初にお見せしたアニメのように、図形をドラッグ操作で移動できることが確認できると思います。

図形に対するドラッグ操作
import tkinter

def click(event):
	global figure
	global before_x, before_y

	x = event.x
	y = event.y

	# クリックされた位置に一番近い図形のID取得
	figure = canvas.find_closest(x, y)

	# マウスの座標を記憶
	before_x = x
	before_y = y

def drag(event):
	global before_x, before_y

	x = event.x
	y = event.y

	# 前回からのマウスの移動量の分だけ図形も移動
	canvas.move(
		figure,
		x - before_x, y - before_y
	)

	# マウスの座標を記憶
	before_x = x
	before_y = y

def main():
	global canvas

	app = tkinter.Tk()

	# キャンバス作成
	canvas = tkinter.Canvas(
		app,
		width=500, height=300,
		highlightthickness=0,
		bg="white"
	)
	canvas.grid(row=0, column=0)


	# 色を用意
	colors = (
		"red", "green", "yellow", "blue", "purple", "pink", "orange"
	)

	# 色の数だけ適当に位置をずらしながら長方形(正方形)を描画
	for i, color in enumerate(colors):
		rect = canvas.create_rectangle(
			i * 60 + 20, 20, i * 60 + 70, 70,
			fill=color,
		)

		# 描画した図形にイベント処理設定
		canvas.tag_bind(rect, "<ButtonPress-1>", click)
		canvas.tag_bind(rect, "<Button1-Motion>", drag)

	app.mainloop()

if __name__ == "__main__":
	main()

以降は、上記サンプルスクリプトを参照しながら、ドラッグ操作による図形の移動の実現方法を解説していきます。

ドラッグ操作による図形の移動の実現方法

では、ドラッグ操作による図形の移動の実現方法について解説していきます。

スポンサーリンク

ウィジェットや図形の準備

まずは事前準備としてウィジェットの作成およびドラッグ操作で移動させる図形の描画を行なっておきます。

事前に準備しておくウィジェットや図形

この辺りを行なっているのが、図形をドラッグ操作で移動させるサンプルスクリプトmain 関数になります。

このあたりは説明不要かなぁと思いますので今回は説明は省略しますが、利用しているメインウィンドウとキャンバスウィジェット・図形の描画については下記ページで解説していますので、詳しく知りたい方は下記ページをご参照いただければと思います。

メインウィンドウ作成解説ページのアイキャッチ Tkinterの使い方:メインウィンドウを作成する tkinterのキャンバスの作り方解説ページアイキャッチ Tkinterの使い方:キャンバスウィジェットの作り方 tkinterキャンバスに図形を描画する方法解説ページのアイキャッチ Tkinterの使い方:Canvasクラスで図形を描画する

キャンバスのオブジェクト canvas は他の関数でも利用するため、グローバル変数としています。

また、下記に関しては難しそうに思えるかもしれませんが、単に異なる色で描画位置をずらしながら create_rectangle で長方形を描画しているだけです。

長方形の描画
# 色を用意
colors = (
	"red", "green", "yellow", "blue", "purple", "pink", "orange"
)

# 色の数だけ適当に位置をずらしながら長方形(正方形)を描画
for i, color in enumerate(colors):
	rect = canvas.create_rectangle(
		i * 60 + 20, 20, i * 60 + 70, 70,
		fill=color,
	)

とりあえず図形のドラッグ操作による移動のみを実現したいのであれば、上記のように複数長方形を描画する必要もなく、適当な図形を1つだけ描画するのでも問題はありません。

描画した図形のイベント処理を設定する

ただ、図形の数などは幾つでも良いのですが、図形に対してイベント処理の設定が必要である点には注意が必要です。

tkinter のキャンバスには tag_bind メソッドが用意されており、このメソッドを利用することで、描画した図形に対するイベント処理の設定が可能になります。

イベント処理自体は下記ページで解説していますので、詳しく知りたい方はコチラをご参照いただければと思います。

イベント処理解説ページのアイキャッチ Tkinterの使い方:イベント処理を行う

上記ページで使用している bind は主にウィジェットに対してイベント処理の設定を行うメソッドになりますが、今回使用するのは tag_bind で、簡単に言えば bind メソッドを図形に対して実行するのが tag_bind だと考えて良いと思います。

ただ、tag_bind の場合は第1引数に図形の ID or タグを指定する必要がありますので、その点だけ注意が必要です。

図形の ID やタグについては下記ページで解説していますので、詳しく知りたい方は下記ページをご参照しただければと思います。これらは描画した図形を操作する際によく利用しますので、知っておいて損はないと思います。

tkinterキャンバスの図形の操作方法解説ページのアイキャッチ Tkinterの使い方:Canvasクラスで描画した図形を操作する

さて、図形をドラッグ操作で移動させるサンプルスクリプト では下記のように tag_bind メソッドを実行しています。図形を描画するループの中で実行しており、第1引数には事前に create_rectangle で描画した図形の ID である rect を指定しているので、各長方形に対して2回ずつ tag_bind メソッドを実行していることになります。

図形に対するイベント処理の設定
# 描画した図形にイベント処理設定
canvas.tag_bind(rect, "<ButtonPress-1>", click)
canvas.tag_bind(rect, "<Button1-Motion>", drag)

1行目ではイベントシーシーケンスに <ButtonPress-1> を指定しているので、マウスで図形が左クリックされた時のイベント処理の設定を行うことになります。つまり、これを実行することで、左クリック時に click 関数がイベントハンドラとして実行されるようになります。

さらに2行目では、イベントシーシーケンスに <Button1-Motion> を指定しているので、マウスで図形に対してドラッグ操作された時のイベント処理の設定を行うことになります。つまり、これを実行することで、ドラッグ操作時に drag 関数がイベントハンドラとして実行されるようになります。

今回やりたいことはドラッグ操作による図形の移動ですので、2行目の tag_bind メソッドの実行だけ行えば良さそうなものですが、ドラッグ操作による図形の移動を行うためにはクリック時に特定の処理を行うことが必要になります。この辺りは、次の 図形を移動する で説明していきます。

ちなみに、今回は2行目の tag_bind メソッドでドラッグ操作時のイベント処理を直接設定していますが、クリック時・クリック解除時・マウス移動時の3つのタイミングのイベント処理設定を行うことでもドラッグ操作による図形の移動は実現可能です。

具体的には、フラグとなる変数を用意しておき、クリック時にフラグを True に、クリック解除時にフラグを False に設定するようにし、さらにマウス移動時にフラグが True の場合だけ図形の移動処理を行うようにすれば、ドラッグによる図形の移動を実現できるはずです。

ただ、上記の2行目の tag_bind メソッドのように、イベントシーシーケンスに <Button1-Motion> を指定してドラッグ操作時のイベント処理を設定した方が、フラグ管理なども不要になるので楽だとは思います。

図形を移動する

ここまでの説明で、必要なウィジェットや図形の準備が完了し、さらに各図形に対して左クリックが行われた際に click 関数が、ドラッグ操作が行われた際に drag 関数が実行されるようになりました。

これらの処理は 図形をドラッグ操作で移動させるサンプルスクリプト で紹介した main 関数で行ってきましたが、ここからは click 関数と drag 関数を作成し、ドラッグ操作による図形の移動を実現していきたいと思います。

図形を移動するメソッド

まず、キャンバスに描画された図形を移動させるためには、キャンバスの move メソッドを利用します。

move
move(tagOrId, xAmaount, yAmaount)

move メソッドの各引数は下記のようになります。

  • 第1引数 tagOrId:移動させる図形の ID or タグ
    • (今回は ID を指定するようにしていきます)
  • 第2引数 xAmaountx 方向に移動させる量(ピクセル数)
  • 第3引数 yAmaounty 方向に移動させる量(ピクセル数)

move メソッドを実行すると、上記の引数に基づいて図形を移動させることができます。

moveメソッドの説明図

つまり、ドラッグ操作時に実行される drag 関数の中で move メソッドを実行すれば、ドラッグ操作でマウスが移動するたびに図形を移動させるような処理を実現することができます。

ただ、今回はドラッグ操作で図形の移動を行うわけですから、第1引数 tagOrId にはドラッグ操作されている図形の ID or タグを指定する必要があります。前述の通り、今回はタグではなく図形 ID を指定するようにしていきますが、どうやってドラッグ操作されている図形の ID を取得すれば良いでしょうか?

また、ドラッグ操作による図形の移動とは、要はドラッグ操作時にマウスの移動に合わせて図形を移動させることですので、第2引数 xAmaount と第3引数 yAmaount には、前回の図形移動時からのマウスの x 方向の移動ピクセル数と y 方向の移動ピクセル数をそれぞれ指定する必要があることになります。この移動ピクセル数はどうやって求めれば良いでしょうか?

この辺りの、ドラッグ操作されている図形の ID の取得方法やマウスの移動ピクセル数の求め方について、ここから解説していきたいと思います。

ドラッグ操作されている図形 ID の取得

では、まずは move メソッドの第1引数 tagOrId に指定する必要のあるドラッグ操作されている図形の ID の取得について解説していきます。

今回、その図形 ID の取得を行うために、下記の find_closest メソッドを利用したいと思います(引数 halostart は省略可能です。正直これらの引数については私も理解していないです…)。

find_closest
find_closest(x, y, halo=None, start=None)

find_closest メソッドは、第1引数 x と第2引数 y で与えられる座標に一番近い図形の ID を返却するメソッドになります。

find_closestメソッドの説明図

また、クリックやドラッグ操作のイベントが発生した場合、イベントハンドラ実行時(click 関数や drag 関数実行時)に引数として tkinter.Event クラスのオブジェクトが渡され、そのオブジェクトの xy データ属性より、マウスカーソルの現在位置の座標を得ることができます。

ですので、例えばイベントハンドラの引数を event とすれば、そのイベントハンドラの中で find_closest(event.x, event.y) を実行することにより、マウスカーソルに一番近い位置の図形の ID を取得することができます。

さらに、ドラッグ操作を行う際には最初に必ず左クリック操作が行われますので(左クリックし、左クリックしたままマウスカーソルを移動させるのがドラッグ操作)、図形の左クリック時に実行される click 関数の中で find_closest を実行すれば、クリックした図形の ID を取得することができることになります。

あとは、その後のドラッグ操作時に実行される drag 関数の中で、第1引数に取得した図形 ID を指定して move メソッドを実行してやれば良いです。

とりあえず、ここまで説明してきた内容を click 関数に反映すれば、下記のようになります。

図形 ID の取得
def click(event):
	global figure

	x = event.x
	y = event.y

	# クリックされた位置に一番近い図形のID取得
	figure = canvas.find_closest(x, y)

figuremove メソッドの第1引数に指定する図形 ID となります。また、move メソッドは drag 関数で実行するため、drag 関数からも figure が参照できるよう、figure はグローバル変数としています。 

ちなみに、ドラッグ操作時に実行される drag 関数の中で find_closest メソッドにより図形 ID の取得を行うことも可能ではあるのですが、ドラッグ操作時に毎回図形 ID が更新されることになるため、図形同士が重なっている際などに意図せず図形 ID が変化してしまうことがあります。

その様子を示したのが下のアニメで、青色の図形をドラッグしているのにオレンジ色の図形と重なった際に、その後オレンジ色の図形が移動するようになってしまっています。

ドラッグ操作途中で移動する図形が変わってしまう様子

こんな感じで、ドラッグ操作時に実行される関数の中で図形 ID を取得するようにしてしまうと、途中で移動を行う図形の ID が変わってしまい、ユーザーの意図通りに図形を移動できなくなる可能性があります。

それに対し、左クリック時に実行される関数の中で図形 ID を取得しておけば、ドラッグ操作で図形を移動している間は図形 ID が変化しないため、上のアニメのように途中で移動する図形が変わってしまうような現象を防ぐことができます。

マウスの移動ピクセル数の計算

続いて、move メソッドの第2引数 xAmount と第3引数 yAmount に指定する図形の移動ピクセル数、つまりはマウスの移動ピクセル数の求め方について解説していきます。

前述の通り、クリックやドラッグ操作のイベントが発生した場合、イベントハンドラ実行時(click 関数や drag 関数実行時)に引数として tkinter.Event クラスのオブジェクトが渡され、そのオブジェクトの xy データ属性より、マウスカーソルの現在位置の座標を得ることができます。

ですので、図形の移動を行う drag 関数の中で、このデータ属性よりマウスカーソルの現在位置の座標を知ることができます。ただ、今回求めたいのは、前回の図形移動時(move メソッド実行時)からのマウスカーソルの移動ピクセル数になります。

そのため、前回 move メソッドを実行した時のマウスカーソルの位置の座標を覚えておき、その座標と現在のマウスカーソルの位置の座標との差を求め、そこからマウスカーソルの移動ピクセル数を求めるような計算が必要になります。

マウスの移動ピクセル数の求め方

こういった処理は、drag 関数を下記のように作成することで実現することができます。

移動ピクセル数の取得と図形の移動
def drag(event):
	global before_x, before_y

	x = event.x
	y = event.y

	# 前回からのマウスの移動量の分だけ図形も移動
	canvas.move(
		figure,
		x - before_x, y - before_y
	)

	# マウスの座標を記憶
	before_x = x
	before_y = y

上記において、(x, y) が現在のマウスカーソルの位置の座標であり、(before_x, before_y) が前回 move メソッドを実行した時のマウスカーソルの位置の座標となります。そして、これらの差分を move メソッドの引数に指定することで、前回 move メソッドを実行した時からマウスカーソルが移動した分だけ、図形が移動されるようにしています。

さらに、最後に (before_x, before_y) を (x, y) で更新することで、次に drag 関数が実行された際に、現在のマウスカーソルの位置の座標 (x, y) を前回のマウスカーソルの位置の座標として新たに図形の移動が行われるようにしています。

こんな感じで、どんどん前回のマウスカーソルの位置の座標を更新していくことで、drag 関数が実行されるたびに、前回からマウスカーソルが移動した分だけ図形を移動することができるようになります。

ポイントは before_xbefore_y をグローバル変数として扱っているところです。通常のローカル変数の場合、関数終了時にその変数の中身が忘れ去られてしまいますが、グローバル変数として扱うことで、関数終了後も変数の中身が保持され、次回の関数実行時や他の関数実行時にその変数を参照することができるようになります。

一応上記の drag 関数は、関数単体としては出来上がっているのですが、まだ問題点があります。

drag 関数は、(before_x, before_y) に前回のマウスカーソルの位置の座標が設定されていることを前提に動作します。ですが、一番最初に drag 関数が実行された際には、まだ drag 関数は実行されていないので (before_x, before_y) には何も設定されていないことになります。

そうなると、マウスカーソルの移動ピクセル数を上手く求めることができず、図形が変な位置に移動してしまうことになります。そのため、最初の drag 関数を実行する前に、あらかじめ (before_x, before_y) を設定する処理を行なっておく必要があります。

それを行なっておくのが、click 関数の役割となります。

前述の通り、ドラッグ操作が行われる前には必ず左クリックが行われます。ですので、drag 関数が実行される前には click 関数が実行されることになります。

したがって、click 関数でクリックされた位置の座標を (before_x, before_y) に設定しておけば、初めて drag 関数が実行された際にも、クリックされたマウスカーソルの位置からのマウスカーソルの移動ピクセル数をうまく算出でき、うまく図形を移動させることができるようになります。

click関数とdrag関数が実行されていく様子

そのため、click 関数でも下記のように、before_xbefore_y の設定を行うようにする必要があります。

クリックされた位置の座標の設定
def click(event):
	global figure
	global before_x, before_y

	x = event.x
	y = event.y

	# クリックされた位置に一番近い図形のID取得
	figure = canvas.find_closest(x, y)

	# マウスの座標を記憶
	before_x = x
	before_y = y

以上で click 関数と drag 関数が完成し、ドラッグ操作による図形の移動を実現できたことになります!

出来上がりは 図形をドラッグ操作で移動させるサンプルスクリプト で紹介したものと一緒なのでスクリプトの実行結果等の説明は省略しますが、ぜひ実際に実行し、どのようにスクリプトが動作しているか復習してみてください!

スポンサーリンク

スクロールバー付きキャンバス利用時の注意点

単なるキャンバスを利用している場合は、ここまで解説してきた内容に基づいてスクリプトを作成すれば図形のドラッグ操作による移動は実現可能です。

ですが、スクロール可能なキャンバスを利用する際には注意点があり、もう少し追加で対応が必要になります。

ここからは、その注意点および注意点に対する対応について解説していきます。

ちなみにスクロールはウィジェットにスクロールバーを設定することで行うことができます(スクロールバー無しでもスクロールできるけど)。スクロールバーについては下記ページで解説していますので、詳しく知りたい方は読んでみてください。

スクロールバーの作成方法解説ページアイキャッチ Tkinterの使い方:スクロールバー(Scrollbar)の使い方

スクロール後に上手く図形が移動しない例

例えば下記は、スクロールバー付きのキャンバスに対し、ここまで解説してきた内容に基づいてドラッグ操作で図形を移動できるようにしたつもりのスクリプトになります。

ですが、スクロールした後にドラッグ操作で図形を移動しようと思ってもうまく移動させることができません。

スクロール後に上手く図形が移動しない例
import tkinter

def click(event):
	global figure
	global before_x, before_y

	x = event.x
	y = event.y

	# クリックされた位置に一番近い図形のID取得
	figure = canvas.find_closest(x, y)

	# マウスの座標を記憶
	before_x = x
	before_y = y

def drag(event):
	global before_x, before_y

	x = event.x
	y = event.y

	# 前回からのマウスの移動量の分だけ図形も移動
	canvas.move(
		figure,
		x - before_x, y - before_y
	)

	# マウスの座標を記憶
	before_x = x
	before_y = y

def main():
	global canvas

	app = tkinter.Tk()

	# キャンバス作成
	canvas = tkinter.Canvas(
		app,
		width=500, height=300,
		highlightthickness=0,
		bg="white",
		scrollregion=(-1000, 0, 1000, 500),
	)
	canvas.grid(row=0, column=0)

	xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
)
	xbar.grid(
		row=1, column=0,  # キャンバスの下の位置を指定
		sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
	)
	xbar.config(
		command=canvas.xview
	)
	canvas.config(
		xscrollcommand=xbar.set
	)

	# 色を用意
	colors = (
		"red", "green", "yellow", "blue", "purple", "pink", "orange"
	)

	# 色の数だけ適当に位置をずらしながら長方形(正方形)を描画
	for i, color in enumerate(colors):
		rect = canvas.create_rectangle(
			i * 60 + 20, 20, i * 60 + 70, 70,
			fill=color,
		)

		# 描画した図形にイベント処理設定
		canvas.tag_bind(rect, "<ButtonPress-1>", click)
		canvas.tag_bind(rect, "<Button1-Motion>", drag)

	app.mainloop()

if __name__ == "__main__":
	main()

スクリプトを実行し、ウィンドウ下部のスクロールバーでスクロールを行った後に図形をドラッグ操作してみると分かると思うのですが、ドラッグ操作を行なっても意図した図形ではない図形が移動したり、移動する位置がおかしかったりすると思います。

スクロール後の移動がうまく動作しない様子

スクロールする場合は座標の変換が必要

スクロールした後に上手くドラッグ操作で図形が移動できない原因は、「キャンバスのメソッドに指定する座標がスクロールした分だけずれている」という点にあります。

スクロール可能なキャンバスでは、下の図のようにキャンバス全体(scrollregion)のうち、一部分のみを表示領域としてアプリのウィンドウに表示されることになります。

キャンバスと表示領域の関係図

前述の通り、マウス操作により実行されるイベントハンドラでは、マウスカーソルの現在位置の座標を取得することが可能ですが(event.x と event.y)、この座標は「表示領域の左上を原点とする座標」となります。

イベントハンドラ実行時に得られるマウスの座標の説明図

それに対し、キャンバスのメソッドで指定する座標は「キャンバス全体(scrollregion)の (0, 0) 座標を原点とする座標」である必要があります(ちなみにキャンバス全体における (0, 0) 座標は左上とは限りません。scrollregion の指定の仕方によって変わります)。

キャンバスに指定する必要のある座標の説明図

おそらく、アプリ起動時には上記の2つの座標における原点は同じ位置に存在します。この場合、座標の違いを気にする必要はないのですが、スクロールを行うと2つの座標における原点がずれることになります。

そして、この2つの座標における原点がスクロールによってずれてしまった場合、表示領域の左上を原点とする座標、例えば event.xevent.y をそのままキャンバスのメソッドに指定しまうと、そのずれた分だけメソッドの動作もずれることになってしまうことになります。

スクロール後にキャンバスのメソッドに指定する座標がずれてしまう様子

例えば、指定した座標に一番近い図形の ID を取得する際に find_closest メソッドを利用していましたが、スクロール後に find_closest(event.x, event.y) を実行すると、座標 (event.x, event.y) に一番近い図形の ID ではなく、スクロールした分だけ座標 (event.x, event.y) からずれた位置に一番近い図形の ID を取得することになってしまいます。

ですので、スクロールした後にも上手くドラッグ操作による図形の移動を行えるようにするためには、「表示領域の左上を原点とする座標」を「キャンバス全体の (0, 0) 座標を原点とする座標」に変換してからキャンバスのメソッドを実行するようにする必要があります。

キャンバスのメソッド実行前に座標変換を行う例

そして、その変換を行うためのメソッドがキャンバスには用意されており、そのメソッドが canvasxcanvasy になります。

canvasx メソッドの引数に「表示領域の左上を原点とする座標」の x 座標を指定すれば、「キャンバス全体の (0, 0) 座標を原点とする座標」に変換した x 座標を取得することができます。

canvasy メソッドも同様で、引数に「表示領域の左上を原点とする座標」の y 座標を指定すれば、「キャンバス全体の (0, 0) 座標を原点とする座標」に変換した y 座標を取得することができます。

ですので、スクロール後に上手く図形が移動しない例 でキャンバスのメソッドに指定していた座標を、canvasx メソッドと canvasy メソッドで変換した座標に変更してやれば、スクロール後でもドラッグ操作による図形の操作を上手く動作させることができるようになります。

ちょっと難しい話になってしまいましたが、とりあえずは、スクロール可能なキャンバスを利用する場合、キャンバスのメソッドには event.xevent.y ではなく canvasx(event.x)canvasy(event.y) を指定する必要があることだけ覚えておくと良いと思います。

スポンサーリンク

スクロール位置を考慮したサンプルスクリプト

上記の説明に基づき、スクロール後に上手く図形が移動しない例 で紹介したスクリプトを canvasxcanvasy を使用するように変更したスクリプトが下記になります。

スクロール位置を考慮した図形の移動
import tkinter

def click(event):
	global figure
	global before_x, before_y

	x = canvas.canvasx(event.x)
	y = canvas.canvasy(event.y)

	# クリックされた位置に一番近い図形のID取得
	figure = canvas.find_closest(x, y)

	# マウスの座標を記憶
	before_x = x
	before_y = y

def drag(event):
	global before_x, before_y

	x = canvas.canvasx(event.x)
	y = canvas.canvasy(event.y)

	# 前回からのマウスの移動量の分だけ図形も移動
	canvas.move(
		figure,
		x - before_x, y - before_y
	)

	# マウスの座標を記憶
	before_x = x
	before_y = y

def main():
	global canvas

	app = tkinter.Tk()

	# キャンバス作成
	canvas = tkinter.Canvas(
		app,
		width=500, height=300,
		highlightthickness=0,
		bg="white",
		scrollregion=(-1000, 0, 1000, 500),
	)
	canvas.grid(row=0, column=0)

	xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
)
	xbar.grid(
		row=1, column=0,  # キャンバスの下の位置を指定
		sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
	)
	xbar.config(
		command=canvas.xview
	)
	canvas.config(
		xscrollcommand=xbar.set
	)

	# 色を用意
	colors = (
		"red", "green", "yellow", "blue", "purple", "pink", "orange"
	)

	# 色の数だけ適当に位置をずらしながら長方形(正方形)を描画
	for i, color in enumerate(colors):
		rect = canvas.create_rectangle(
			i * 60 + 20, 20, i * 60 + 70, 70,
			fill=color,
		)

		# 描画した図形にイベント処理設定
		canvas.tag_bind(rect, "<ButtonPress-1>", click)
		canvas.tag_bind(rect, "<Button1-Motion>", drag)

	app.mainloop()

if __name__ == "__main__":
	main()

スクロール後に上手く図形が移動しない例 からの変更点は、click 関数と drag 関数で行っていた下記の処理を、

変更前
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)

下記のように canvasxcanvasy を使用するように変更しただけです。

変更後
x = event.x
y = event.y

スクリプトを実行すれば、スクロール後も図形のドラッグ操作による移動がうまく行えるようになっていることが確認できると思います。

まとめ

このページでは、tkinter での「ドラッグ操作による図形の移動の実現方法」について解説しました!

考え方はシンプルで、要はドラッグ操作が行われた際にのみ実行される関数の中で move メソッドを実行すれば良いだけです。ただ、move メソッドの引数に指定する図形の ID やマウスの移動ピクセル数を取得するあたりはポイントになると思いますので、その辺りはしっかり理解しておきましょう!

特に find_closest メソッドは便利なので是非覚えておいてください!

このドラッグ操作による図形の移動を利用すれば面白いゲームも作れそうかなぁと考えています。実際に思いついた場合は、また記事を起こして紹介していきたいと思います!

同じカテゴリのページ一覧を表示