Programming

Fix TTK Treeview Previous Item on Button-1 Click Tkinter

Why does ttk.Treeview show previous item's text on Button-1 click? Learn event timing issues in Tkinter Treeview and fixes like <<TreeviewSelect>>, ButtonRelease-1, identify_row, after_idle for instant selection updates.

1 answer 1 view

Why does ttk.Treeview show the previous item’s text instead of the newly selected one on <Button-1> click in Tkinter?

I’m creating a Tkinter application that displays the text of a selected Treeview item in a Text widget upon selection. Here’s the code:

python
import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("tk test")
root.geometry("500x300")

def returnText(event):
 global textarea
 textarea.delete("1.0", tk.END)
 textarea.insert("1.0", tree.item(tree.focus())["text"])


tree = ttk.Treeview()
tree.pack(padx=10, pady=10, expand=True, fill=tk.X)

tree.heading("#0", text="contents")

tree.insert("", 0, text="test1")
tree.insert("", 0, text="test2")
tree.insert("", 0, text="test3")

tree.bind("&lt;Button-1&gt;", returnText)

textarea = tk.Text(root)
textarea.pack(expand=True, fill=tk.X, padx=10, pady=10)


root.mainloop()

When I click on a Treeview item, the Text widget updates with the text from the previously selected item, not the current one. The event is bound to &lt;Button-1&gt;, which should trigger on selection. What causes this lag and how can I fix it to show the correct selected item’s text immediately?

When you bind a handler to “” on a ttk.Treeview, that handler runs before the Treeview finishes updating its selection and focus — so calls like tree.focus() or tree.selection() still return the previous item. Use the Treeview virtual event <<TreeviewSelect>>, bind to <ButtonRelease-1>, schedule your update with after_idle, or read the clicked row directly with identify_row() to get the correct text immediately.


Contents


Why tkinter Treeview shows the previous item on

Why does the Text widget show the previously selected item? Because of event timing. A mouse click generates a ButtonPress event (<Button-1>), and user-level bindings you attach to the widget run before the Treeview’s own class-level handling updates the widget’s selection and focus. In short: your callback runs too early, so tree.focus() or tree.selection() still point to the old item when your function executes. This behavior is explained in the Treeview tutorial and in community answers showing the same symptom TkDocs Treeview tutorial and on Stack Overflow (example: the selection-update lag discussion) https://stackoverflow.com/questions/79867729/response-of-selected-values-in-ttk-treeview-lags.

You can think of it like this: the click arrives, your handler sees the state that existed just before the click, then the widget finishes its internal work and updates selection. So handlers bound to <Button-1> will often be “one click behind” unless you explicitly wait or use a later event.


Fixes for ttk Treeview selection lag

Pick the approach that matches what you want:

  • Use the virtual event <<TreeviewSelect>> (recommended)

  • Fired after the selection changes (for mouse, keyboard, or programmatic changes). Great if you want a single, reliable place to react to selection updates.

  • Example usage: tree.bind("<<TreeviewSelect>>", on_select)

  • See the Treeview docs and examples: TkDocs and the Python docs https://docs.python.org/3/library/tkinter.ttk.html.

  • Bind to <ButtonRelease-1>

  • The release event happens after the click processing, so selection is already updated by then. Works well if you only care about mouse clicks.

  • Schedule the update with after_idle() (or after(0))

  • Inside your <Button-1> handler call event.widget.after_idle(...) to run your selection-reading code after Tk finishes processing the click. This is a minimal change if you prefer to keep the original bind.

  • Identify the row under the pointer with identify_row(event.y)

  • If you need the clicked item immediately regardless of selection state (for example, for a right-click context menu), you can call tree.identify_row(event.y) inside a <Button-1> handler to get the item id under the mouse pointer and read its text. This avoids waiting for the widget’s selection machinery.

  • Do NOT return "break" from a <Button-1> handler if you want the widget to do its normal selection update — that would prevent the class binding from executing and block selection entirely.

