pythontkintercanvastkinter-canvas

How can I setup the virtual grid?


I am trying to make a grid system for my tkinter window. I do not know how to do this correctly. This would be a system where I can enter something like 2,2 and it puts it on the grid (with larger squares in this grid).

import tkinter as tk

class Trk:
    def __init__(self,win,blocksx,blocksy,bg="#232627"):
        self.screenwidth = win.winfo_screenwidth()
        self.screenheight = win.winfo_screenheight()
        self.canvas = tk.Canvas(win,width=self.screenwidth,height=self.screenheight,background=bg)
        self.canvas.pack()
        self.background = bg
        self.parent = win
        self.winwidth = win.winfo_width()
        self.winheight = win.winfo_height()
        self.width = self.canvas.winfo_width()
        self.height = self.canvas.winfo_height()
        self.blockx = blocksx
        self.blocky = blocksy
        self.canvas.config(highlightthickness=0)
        self.canvas.update()
    def coordinate(self,row,col):
        """
        Gets the coordinates
        of a certain block.
        """
        row -= 1
        col -= 1
        if row > self.blockx or col > self.blocky or row < 0 or col < 0:
            "raise positionError"
        x = col * (self.width / self.blockx)
        y = row * (self.height / self.blocky)
        print(f"Coordinates for block ({row}, {col}): ({x}, {y})")
        return x, y
    def addLine(self,row1,col1,row2,col2,color="white",width=0.5):
        row1,col1 = self.coordinate(row1,col1)
        row2,col2 = self.coordinate(row2,col2) 
        self.canvas.create_line(row1,col1,row2,col2,fill=color,width=width)
        self.canvas.update()

The coordinate function should split the window into blockx columns and blocky rows, to make a grid that isn't there psychically but can be used to align items (like using addLine()). It does not split correctly and isn't relative to the windows size and what the Trk class is called with. What is the correct equation? 1,1 would be equal to 0,0 in tkinter coordinates. And Trk.blockx and Trk.blocky would be equal to how many blocks there are, so blockx, blocky would be the bottom-right.

To debug, use the coordinate function to get the minimum and maximum coordinates:

from tkinter import *
from terkinter import *
parent = tk.Tk()
canv = Trk(parent,20,40) # these are maximum coordinates
print(canv.coordinate(1,1)) # should be top-left
print(canv.coordinate(20,40)) # maximum coordinates, should be bottom right
# also try adjusting the maximum coordinates to make sure that they can be adjusted.

parent.mainloop()

Solution

    1. You need self.parent.update() to get the correct width and height.

    1. You have a mismatch between parameters and arguments.

    Assuming 20 rows x 40 columns. canv.coordinate(20,40) is expected to be at the bottom right.

    def __init__(..., blocksx, blocksy, ...)
    
    canv = Trk(..., 20, 40) -> blocksx=20, blocksy=40
    

    So you are dividing by the wrong number in the def coordinate.

    x = col * (self.width / self.blockx)

    y = row * (self.height / self.blocky)


    Full example:

    import tkinter as tk
    
    
    class Trk:
        # switch parameters in init
        def __init__(self,win, blocksy, blocksx, bg="#232627"):
            self.screenwidth = win.winfo_screenwidth()
            self.screenheight = win.winfo_screenheight()
            self.canvas = tk.Canvas(win,
                                    width=self.screenwidth,
                                    # Part of the canvas may not be visible.
                                    # I have a Windows taskbar at the bottom.
                                    height=self.screenheight-100,
                                    background=bg,
                                    highlightthickness=0,
                                    bd=0)
            self.canvas.pack()
            self.background = bg
            
            self.parent = win
            self.parent.update() # update to get width and height
            
            self.winwidth = win.winfo_width()
            self.winheight = win.winfo_height()
            self.width = self.canvas.winfo_width()
            self.height = self.canvas.winfo_height()
            self.blockx = blocksx
            self.blocky = blocksy
    
        def coordinate(self,row,col):
            """
            Gets the coordinates
            of a certain block.
            """
            row -= 1
            col -= 1
            if row > self.blocky or col > self.blockx or row < 0 or col < 0:
                print("raise positionError")
            x = col * (self.width / self.blockx)
            y = row * (self.height / self.blocky)
            #print(f"Coordinates for block ({row}, {col}): ({x}, {y})")
            return x, y
        
        def addLine(self,row1,col1,row2,col2,color="red",width=2):
            row1,col1 = self.coordinate(row1,col1)
            row2,col2 = self.coordinate(row2,col2) 
            self.canvas.create_line(row1,col1,row2,col2,fill=color,width=width)
            
    
    parent = tk.Tk()
                    # y, x
    canv = Trk(parent,20,40) # these are maximum coordinates
    # 0, 0
    print(canv.coordinate(1,1)) # should be top-left
    # 19, 39
    print(canv.coordinate(20,40))
    # 20, 40
    print(canv.coordinate(21,41)) # bottom right point
    
    canv.addLine(1, 1, 21, 41) # diagonal
    canv.addLine(21, 1, 1, 41) # diagonal
    canv.addLine(1, 1, 1, 41) # top horizontal
    canv.addLine(21, 1, 21, 41) # bottom horizontal
    canv.addLine(1, 1, 21, 1) # left vertical
    canv.addLine(1, 41, 21, 41) # right vertical
    for row in range(2, 21):
        canv.addLine(row, 1, row, 41)
    for col in range(2, 41):
        canv.addLine(1, col, 21, col)
    canv.canvas.update()