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).