Programming the Canvas

A Canvas in tkinter has a function that allows us to draw a line between two or more points. We are going to be using this to draw on the screen, by making multiple tiny connected line segments when we move our mouse on the screen. If you think of the simplest line you can draw, at a minimum, you need to know two different points, each with a corresponding set of coordinates.

Everything in your app has a set of coordinates, that keeps track of how many pixels over (X) from the left and down (Y) from the top of the window something is. So if we have a point on the canvas with the coordinates x = 50 , y = 100, that corresponds to a point that is 50 pixels in from the left hand side, and 100 pixels down from the top. So if we want to draw a simple straight line, we need to keep track of two x coordinates, and two y coordinates.

Think of the very first line segment that our app will draw. When we click initially on the screen, nothing should be drawn, but the instant that we move the mouse away from that spot, the canvas should draw a line between where we initially clicked, and where we moved to. With this in mind, it hopefully makes sense that we should treat the initial click and the movement of the mouse as two separate things that we will need to code. We have to define a function for when we click, and when we drag.

Lets start with the click function, in your code, define a function called “click” like follows. This function is going to take a parameter called an “event”. This event contains the x and y coordinates of where our mouse moved to.

def click(event):

When we click on the screen, we want to set the starting coordinates of the line we are going to draw. Because these are variables we want to use outside of this click function, we should declare these as global variables first, like follows

def click(event):
    global lastX, lastY
    lastX = event.x
    lastY = event.y

Now that we have a starting point, we can begin to code the draw function. Start by defining a function, “draw” that takes an “event” parameter.

def draw(event):

This function will also interact with some variables that are defined outside of its body. For drawing the line, we are going to need the “lastX” and “lastY” variable from our click function, then we are going to need the “pencolor” variable which we will set with the buttons. Make sure that we declare each of these variables as “global” before we use them

def draw(event): 
 
    global lastX, lastY, penColor

Once we have access to those variables, we are going to get the current position of the mouse as well. In your function add the two variables, x and y into your code, and set them to the event.x and event.y attributes. Then, combine all of these things to draw the line with the canvas’s create_line method

def draw(event): 
 
    global lastX, lastY, penColor
    x = event.x
    y = event.y
    drawing.create_line(lastX, lastY, x, y, fill = penColor)
    

The create_line method can also take a width parameter, representing how many pixels wide the line is, and a capstyle parameter, that will help smooth the line out. You can these into your create_line function so it looks as follows.

drawing.create_line(lastX, lastY, x, y, fill = penColor, capstyle = "round", width = 15)

Think about what happens after this function runs for the first time. After we draw a line segment between two points, the next line segment should start where this one ended. To do that via a program like this one, we will want to update the “lastX and lastY” to the new point, after we draw our line. When we add this in, our completed function looks as follows:

def draw(event): 
    # Coordinates. 
    global lastX, lastY, penColor
    x = event.x
    y = event.y
    drawing.create_line(...)
    lastX = x
    lastY = y

The last thing we need to do is use the canvas’s “bind” function to attach our click and draw functions. What “bind” does is allow us to attach a user-defined function to a certain “event”, such as a mouse click, key press, or movement. It is very similar to the “onkeypress” function we used in the turtle program. Add the following lines of code to your program, just before the line “root.mainloop()”

drawing.bind("<Button-1>", click)
drawing.bind("<B1-Motion>", draw)