Python(Canvasウィジェット)

今回は、以下のサイトで紹介されているプログラムをPython3系で実行できるように修正して、Canvasウィジェットを学習しました。

9. ボードゲーム用 GUI を作ろう
10. キャンバスにドラッグできるオブジェクトを描こう
11. Canvas を使って納涼しよう

コードの説明はサイトの方に詳しく書かれているので、そちらを参照してください。

また、修正内容については主に以下の3点です。

1.モジュール名の変更
2.intで渡すべき値がfloatになっていた
3.ファイル処理の方法

ファイル処理については以前の投稿を確認してください。
Python(ファイル処理とwith構文)

Canvasウィジェット
弧、ビットマップ、イメージ、線分、楕円、多角形、長方形、テキスト、ウインドウといったオブジェクトを描くことができます。

オプションscrollregionを指定することでスクロールバーをつけることができます。

オブジェクトに.tag_bind()メソッドで、刺激に対するコールバック関数を設定することで、ドラッグできるオブジェクトなどを作ることができます。

オブジェクトにafter()メソッドで更新処理させることで、アニメーションを作ることもできます。

ファイル操作を扱った、詰め碁のGUIアプリについては修正箇所が多かったのでコードを記載します。
他のコードについては微調整で実行可能だったので、割愛させていただきます。

詰碁作成用 GUIツール

import tkinter as Tk

class Gboard(Tk.Canvas):
    """Tk.Canvas for Go Board"""
    grid_size = 20
    stones = dict()

    def __init__(self, master=None):
        en = self.grid_size * 19
        z = self.grid_size * 0.36
        hosi = 2
        Tk.Canvas.__init__(self, master, relief=Tk.RAISED, bd=4, bg="#F7EE8A",
                            width=20*self.grid_size, height=20*self.grid_size, highlightthickness=0)

        # binding the goban canvas to put_stones method
        self.bind("<1>", self.put_stones)
        # drawing lines and coordinate
        for i in range(19):
            x= (i+1) * self.grid_size
            self.create_line(x, self.grid_size, x, en)
            self.create_line( self.grid_size, x, en, x)
            self.create_text(z, x, text=str(i), justify=Tk.RIGHT, fill="#002010",
                            font = ("Helvetica","6","normal"))
            self.create_text(x, z , text=str(i), justify=Tk.CENTER, fill="#002010",
                            font = ("Helvetica","6","normal"))

        # drawing black dots
        for i in range(4,17,6):
            for j in range(4,17,6):
                x = i * self.grid_size
                y = j * self.grid_size
                self.create_oval(x-hosi, y-hosi, x+hosi, y+hosi, fill= "black")

    def bclear(self):
        """ clear stones in the map and on the canvas"""
        self.stones.clear()
        self.delete("stone")

    def bopen (self, fname):
        """open *.gbn file, whose content is ( [kuro ishi positions], [shiro ishi positions])"""
        with open(fname,"r") as fp:
            for i,pos in enumerate(fp):
                if i == 1:
                    lb=pos
                elif i == 2:
                    lw=pos

        for row, col in lb:
            self.stones[(row,col)] = self.put_a_stone(row, col, "black")
        for row, col in lw:
            self.stones[(row,col)] = self.put_a_stone(row, col, "white")

    def bsave(self, fname):
        """ save positions of stones in a file """
        lb = []
        lw = []
        for key, val in self.stones.items():
            if self.itemcget(val, "fill") == "black":
                lb.append(key)
            else:
                lw.append(key)

        with open(fname,"w") as fp:
            fp.write("[black stones], [white stones]\n")
            fp.write(str(lb))
            fp.write("\n")
            fp.write(str(lw))
            fp.write("\n")

    def put_stones(self, event):
        """ putting go ishis on the goban,
            this function is bounded to the left one click of the mouse"""
        cx = self.canvasx(event.x, self.grid_size)
        cy = self.canvasy(event.y, self.grid_size)
        col = int(cx/self.grid_size) - 1
        row = int(cy/self.grid_size) - 1
        if (0<=row<=18 and 0<=col<=18):
            if (not ((row,col) in self.stones)):
                self.stones[(row,col)] = self.put_a_stone(row, col, "black")
            elif(self.itemcget(self.stones[(row,col)], "fill") == "black"):
                self.itemconfig(self.stones[(row,col)], fill="white")
            else:
                self.delete(self.stones[(row,col)])
                del self.stones[(row,col)]

    def put_a_stone(self, row, col, color):
        """ it drows a go-ishi on the goban canvas and returns the go-ishi's ID """
        r = self.grid_size * 0.45
        x_left = (col+1)*self.grid_size-r
        x_right = (col+1)*self.grid_size+r
        y_top = (row+1)*self.grid_size-r
        y_bottom = (row+1)*self.grid_size+r
        return self.create_oval(x_left, y_top, x_right, y_bottom, fill = color, tags = "stone")

    def add_n_on_stone(self, i, row, col, tcolor):
        """ draw number of a stone """
        return self.create_text((col+1)*self.grid_size, (row+1)*self.grid_size,
                                text=str(i+1), justify=Tk.CENTER, fill=tcolor,
                                font = ("Helvetica","8","bold"), tags="stone")

if __name__ == "__main__":
    board = Gboard()
    board.pack()
    board.mainloop()

次回はTextウィジェットを扱いたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください