2015-06-05 2 views
-1

Я пытаюсь смоделировать сетку, как то, что будет использоваться для игрового поля, используя прямоугольники tkinter, нарисованные на холсте, однако у меня возникают проблемы с созданием цикла, который делает это правильно.Сделать сетку с Tkinter Rectangle

Практически у меня есть переменная, которая содержит определенное количество строк для сетки и переменной для количества столбцов, и мне нужно создать сетку прямоугольников на основе тех конфигураций, которые могут измениться в любое время, когда приложение который делает его немного сложным для меня.

В любом случае, я в настоящее время имеют функцию, чтобы нарисовать прямоугольник на экране, как так:

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') 

Вы можете заметил я некоторые пользовательские координатные методы преобразования происходит, чтобы компенсировать экрана повторной калибровки. Однако моя проблема заключается в функции _place_empty_tiles(self) в цикле for. Скажем, количество столбцов 4, он в настоящее время печать на холсте следующее: enter image description here

Однако

  1. это на самом деле делает ряд, и
  2. , что только одна строка.

Как я могу сделать это, так что я могу создать сетку с подобным стилем, учитывая количество строк и столбцов, хранятся в self._game.columns и self._game.rows?

UPDATE: Пробовал основывая его 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() 

который близок, но по-прежнему получать некоторые неожиданные результаты: enter image description here

ответ

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') 
+0

Я только что попробовал, и он ничего не рисует на холсте. – user4422713

+0

Это не полная программа, но если вы используете ее вместе с 'root = Tk(); canvas = Canvas (root); canvas.pack (заполнить = "и"); draw_board (холст); root.mainloop() ', то это, безусловно, нарисует шаблон шахматной доски. – patthoyts

+0

Хорошо, мне удалось реализовать, и я обновил свой вопрос, но я все еще получаю странные результаты. У меня проблемы с координатами. – user4422713

0

Вот пример, который рисует сетку, которая соответствует окну настолько близко, насколько это возможно. Он предназначен для перерисовки при каждом изменении размера окна. Если вы не хотите этого поведения, вы можете жестко закодировать ширину и высоту ячейки.

Ячейки хранятся в словаре, индексированном по строке и столбцу, чтобы упростить обращение к каждой плитке. Нажатие на плитку переключит его между синим и красным. Обратите внимание, что при изменении размера окна он не будет помнить, какие ячейки были предварительно нажаты. Это легко исправить, если вы хотите.

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() 
Смежные вопросы