Python 用Tkinter矩形制作网格

Python 用Tkinter矩形制作网格,python,tkinter,tkinter-canvas,Python,Tkinter,Tkinter Canvas,我试图模拟一个网格,就像游戏板使用的网格一样,将tkinter矩形绘制到画布上,但是我很难制作一个正确的循环 我有一个变量,其中包含一定数量的网格行和一定数量的列,我需要根据这些配置创建一个矩形网格,这些配置可以在应用程序运行时随时更改,这对我来说有点棘手 无论如何,我现在有一个函数可以在屏幕上画一个矩形,如下所示: def _place_empty_tiles(self): self._canvas.update() width = self._canvas.w

我试图模拟一个网格,就像游戏板使用的网格一样,将tkinter矩形绘制到画布上,但是我很难制作一个正确的循环

我有一个变量,其中包含一定数量的网格行和一定数量的列,我需要根据这些配置创建一个矩形网格,这些配置可以在应用程序运行时随时更改,这对我来说有点棘手

无论如何,我现在有一个函数可以在屏幕上画一个矩形,如下所示:

def _place_empty_tiles(self):
        self._canvas.update()
        width = self._canvas.winfo_width()
        height = self._canvas.winfo_height()
        self.x = width / self._game.columns
        self.y = height / self._game.rows
        for i in range(self._game.columns):
            click_point = point.from_pixel(self.x, self.y, width, height)
            self._state.handle_click(click_point)
            self.x += 60

    def _redraw_game_pieces(self)->None:
        '''Delete and redraw all the  of game pieces'''
        self._canvas.delete(tkinter.ALL)
        canvas_width = self._canvas.winfo_width()
        canvas_height = self._canvas.winfo_height()

        for tile in self._state.all_tiles():
            center_x, center_y = tile.center().pixel(canvas_width, canvas_height)

            radius_x = tile.radius_frac() * canvas_width
            radius_y = tile.radius_frac() * canvas_height

            self._canvas.create_rectangle(
                center_x - radius_x, center_y - radius_y,
                center_x + radius_x, center_y + radius_y,
                fill = '#006000', outline = '#000000')
def _place_empty_tiles(self):
    self._canvas.update()
    width = self._canvas.winfo_width()
    height = self._canvas.winfo_height()
    for r in range(self._game.rows -1,-1,-1):
        for c in range(self._game.columns):
            click_point = point.from_pixel(c*30+4, r*30+4, c*30+30, r*30+30)
            self._state.handle_click(click_point)
    self._redraw_game_pieces()
你可能会注意到我有一些自定义的坐标转换方法来补偿屏幕的重新调整。但是,我的问题是在for循环中的函数
\u place\u empty\u tiles(self)
下。假设列的数量为4,它当前将在画布上打印以下内容:

