拖放棋子

Drag and drop a pawn

from tkinter import Tk, Canvas, Label, NSEW

class CanvasChecker(Canvas):

    def __init__(self, parent, n_pixels_per_case=60):

        self.checker = {(7, 0): 'o', (7, 2): 'o', (7, 4): 'o', (7, 6): 'o', (6, 1): 'o', 
                (6, 3): 'o', (6, 5): 'o', (6, 7): 'o', (5, 0): 'o', (5, 2): 'o', (5, 4): 'o',
                (5, 6): 'o', (2, 1): 'x', (2, 3): 'x', (2, 5): 'x', (2, 7): 'x', (1, 0): 'x',
                (1, 2): 'x', (1, 4): 'x', (1, 6): 'x', (0, 1): 'x', (0, 3): 'x', (0, 5): 'x',
                (0, 7): 'x'}

        self.n_pixels_per_case = n_pixels_per_case

        width = 8 * n_pixels_per_case
        height = 8 * n_pixels_per_case

        super().__init__(parent, width=width, height=height)

        self.bind('<Configure>', self.redimension)

    def draw_cases(self):
        for i in range(8):
            for j in range(8):
                beg_line = i * self.n_pixels_per_case
                end_line = beg_line + self.n_pixels_per_case
                beg_column = j * self.n_pixels_per_case
                end_column = beg_column + self.n_pixels_per_case

                if (i + j) % 2 == 0:
                    color = '#E88515'
                color = '#DDDDFF'

                self.create_rectangle(beg_column, beg_line, end_column, end_line, fill=color, tags='case')

    def draw_pieces(self):
        for position in self.checker:
            coordinate_y = position[0] * self.n_pixels_per_case + self.n_pixels_per_case // 2
            coordinate_x = position[1] * self.n_pixels_per_case + self.n_pixels_per_case // 2

            piece = self.checker[position]

            if piece == 'o':
                icon = "\u26C0"
            elif piece == 'O':
                icon = "\u26C1"
            elif piece == 'x':
                icon = "\u26C2"
            else:
                icon = "\u26C3"

            character_police = ('Already Seen', self.n_pixels_per_case//2)
            self.create_text(coordinate_x, coordinate_y, text=icon, font=character_police, tags='piece')

    def redimension(self, event):

        new_size = min(event.width, event.height)
        self.n_pixels_per_case = new_size // 8
        self.actualise()

    def actualise(self):
        self.delete('case')
        self.draw_cases()
        self.delete('piece')
        self.draw_pieces()


class Game(Tk):

    def __init__(self):
        super().__init__()

        self.canvas_checker = CanvasChecker(self, 60)
        self.canvas_checker.grid(sticky=NSEW)

        self.messages = Label(self)
        self.messages.grid()

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)


if __name__ == '__main__':
    window = Game()
    window.mainloop()

我有一个棋盘。我会对在不同情况下拖放每个 pawn 感兴趣,但我很困惑我该怎么做。我考虑过使用 my_canvas.bind("<B1-Motion>", move),但我不确定如何在上面的代码中使用它。我现在只能看到白色和黑色的不同部分,不能移动它们。

如何在棋盘上拖放棋子?

您所要做的就是从您链接到的问题(在您的问题的早期版本中)中投票最高的答案中复制一些代码,然后调整绑定以处理标签“piece”而不是“令牌”。

首先,将该代码中的函数 drag_startdrag_stopdrag 复制到您的 CanvasChecker class 中。在复制的代码中将 self.canvas 更改为 self

接下来,在 __init__ 函数的某处添加这一行:

self._drag_data = {"x": 0, "y": 0, "item": None}

最后,添加以下绑定,同样在__init__:

self.tag_bind("piece", "<ButtonPress-1>", self.drag_start)
self.tag_bind("piece", "<ButtonRelease-1>", self.drag_stop)
self.tag_bind("piece", "<B1-Motion>", self.drag)

