2

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.

Deepak pal
  • 61
  • 8
  • [This question](https://stackoverflow.com/q/51576693/7432) has an example that lets you edit the text of a canvas item. – Bryan Oakley Dec 20 '20 at 18:28
  • @BryanOakley Nice, thank you for sharing, but seems his issue has not yet resolved. I can't remove focus and border from the Text. Can you help me with that ? – Deepak pal Dec 21 '20 at 06:58
  • canvas text items don't have a border, and it's possible to remove the focus from the text so I don't know what you mean. – Bryan Oakley Dec 21 '20 at 15:28

2 Answers2

2

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)

JacksonPro
  • 3,135
  • 2
  • 6
  • 29
  • Also, OP if you found this helpful hit the tickmark beside the answer. If you have any questions regarding the code, comment. – JacksonPro Dec 20 '20 at 11:10
  • Thank you soo much It's almost working for me. Is it possible to remove the border and make the background color transparent of `tk.Entry` ? Also, any possibilities to get the first value that is `TOUCH ME TO EDIT THIS TEXT` inside the Entry box when user clicks on it ? – Deepak pal Dec 21 '20 at 06:03
  • @Deepakpal I don't think you can bake the entry widget have a transparent bg. But there are a few hacks to achieve that, which you may search the net. coming to your second question yes you can do that you have to use `text_box.insert(0, 'Touch Me to edit this')`. I'll make an edit. – JacksonPro Dec 21 '20 at 06:52
  • Please check this question, https://stackoverflow.com/questions/51576693/how-to-remove-icursor-from-tkinter-canvas-text-item I was actually looking for an output something like this – Deepak pal Dec 21 '20 at 07:04
  • 1
    @Deepakpal The only thing you need to add in that is `elif event.keysym == 'Return': self.canvas.delete("highlight") print(self.canvas.focus(""))` under `handle_key`. Otherwise it works perfectly fine. – JacksonPro Dec 21 '20 at 07:23
  • Thank you soo much!!! It works!!!!!!!! One last thing, The code in the link makes all the `canvas.create_text` editable, Is there any way we can make only one or specific `canvas.create_text` editable ? – Deepak pal Dec 21 '20 at 18:27
0

I'd do it like that. But you should consider different windows for Output and control. But here how it works.

from tkinter import *

window = Tk()
canvas = Canvas(window, width=300, height=300, bd=0)
canvas.pack()

def updatetext(): #create a function
    x = newtext.get()
    print(x)
    canvas.itemconfig(tagOrId='text', text = x)

background = PhotoImage(file="background.png")  # can be any background image
canvas.create_image(300, 300, image=background)
newtext = StringVar(value = 'Your new text')

canvas.create_text(20, 70, text='TOUCH ME TO EDIT THIS TEXT', anchor=NW, fill="lime", tag = 'text')
Entry(window, textvariable = newtext).pack()
Button(window, command = updatetext, text = 'Update text').pack()


window.mainloop()

Canvas is now updated with the Update button. And use tags, it is a really powerful thing in Tkinter and very handy. If you want text to be updated without pressing update button then use built-in after.