Search code examples
pythontkintertkinter-canvastkinter-text

How to have text next to an arrow in tkinter


I am trying to draw an arrow in python's tkinter package which has text written along the arrow. How does one do this? I haven't found a method online


Solution

  • Here is an example by using a Canvas

    import numpy as np
    from tkinter import *
    
    
    # Calculation from https://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python
    def calc_angle(x1, y1, x2, y2):
        p0 = [x1, y1]
        p1 = [x2, y2]
        p2 = [0, y2]
    
        ''' 
        compute angle (in degrees) for p0p1p2 corner
        Inputs:
            p0,p1,p2 - points in the form of [x,y]
        '''
    
        v0 = np.array(p0) - np.array(p1)
        v1 = np.array(p2) - np.array(p1)
    
        angle = np.math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1))
        return round(np.degrees(angle), 2)
    
    
    def create_line_with_text(x1, y1, x2, y2, text):
        # line creation
        canvas.create_line(x1, y1, x2, y2, arrow=LAST)
    
        # angle calculation of given pos
        angle = calc_angle(x1, y1, x2, y2)
    
        # text rotation if arrow form right to left
        if x1 > x2:
            angle += 180
    
        # creates text
        canvas.create_text(x2, y2, anchor=S, angle=angle, text=text)
    
    root = Tk()
    root.geometry("800x600")
    
    canvas = Canvas(root, bg="white", height=800, width=600) # Creating a Canvas to draw on
    canvas.pack(fill=BOTH)
    #                    ( x1,  y1,  x2,  y2)
    create_line_with_text(200, 100, 500, 400, "MyText")
    create_line_with_text(100, 200, 300, 500, "MyText2")
    create_line_with_text(400, 200, 100, 300, "MyText3")
    
    # Manual Line and Text Creation
    # canvas.create_line(200, 100, 500, 400, arrow=LAST) # Draws a Line with an Arrow at the End
    # - the angle of the text should be calculated out of the x's and y's of the line
    # canvas.create_text(340, 190, anchor=NW, angle=-44.99, text="My Text") # Creates Text
    root.mainloop()
    

    Then the output looks like this:

    Example Image

    Note: The create_line has no in-build text parameter. So you need to work with create_text.