The following Python code generates a list box and text widget. When I select an option, the cursor should show in the text widget but it does not. However, if I press Tab, the text widget is activated and then I can see the cursor.
import tkinter as tk
list_cursor_pos = ['2.5', '5.10', '8.15']
def on_listbox_select(event):
i = listbox.curselection()[0]
cursor_pos = list_cursor_pos[i]
text_box.focus_set()
text_box.mark_set("insert", cursor_pos)
text_box.see(cursor_pos)
text_box.event_generate('<FocusIn>')
root = tk.Tk()
# Listbox
listbox = tk.Listbox(root)
listbox.pack(side = tk.LEFT, padx=10, pady=10)
for e in list_cursor_pos:
listbox.insert('end', f'Go to {e} in the text')
listbox.bind("<<ListboxSelect>>", on_listbox_select)
# Text box
text_box = tk.Text(root, height=15, width=50)
text_box.pack(side = tk.RIGHT, padx=10, pady=10)
# Create content for text box
content = ""
for i in range(9):
content += f"{i+1}:234567890123456789\n"
text_box.insert("1.0", content)
root.mainloop()
When I do the same using a button instead of a list box, it works.
import tkinter as tk
def set_cursor_pos():
cursor_pos = "2.5"
text_box.focus_set()
text_box.mark_set("insert", cursor_pos)
root = tk.Tk()
myButton = tk.Button(root, text = "Set cursor position at 2.5", command=set_cursor_pos)
myButton.pack(side = tk.LEFT, padx=10, pady=10)
myButton.focus_set()
# Text box
text_box = tk.Text(root, height=15, width=50)
text_box.pack(side = tk.RIGHT, padx=10, pady=10)
content = ""
for i in range(9):
content += f"{i+1}:234567890123456789\n"
text_box.insert("1.0", content)
root.mainloop()
<< >>
means VirtualEvent
, I'm not sure but it may work in different way than normal events in command=
and in < >
. Maybe it runs your code before it sets focus on Listbox
, so your code may set focus on Text
but later tkinter sets it on Listbox
.
I found two methods for this:
after()
to execute focus_set()
little later:def on_listbox_select(event):
i = listbox.curselection()[0]
cursor_pos = list_cursor_pos[i]
text_box.mark_set("insert", cursor_pos)
text_box.see(cursor_pos)
#text_box.event_generate('<FocusIn>')
root.after(100, change_focus)
def change_focus():
text_box.focus_set()
<FocusIn>
in Listbox
to execute itdef on_listbox_select(event):
i = listbox.curselection()[0]
cursor_pos = list_cursor_pos[i]
text_box.mark_set("insert", cursor_pos)
text_box.see(cursor_pos)
#text_box.event_generate('<FocusIn>')
def change_focus(event):
text_box.focus_set()
listbox.bind("<FocusIn>", change_focus)
Full working code used for tests:
I don't know why but if I select element on list and next I use Shift+Arrow
(left, right, up or down) (when cursor is already in text
) then it executes on_listbox_select
again but listbox.curselection()
gives empty list and it raises error on [0]
- so I had to add if not i: return
to solve it.
import tkinter as tk
list_cursor_pos = ['2.5', '5.10', '8.15']
def on_listbox_select(event):
print(event)
i = listbox.curselection()
if not i: # resolve problem with `Shift-Arrow`
return
i = i[0]
cursor_pos = list_cursor_pos[i]
text_box.mark_set("insert", cursor_pos)
text_box.see(cursor_pos)
#text_box.event_generate('<FocusIn>')
#root.after(100, change_focus)
def change_focus(event=None): # I use `event=None` to work with `after()` without changes in this function
text_box.focus_set()
root = tk.Tk()
# Listbox
listbox = tk.Listbox(root, takefocus=0)
listbox.pack(side='left', padx=10, pady=10)
for e in list_cursor_pos:
listbox.insert('end', f'Go to {e} in the text')
listbox.bind("<<ListboxSelect>>", on_listbox_select)
listbox.bind("<FocusIn>", change_focus)
# Text box
text_box = tk.Text(root, height=15, width=50)
text_box.pack(side='right', padx=10, pady=10)
# Create content for text box
content = ""
for i in range(1, 10):
content += f"{i}:234567890123456789\n"
text_box.insert("1.0", content)
root.mainloop()