Search code examples
pythonpython-3.xtkintertkinter-canvastkinter-entry

Is it possible to change the content in canvas.create_text by clicking on it just like in Entry?


Following is my code,

from tkinter import *
 
window = Tk()
canvas = Canvas(window,width=300, height=300, bd=0)
canvas.pack()

background = PhotoImage(file="Images/background.png") # can be any background image
canvas.create_image(300,300,image=background)

canvas_textbox = canvas.create_text(20, 70, text='TOUCH ME TO EDIT THIS TEXT', anchor=NW, fill="lime")
 
window.mainloop()

Is there any possibilities to change the canvas.create_text so that it can function just like Entry (gives the text cursor when user clicks on it for edit text) but looks like canvas.create_text only.


Solution

  • canvas_textbox = canvas.create_text() will return an object id(numeric)

    Firstly, Bind the canvas to the mouse. Then pass the mouse position to closest=canvas.find_closest(x, y), which will return the item(s) id under the x,y position.

    Now check whether the object id text is in the closest. If it is in the closest use create_window to place the Entry widget at the mouse position or the position f your choice.

    Here is the code:

    from tkinter import *
    from PIL import Image, ImageTk
    
    def update(event):
        canvas.delete('entry')
        canvas.itemconfig(tagOrId='text', text=text_box.get())
    
    def clicked(event):
    
        closest = canvas.find_closest(event.x, event.y)# returns the closest item to x, y in the form of tuple
        
        if 2 in closest:
            canvas.itemconfig(tagOrId='text', text='')
            canvas.create_window(event.x, event.y, window=text_box, tag='entry')
        else:
            print('No')
    
    window = Tk()
    canvas = Canvas(window,width=300, height=300, bd=0)
    canvas.pack()
    
    background = ImageTk.PhotoImage(Image.open(r"\path.jpg")) # can be any background image
    canvas.create_image(300,300,image=background)
    
    canvas_textbox = canvas.create_text(20, 70, text='TOUCH ME TO EDIT THIS TEXT', anchor=NW, fill="lime", tag='text')
    text_box = Entry(window)
    text_box.bind('<Return>', update)
    
    print(canvas.find_all()) # returns all the items in canvas as tuple
    
    canvas.bind('<Button>', clicked)
    
    window.mainloop()
    

    Or you may also try this:

    from tkinter import *
    from PIL import Image, ImageTk
    
    def update(event):
        canvas.delete('entry')
        canvas.itemconfig(tagOrId='text', text=text_box.get())
    
    def clicked(event):
    
        closest = canvas.find_closest(event.x, event.y)# returns the closest item to x, y in the form of tuple
        x, y = canvas.coords(closest)
        
        if canvas_textbox in closest:
            canvas.itemconfig(tagOrId='text', text='')
            canvas.create_window(x+100, y, window=text_box, tag='entry')
    
        else:
            print('No')
    
    window = Tk()
    canvas = Canvas(window,width=300, height=300, bd=0)
    canvas.pack()
    
    background = ImageTk.PhotoImage(Image.open(r"\image")) # can be any background image
    canvas.create_image(300,300,image=background)
    
    canvas_textbox = canvas.create_text(20, 70, text='TOUCH ME TO EDIT THIS TEXT', anchor=NW, fill="lime", tag='text')
    text_box = Entry(window, borderwidth=0, highlightthickness=0)
    text_box.insert(0, 'TOUCH ME TO EDIT THIS TEXT')
    print(canvas.coords(2))
    text_box.bind('<Return>', update)
    
    print(canvas.find_all()) # returns all the items in canvas as tuple
    
    canvas.bind('<Double-1>', clicked) 
    
    window.mainloop()
    

    (double click on the text)