For background and confirmation that <Button-1> runs before the Treeview updates its internal selection, see community answers and discussions on Stack Overflow that diagnose the same behavior https://stackoverflow.com/questions/30614279/tkinter-treeview-get-selected-item-values and https://stackoverflow.com/questions/75866307/order-of-bindings-in-a-tkinter-treeview-on-single-mouse-click-button-1.


Code examples (fixed handlers)

Below are several concise fixes you can drop into your app. Replace the original tree.bind("<Button-1>", returnText) with one of these.

  1. Recommended — use <> (fires after selection changes)
python
import tkinter as tk
from tkinter import ttk

root = tk.Tk()
tree = ttk.Treeview(root)
tree.pack(fill="x")

# sample data
tree.insert("", "end", text="test1")
tree.insert("", "end", text="test2")
tree.insert("", "end", text="test3")

textarea = tk.Text(root, height=4)
textarea.pack(fill="x")

def on_select(event):
 sel = event.widget.selection()
 if not sel:
 return
 item = sel[0] # first selected item
 textarea.delete("1.0", tk.END)
 textarea.insert("1.0", event.widget.item(item)["text"])

tree.bind("<<TreeviewSelect>>", on_select)

root.mainloop()
  1. Immediate-from-click — use identify_row in the <Button-1> handler
python
def on_click(event):
 item = event.widget.identify_row(event.y)
 if not item:
 return
 textarea.delete("1.0", tk.END)
 textarea.insert("1.0", event.widget.item(item)["text"])

tree.bind("<Button-1>", on_click)

This reads the row under the mouse right away (no waiting). It doesn’t rely on selection having been updated yet.

  1. Keep <Button-1> but schedule the update after Tk finishes processing
python
def on_button1(event):
 # run show_selected_text after all pending events (so selection is updated)
 event.widget.after_idle(show_selected_text)

def show_selected_text():
 sel = tree.selection()
 if sel:
 textarea.delete("1.0", tk.END)
 textarea.insert("1.0", tree.item(sel[0])["text"])

tree.bind("<Button-1>", on_button1)
  1. Or bind to <ButtonRelease-1> — usually the selection is already set then:
python
def on_release(event):
 item = event.widget.identify_row(event.y)
 if item:
 textarea.delete("1.0", tk.END)
 textarea.insert("1.0", event.widget.item(item)["text"])

tree.bind("<ButtonRelease-1>", on_release)

Extra tips and gotchas

  • selection() vs focus(): tree.selection() returns a tuple of selected items (can be multiple in “extended” mode); tree.focus() returns the single focused item. Choose the one that matches your selection mode.
  • Multi-select mode: if your Treeview allows multiple selection, decide whether to display the first selected item or concatenate multiple texts.
  • Right-click menus: right-click often doesn’t change selection; use identify_row() to find the row under the pointer for context menus.
  • Programmatic selection: <<TreeviewSelect>> fires when selection is changed with selection_set() or selection_add(), so it’s the single reliable event to watch.
  • Performance: keep handlers fast. If you must do expensive work on selection, schedule it with after_idle() or run it in a background thread (careful to marshal results back to the UI thread).
  • If you ever change bindtags or customize binding order, be aware that will affect when handlers run relative to the Treeview’s internal behavior.

For practical references and further reading see the Treeview tutorial and the linked Stack Overflow threads that explain the timing and fixes: TkDocs Treeview tutorial, Stack Overflow — selection lag, Stack Overflow — get selected item values.


Sources


Conclusion

The lag comes from binding to <Button-1> which executes before the Treeview updates selection and focus, so your call to tree.focus() returns the previous item. The simplest, most reliable fix is to handle <<TreeviewSelect>>; alternatives are <ButtonRelease-1>, after_idle(), or using identify_row() in a <Button-1> handler depending on whether you want immediate, click-based, or programmatic-selection-aware updates of your tkinter treeview.

Authors
Verified by moderation
Moderation
Fix TTK Treeview Previous Item on Button-1 Click Tkinter