您需要添加判断移动是否合法的逻辑,但这回答了如何用鼠标移动棋子的问题。


from tkinter import Tk, Canvas, Label, NSEW

class CanvasChecker(Canvas):

    def __init__(self, parent, n_pixels_per_case=60):

        self.checker = {(7, 0): 'o', (7, 2): 'o', (7, 4): 'o', (7, 6): 'o', (6, 1): 'o',
                (6, 3): 'o', (6, 5): 'o', (6, 7): 'o', (5, 0): 'o', (5, 2): 'o', (5, 4): 'o',
                (5, 6): 'o', (2, 1): 'x', (2, 3): 'x', (2, 5): 'x', (2, 7): 'x', (1, 0): 'x',
                (1, 2): 'x', (1, 4): 'x', (1, 6): 'x', (0, 1): 'x', (0, 3): 'x', (0, 5): 'x',
                (0, 7): 'x'}

        self.n_pixels_per_case = n_pixels_per_case

        width = 8 * n_pixels_per_case
        height = 8 * n_pixels_per_case

        super().__init__(parent, width=width, height=height)

        self.bind('<Configure>', self.redimension)

        self._drag_data = {"x": 0, "y": 0, "item": None}
        self.tag_bind("piece", "<ButtonPress-1>", self.drag_start)
        self.tag_bind("piece", "<ButtonRelease-1>", self.drag_stop)
        self.tag_bind("piece", "<B1-Motion>", self.drag)


    def draw_cases(self):
        for i in range(8):
            for j in range(8):
                beg_line = i * self.n_pixels_per_case
                end_line = beg_line + self.n_pixels_per_case
                beg_column = j * self.n_pixels_per_case
                end_column = beg_column + self.n_pixels_per_case

                if (i + j) % 2 == 0:
                    color = '#E88515'
                color = '#DDDDFF'

                self.create_rectangle(beg_column, beg_line, end_column, end_line, fill=color, tags='case')

    def draw_pieces(self):
        for position in self.checker:
            coordinate_y = position[0] * self.n_pixels_per_case + self.n_pixels_per_case // 2
            coordinate_x = position[1] * self.n_pixels_per_case + self.n_pixels_per_case // 2

            piece = self.checker[position]

            if piece == 'o':
                icon = "\u26C0"
            elif piece == 'O':
                icon = "\u26C1"
            elif piece == 'x':
                icon = "\u26C2"
            else:
                icon = "\u26C3"

            character_police = ('Already Seen', self.n_pixels_per_case//2)
            self.create_text(coordinate_x, coordinate_y, text=icon, font=character_police, tags='piece')

    def redimension(self, event):

        new_size = min(event.width, event.height)
        self.n_pixels_per_case = new_size // 8
        self.actualise()

    def actualise(self):
        self.delete('case')
        self.draw_cases()
        self.delete('piece')
        self.draw_pieces()

    def drag_start(self, event):
        """Begining drag of an object"""
        # record the item and its location
        self._drag_data["item"] = self.find_closest(event.x, event.y)[0]
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

    def drag_stop(self, event):
        """End drag of an object"""
        # reset the drag information
        self._drag_data["item"] = None
        self._drag_data["x"] = 0
        self._drag_data["y"] = 0

    def drag(self, event):
        """Handle dragging of an object"""
        # compute how much the mouse has moved
        delta_x = event.x - self._drag_data["x"]
        delta_y = event.y - self._drag_data["y"]
        # move the object the appropriate amount
        self.move(self._drag_data["item"], delta_x, delta_y)
        # record the new position
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

class Game(Tk):

    def __init__(self):
        super().__init__()

        self.canvas_checker = CanvasChecker(self, 60)
        self.canvas_checker.grid(sticky=NSEW)

        self.messages = Label(self)
        self.messages.grid()

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)


if __name__ == '__main__':
    window = Game()
    window.mainloop()