简体   繁体   中英

Python Tkinter Canvas does not appear

Hello I got a problem with using the Tkinter package on python. I want to create a window containing two major widgets of which one is a canvas that will later show a grid with cells. When initializing the canvas I use "create_rectangle" to fill the canvas with the desired objects. Also when clicking on a cell (for testing reasons) the canvas should change its color in the area of the rectangle. However when initialy displaying the window at first no objects can be seen (the expected result would be only white colored rectangles) and only when a Click on the canvas is performed the area changes its color as desired. While looking through the internet I tried several variations of the order of the pack()- and create_rectangle()-methods. This is the code:

from tkinter import *
from tkinter.ttk import *
import cells

GRID_WIDTH = 15
GRID_HEIGHT = 15


class Ui(Frame):
    """ Class to represent the ui of conways game of life"""

    def __init__(self, parent, grid):
        self.parent = parent
        self.grid = grid
        Frame.__init__(self, parent)
        self.__setup()

    def __setup(self):
        """ Method to setup the components of the ui """
        self.parent.title("Conway's game of life")
        self.pack()

        #Setup a frame to hold control components
        frame_cntrl = Frame(self)
        frame_cntrl.pack(side = RIGHT, anchor="n")
        self.__setup_cntrl_components(frame_cntrl)

        #Setup a frame to hold the Grid
        self.canvas = Canvas(self)
        self.canvas.pack(side = LEFT)
        self.__draw_grid()
        self.canvas.bind("<Button-1>", self.__canvas_clicked)


    def __setup_cntrl_components(self, parent):
        """ Method to setup the control elements of the ui"""
        #Setup a label for the generation
        self.lb_generation = Label(parent, text="dummy")
        self.lb_generation.pack(side = TOP)

        #Setup a button for iteration
        self.bt_iteration = Button(parent, text="Iterate")
        self.bt_iteration.pack(side = TOP)



    def __draw_cell(self, x, y):
        """ Draws a cell on the canvas"""
        width, height = self.canvas.winfo_width(), self.canvas.winfo_height()
        color = "black" if self.grid.cell_alive(x, y) else "white"
        x0 = width * x / self.grid.width + 1
        x1 = width * (x + 1) / self.grid.width
        y0 = height * y / self.grid.height + 1
        y1 = height * (y + 1) / self.grid.height
        self.canvas.create_rectangle(x0, y0, x1, y1, width=0, fill=color)

    def __draw_grid(self):
        """ Method to setup the grid itself"""
        width, height = self.canvas.winfo_width(), self.canvas.winfo_height()
        for i in range(0, self.grid.width):
            for j in range(0, self.grid.height):
                self.__draw_cell(i, j)


    def __canvas_clicked(self, event):
        """ Method for when the cell was clicked """
        x, y, width, height = event.x, event.y, self.canvas.winfo_width(), self.canvas.winfo_height()
        cell_x = int(x / width * self.grid.width)
        cell_y = int(y / height * self.grid.height)
        self.grid.switch_cell(cell_x, cell_y)
        self.__draw_cell(cell_x, cell_y)




if __name__ == "__main__":
    Ui(Tk(), cells.Grid(GRID_WIDTH, GRID_HEIGHT)).mainloop()

Problem 1 :

Your main problem is that, before the canvas is actually displayed, canvas.winfo_width() and canvas.winfo_height() do not return the canvas width and height, but the value 1 .

I suggest you create the canvas as follows:

# Define canvas and save dimensions
self.canvas_width = 300
self.canvas_height = 200
self.canvas = Canvas(self, width = self.canvas_width, 
                           height = self.canvas_height)

Then, in your code, replace each instance of:

width, height = self.canvas.winfo_width(), self.canvas.winfo_height()

with

width, height = self.canvas_width, self.canvas_height

Problem 2:

When creating each cell I don't think you need to add 1 to x0 and y0 . Instead, it should be:

x0 = width * x / self.grid.width
x1 = width * (x + 1) / self.grid.width
y0 = height * y / self.grid.height
y1 = height * (y + 1) / self.grid.height

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM