我正在尝试模拟一个网格,就像使用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')
你可能会注意到我有一些自定义坐标转换方法,以补偿屏幕重新调整大小。但是,我的问题是在for循环中的函数_place_empty_tiles(self)
下。我们假设列数为4,它将在画布上打印出以下内容:
然而,
如何在self._game.columns
和self._game.rows
存储行数和列数的情况下创建类似样式的网格?
更新: 尝试将它关闭The tkinter Knight's Tour Demo我重写了这样的函数:
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()
虽然很接近,但仍有一些意想不到的结果:
答案 0 :(得分:3)
Tk演示包括绘制棋盘的Knight's Tour演示。有人converted it for tkinter你可以检查_draw_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')
答案 1 :(得分:1)
这是一个绘制尽可能贴近窗口的网格的示例。它被设计为在窗口调整大小时重绘自身。如果您不想要这种行为,可以对单元格的宽度和高度进行硬编码。
单元格存储在由行和列索引的字典中,以便于引用每个图块。单击图块将在蓝色和红色之间切换。请注意,当窗口调整大小时,它将不记得以前单击过哪些单元格。如果你愿意,这很容易解决。
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()