chihiro1364
@chihiro1364

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

tkinterでマウスの座標確認するアプリの作り方について

解決したいこと

tkinterでキャンバス内でマウスを動かした時の座標を検出してGUIに出力するアプリを
参考書を見て作りました。

その中で、どこに置いてもよさそうな構文なのに別の場所に置くとうまく動作しない箇所があります。

それはなぜなのか教えてほしいです。

発生している問題・エラー

マウスポインタが移動したら座標を表示し、
マウスの左右どちらかのボタンをクリックしたら1と表示し、
離したら0とキャンバスに表示するアプリです。

mouse_x = 0
mouse_y = 0
mouse_c = 0

def button_press(e):
    global mouse_c
    mouse_c = 1    

def button_release(e):
    global mouse_c
    mouse_c = 0

def motion(e):
    global mouse_x, mouse_y
    mouse_x = e.x
    mouse_y = e.y

def main_prop():
    canvas.delete("motion_up")
    txt = "mouse({},{}){}".format(mouse_x, mouse_y, mouse_c)
    canvas.create_text(456, 384, fill="black",font=("System", 30),  text=txt, tag="motion_up")
    root.after(300, main_prop)


import tkinter
root = tkinter.Tk()
canvas = tkinter.Canvas(width=912, height=768)
canvas.pack()
font=("System", 30)
text=txt, tag="motion_up")
root.bind("<Motion>", motion)
root.bind("<ButtonPress>", button_press)
root.bind("<ButtonRelease>", button_release)
main_prop()
root.mainloop()

上記の構文は0.3秒毎に更新されて正常に動作します。
しかし、main_prop関数に移行して処理を行う構文から
txt = "mouse({},{}){}".format(mouse_x, mouse_y, mouse_c)
font=("System", 30)
の、キャンバスに表示する文字に関する設定を関数外(root.mainloop()迄の間)で行うと動作しないのです。

mouse_x = 0
mouse_y = 0
mouse_c = 0

def button_press(e):
    global mouse_c
    mouse_c = 1    

def button_release(e):
    global mouse_c
    mouse_c = 0

def motion(e):
    global mouse_x, mouse_y
    mouse_x = e.x
    mouse_y = e.y

def main_prop():
    canvas.delete("motion_up")
    canvas.create_text(456, 384, fill="black",  text=txt,font=("System", 30),
 tag="motion_up")
    root.after(300, main_prop)


import tkinter
root = tkinter.Tk()
canvas = tkinter.Canvas(width=912, height=768)
canvas.pack()
font=("System", 30)
text=txt, tag="motion_up")
root.bind("<Motion>", motion)
txt = "mouse({},{}){}".format(mouse_x, mouse_y, mouse_c)
root.bind("<ButtonPress>", button_press)
root.bind("<ButtonRelease>", button_release)
main_prop()
root.mainloop()
0

1Answer

プログラムは先頭から順番に実行されていきます。関数は呼び出したときに実行されます。
前者では、main_prop()root.after(300, main_prop) によって何度もmain_prop関数が呼び出され、その都度変数txtの内容を更新してcanvasに描画しています。
後者では txt = "mouse({},{}){}".format(mouse_x, mouse_y, mouse_c) を実行するのは一度だけで、マウスが移動しても再実行されず、変数txtの内容は変化しません。

以下のプログラムを実行しても Hello, chihiro1364! ではなく Hello, world! が出力されるのと同じ理由です。

name = 'world'
txt = 'Hello, {}!'.format(name)
name = 'chihiro1364'
print(txt)

変化しない変数だけ外に出しておくといいですよ。
300ミリ秒毎ではなく、即座に更新するようにもしてみました。

import tkinter

class mouse:
    x = 0
    y = 0
    c = 0

def button_press(e):
    mouse.c = 1
    update()

def button_release(e):
    mouse.c = 0
    update()

def motion(e):
    mouse.x = e.x
    mouse.y = e.y
    update()

def update():
    text = f"mouse({mouse.x},{mouse.y}){mouse.c}"
    canvas.delete(tag)
    canvas.create_text(456, 384, fill="black", font=font, text=text, tag=tag)

root = tkinter.Tk()
canvas = tkinter.Canvas(width=912, height=768)
canvas.pack()
font = ("System", 30)
tag = "motion_up"
root.bind("<Motion>", motion)
root.bind("<ButtonPress>", button_press)
root.bind("<ButtonRelease>", button_release)
root.mainloop()
1Like

Comments

  1. @chihiro1364

    Questioner

    非常に分かり易かったです。
    ありがとうございます。

    そもそもafter()メソッドが処理のみ毎回行うもので、都度更新する内容だと知らなかったのが原因でした。

    勉強になりました。

Your answer might help someone💌