但是,

  • 它实际上是在吵架,而且
  • 那只是一排 考虑到
    self.\u game.columns
    self.\u game.rows
    中存储的行和列的数量,如何创建一个具有类似样式的网格

    更新: 试着以它为基础,我重写了如下函数:

    def _place_empty_tiles(self):
            self._canvas.update()
            width = self._canvas.winfo_width()
            height = self._canvas.winfo_height()
            self.x = width / self._game.columns
            self.y = height / self._game.rows
            for i in range(self._game.columns):
                click_point = point.from_pixel(self.x, self.y, width, height)
                self._state.handle_click(click_point)
                self.x += 60
    
        def _redraw_game_pieces(self)->None:
            '''Delete and redraw all the  of game pieces'''
            self._canvas.delete(tkinter.ALL)
            canvas_width = self._canvas.winfo_width()
            canvas_height = self._canvas.winfo_height()
    
            for tile in self._state.all_tiles():
                center_x, center_y = tile.center().pixel(canvas_width, canvas_height)
    
                radius_x = tile.radius_frac() * canvas_width
                radius_y = tile.radius_frac() * canvas_height
    
                self._canvas.create_rectangle(
                    center_x - radius_x, center_y - radius_y,
                    center_x + radius_x, center_y + radius_y,
                    fill = '#006000', outline = '#000000')
    
    def _place_empty_tiles(self):
        self._canvas.update()
        width = self._canvas.winfo_width()
        height = self._canvas.winfo_height()
        for r in range(self._game.rows -1,-1,-1):
            for c in range(self._game.columns):
                click_point = point.from_pixel(c*30+4, r*30+4, c*30+30, r*30+30)
                self._state.handle_click(click_point)
        self._redraw_game_pieces()
    
    这很接近,但仍然得到一些意想不到的结果:

    Tk演示包括绘制棋盘的演示。有人和您可以检查
    \u draw\u board
    功能,查看如何使用画布矩形创建此类布局的示例:

    def draw_board(canvas):  
        # draw checkerboard
        for r in range(7, -1, -1):
            for c in range(8):
                if c&1 ^ r&1:
                    fill = 'tan3'
                    dfill = 'tan4'
                else:
                    fill = 'bisque'
                    dfill= 'bisque3'
                coords = (c*30+4, r*30+4, c*30+30, r*30+30)
                canvas.create_rectangle(coords, fill=fill, disabledfill=dfill,
                                        width=2, state='disabled')
    

    下面是一个绘制网格的示例,该网格尽可能与窗口匹配。它被设计为在窗口调整大小时重新绘制自身。如果不希望出现这种行为,可以对单元格的宽度和高度进行硬编码

    这些单元格存储在按行和列索引的字典中,以便于引用每个磁贴。单击平铺将在蓝色和红色之间切换。请注意,当窗口调整大小时,它将不记得以前单击过哪些单元格。如果你愿意,这很容易解决

    import Tkinter as tk
    
    class App(tk.Tk):
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, **kwargs)
            self.canvas = tk.Canvas(self, width=500, height=500, borderwidth=0, highlightthickness=0)
            self.canvas.pack(side="top", fill="both", expand="true")
            self.rows = 20
            self.columns = 20
            self.tiles = {}
            self.canvas.bind("<Configure>", self.redraw)
            self.status = tk.Label(self, anchor="w")
            self.status.pack(side="bottom", fill="x")
    
        def redraw(self, event=None):
            self.canvas.delete("rect")
            cellwidth = int(self.canvas.winfo_width()/self.columns)
            cellheight = int(self.canvas.winfo_height()/self.columns)
            for column in range(self.columns):
                for row in range(self.rows):
                    x1 = column*cellwidth
                    y1 = row * cellheight
                    x2 = x1 + cellwidth
                    y2 = y1 + cellheight
                    tile = self.canvas.create_rectangle(x1,y1,x2,y2, fill="blue", tags="rect")
                    self.tiles[row,column] = tile
                    self.canvas.tag_bind(tile, "<1>", lambda event, row=row, column=column: self.clicked(row, column))
    
        def clicked(self, row, column):
            tile = self.tiles[row,column]
            tile_color = self.canvas.itemcget(tile, "fill")
            new_color = "blue" if  tile_color == "red" else "red"
            self.canvas.itemconfigure(tile, fill=new_color)
            self.status.configure(text="you clicked on %s/%s" % (row, column))
    
    if __name__ == "__main__":
        app = App()
        app.mainloop()
    
    将Tkinter作为tk导入
    类应用程序(tk.tk):
    定义初始化(self,*args,**kwargs):
    tk.tk.\uuuuu初始化(self,*args,**kwargs)
    self.canvas=tk.canvas(self,width=500,height=500,borderwidth=0,highlightthickness=0)
    self.canvas.pack(side=“top”、fill=“both”、expand=“true”)
    self.rows=20
    self.columns=20
    self.tiles={}
    self.canvas.bind(“,self.redraw)
    self.status=tk.Label(self,anchor=“w”)
    自我状态包装(side=“bottom”,fill=“x”)
    def重绘(自身,事件=无):
    self.canvas.delete(“rect”)
    cellwidth=int(self.canvas.winfo_width()/self.columns)
    cellheight=int(self.canvas.winfo_height()/self.columns)
    对于范围内的列(self.columns):
    对于范围内的行(self.rows):
    x1=列*单元宽度
    y1=行*单元高度
    x2=x1+单元宽度
    y2=y1+单元高度
    tile=self.canvas.create_矩形(x1,y1,x2,y2,fill=“blue”,tags=“rect”)
    self.tiles[行,列]=tile
    self.canvas.tag_bind(tile,“,lambda事件,行=行,列=列:self.clicked(行,列))
    已单击定义(自身、行、列):
    tile=self.tiles[行,列]
    tile\u color=self.canvas.itemcget(tile,“fill”)
    新颜色=“蓝色”如果瓷砖颜色==“红色”否则为“红色”
    self.canvas.itemconfigure(平铺,填充=新颜色)
    self.status.configure(text=“您单击了%s/%s”%(行、列))
    如果名称=“\uuuuu main\uuuuuuuu”:
    app=app()
    app.mainloop()
    
    我刚刚试过,它没有在画布上画任何东西。它不是一个完整的程序,但如果你将它与
    root=Tk()一起使用;画布=画布(根);canvas.pack(fill=“两者”);画板(帆布);root.mainloop()
    那么它肯定会画出一个棋盘模式。好吧,我设法实现了,并更新了我的问题,但仍然得到奇怪的结果。我的坐标有问题。