0

I'm trying to change mouse pointer location when I'm clicking inside of an entry. I use icursor method on entry but It didn't work.

I want pointer move to postion 0, When I clicked inside the entry.

from tkinter import *
from tkinter import ttk


def on_click(event):
    event.widget.icursor(0)  # this will not move cursor to the first place

root = Tk()

e = ttk.Entry(root)
e.pack()

e.insert(0, "Hello World")

e.bind("<1>", on_click)

root.mainloop()

So When I click inside in the entry I want mose pointer move to the first(icursor(0)) but It's not work.

actullay It's work if I get mouse pointer position python will sees me it's on 0 position but the pointer itself isn't in the position 0.

print(e.index(INSERT))

anyone have a idea how to fix this?

2 Answers2

1

This is due to the order in which events are handled in Tkinter.

For a detailed explanation read this answer, but in short events are handled in the order of the bindtags. To see what these are you can print(e.bindtags()) which prints

('.!entry', 'TEntry', '.', 'all')

Here .!entry is the current widget e, TEntry is the ttk Entry class, . is the widget's Toplevel or Tk instance and all is a tag that can be bound to that all widgets have.

Now, when you do e.bind("<1>", on_click), you bind the on_click function to the widget e. When you click the widget, first your on_click function is called which puts the cursor at the start, then the default event for a ttk Entry box is called. The default event from the ttk Entry inherits from the standard Tkinter Entry which, according to the manual, is

Clicking mouse button 1 positions the insertion cursor just before the character underneath the mouse cursor, sets the input focus to this widget, and clears any selection in the widget. Dragging with mouse button 1 strokes out a selection between the insertion cursor and the character under the mouse.

So even though you did put the cursor at position 0, the default Entry event for the mouse button is to change the location of the cursor to where you clicked. Because this is the order in which the events are handled, you never see the cursor at location 0.

However, you can add an event after the default event has been handled. To do this you can add a bindtag after the class and bind to that:

e.bindtags(((str(e)), "TEntry", "post-click", ".", "all"))
e.bind_class("post-click", "<1>", on_click)

This way you bind your callback to a tag that is handled after all those actions mentioned in the quote above, so you will see the cursor to be at position 0.

Do keep in mind that this affects all clicks, including double click, triple click, control-click, ...
(Not dragging by the way, since that ends with a <ButtonRelease-1> event).

fhdrsdg
  • 10,297
  • 2
  • 41
  • 62
1

Alternate Solution

def on_click(event):
    root.after_idle(event.widget.icursor, 0)

Source

Smart Manoj
  • 5,230
  • 4
  • 34
  • 59