0

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()
1
  • what system do you use - Windows, Linux, MacOS? Commented Jun 12 at 9:56

1 Answer 1

0

<< >> 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:

  1. use 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()
  1. use event <FocusIn> in Listbox to execute it
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>')

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()
Sign up to request clarification or add additional context in comments.

1 Comment

There is a very simple way to solve this: Just replace: <<ListboxSelect>> with <ButtonRelease> or <ButtonRelease-1>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.