Tkinterで描画情報を設定した時間ごとに取得する


はじめに

PythonでGUIプログラムを書けるライブラリTkinter.
このライブラリでは、中にあるCanvasを使って絵を描く事が出来る.

Canvasを使って絵を描く機会は人間誰しもあると思うが、Canvasに書いた情報を設定した時間ごとに取得するというプログラムは調べてもはっきりとわからなかった.
備忘録も兼ねて、プログラムを書いていく.

ちなみにCanvasを使って絵を描くというプログラム自体は以下のサイトを参考にした.
Pythonのcanvasにマウスで線を描いてみる

実行環境

  • macOS Catalina 10.15.3
  • tkinter 8.6
  • Pillow 6.2.1

コード

#!/usr/bin/env python
# -*- coding: utf8 -*-
import tkinter
import time
from PIL import Image, ImageDraw

class Application(tkinter.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title('Measure the time to draw')
        self.create_variables()
        self.create_widgets()
        self.pack()

    def create_widgets(self):
        self.draw_canvas = tkinter.Canvas(self, bg='white', width=self.img_size[0], height=self.img_size[1])
        self.draw_canvas.grid(row=1, column=0, columnspan=4)
        self.draw_canvas.bind('<Button-1>', self.start)
        self.draw_canvas.bind('<B1-Motion>', self.paint)
        self.draw_canvas.bind('<ButtonRelease-1>', self.reset)

    def create_variables(self):
        self.img_size = (600, 600)
        self.old_x, self.old_y = None, None
        self.color = 'black'
        self.pen_width = 5.0
        self.im = Image.new('RGB', self.img_size, 'white')
        self.draw = ImageDraw.Draw(self.im)

        self.tick_time = 30
        self.timer_id = None
        self.start_time = None

    #methods
    def start(self, event):
        if self.timer_id is None:
            self.timer_start()
        self.draw_canvas.create_line(event.x, event.y, event.x, event.y, width=self.pen_width, fill=self.color, capstyle="round", smooth=True, splinesteps=36)
        self.draw.line((event.x, event.y, event.x, event.y), fill=self.color, width=int(self.pen_width))
        self.old_x, self.old_y = event.x, event.y

    def paint(self, event):
        if self.old_x and self.old_y:
            self.draw_canvas.create_line(self.old_x, self.old_y, event.x, event.y, width=self.pen_width, fill=self.color, capstyle="round", smooth=True, splinesteps=36)
            self.draw.line((self.old_x, self.old_y, event.x, event.y), fill=self.color, width=int(self.pen_width))
        self.old_x, self.old_y = event.x, event.y

    def reset(self, event):
        self.old_x, self.old_y = None, None
        self.timer_reset()

    #timer
    def timer_start(self):
        if self.timer_id is not None:
            self.after_cancel(self.timer_id)
        self.start_time = time.time()
        self.timer_id = self.after(self.tick_time, self.timer_count)

    def timer_count(self):
        t = time.time() - self.start_time
        x = self.old_x if self.old_x is not None else -1
        y = self.old_y if self.old_y is not None else -1
        print("経過時間:%f , X位置 %d, Y位置 %d" % (t, x, y))
        self.timer_id = self.after(self.tick_time, self.timer_count)

    def timer_reset(self):
        if self.timer_id is None:
            return
        self.after_cancel(self.timer_id)
        self.timer_id = None

if __name__ == "__main__":
    root = tkinter.Tk()
    app = Application(master=root)
    app.mainloop()

実行結果

実行してみると、絵を描く為のキャンバスが出てくる.
このキャンバスにマウスで絵を描いてみると、ターミナルに
* 書き始めからの経過時間(/ミリ秒)
* X位置
* Y位置
が表示されるというプログラムになっている.

解説

タイマーの挙動に関する関数は、timer_start()timer_count()timer_reset()で定義されている.
これらの関数はCanvasにbindされたstart()reset()に応じて呼び出されて、after()関数によってtick_time変数に定義された時間ごとに、timer_count()を呼び出して現在の描画情報が得られるというようになっている

最後に

初めての記事作成だった.

文字を書いていて、どんな書き方をしてるのかをどう調査するというところで引っ掛かったところなので、このプログラムは手書きのオンライン情報を取得したいといった状況に役立てれば良いなと考えている.

参考

Pythonのcanvasにマウスで線を描いてみる
tkinter - .after() - RIP Tutorial