2

I have this code to make each text "clickleable", from the Text() widget that has tkinter. However, when I run the program and click over one text I get this error message witch each corresponding text line:

_tkinter.TclError: bad text index "This is the first string." _tkinter.TclError: bad text index "This is the second string." _tkinter.TclError: bad text index "This is the third string."

If anyone may now a way to solve the issue, I be forever grateful. Here is the complete code:

import tkinter as tk

def text_click(event):
    index = text_widget.tag_names(tk.CURRENT)[0]
    clicked_text = text_widget.get(index)
    print(clicked_text)

# Create the main window
window = tk.Tk()

# Create a Text widget
text_widget = tk.Text(window, wrap="word")
text_widget.pack()

# List of strings
texto = ["This is the first string.", "This is the second string.", "This is the third string."]

# Insert each string from the list
for string in texto:
    text_widget.insert(tk.END, string + "\n")

    # Apply a tag to each inserted string
    tag_start = f"{text_widget.index(tk.END)}-{len(string) - 1}c"
    tag_end = f"{text_widget.index(tk.END)}-1c"
    text_widget.tag_add(string, tag_start, tag_end)

    # Bind the click event to the tag
    text_widget.tag_bind(string, "<Button-1>", text_click)

# Make the text widget read-only
text_widget.configure(state="disabled")

# Start the tkinter event loop
window.mainloop()

I am expecting to print the text of each line when clicked over it.

  • You are using the inserted strings themselves as tag names - but they contain characters that have special meaning in an index expression, so they cannot be passed to `.get()`. (The problematic characters appear to be space, period, `@`, `+`, and `-`.) You will need to choose tag names in some other way - perhaps strip out everything but alphanumerics from the strings, perhaps just use an incrementing number. – jasonharper May 26 '23 at 04:38

2 Answers2

2

If you print out index, you'll see it's the string in the error: "This is the first string.". That is not a valid index. An index needs to be something like line.character or @x,y, and a few other special strings (eg: "end", "current", etc).

I am expecting to print the text of each line when clicked over it.

You can use an index of the form @x,y, and you can use the x and y attributes of the event to create that index. Another alternative is to use the index "current" which represents the character closest to the mouse.

You can use "linestart" and "lineend" to translate that index to the start and end of the line.

Example:

def text_click(event):
    start_index = text_widget.index(f"@{event.x},{event.y} linestart")
    end_index = text_widget.index(f"@{event.x},{event.y} lineend")
    clicked_text = text_widget.get(start_index, end_index)
    print(clicked_text)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • May I get information about `@{event.x}`? I couldn't find on website. – toyota Supra May 26 '23 at 08:45
  • @toyotaSupra: the canonical definition of supported indexes is in the [tcl/tk manual pages](https://tcl.tk/man/tcl/TkCmd/text.htm#M24). The curly braces are part of the syntax for [formatted string literals](https://docs.python.org/3/tutorial/inputoutput.html#tut-f-strings) . You can get help on the attributes of the `event` object by printing out `help(tk.Event)` or `help(event)` on the object itself. – Bryan Oakley May 26 '23 at 16:22
  • Thanks @BryanOakley for your solution approach. I will look for how to use the index in the form of @, x and y. – juan carlos maturana May 26 '23 at 19:00
0

You can modify your text_click function like this:

def text_click(event):
    index = text_widget.index(tk.CURRENT)
    clicked_text = text_widget.get(index + " linestart", index + " lineend")
    print(clicked_text)

This retrieves the index of the clicked text using text_widget.index(tk.CURRENT), then it uses that index to retrieve the actual text by adding the appropriate linestart and lineend modifiers to the index.

Ake
  • 805
  • 1
  • 3
  • 14