Reputation: 31
Is there a way to get the start and end index of the visible text in a tkinter text widget?
"myTextWidget.index(CURRENT)" is not what I am looking for, since it only gives me the index of the cursor position.
I want to build a program which search for a word and format all of the word found. However, if there are many words, it takes a lot of time to format all the words. Thus, I only want to format the words which are visible to the user. If the user scrolls up or down, it will again update only the visible text.
I found this post, but this is not what I am looking for: Visible lines in Tkinter text widget
I have included some example code. However, not even this works perfectly. The index of the cursor does not update with all key releases.
from tkinter import *
from tkinter import scrolledtext
def update_visible_text_index(e):
message = "Index of current visible text: " + myText.index(CURRENT)
# "myText.index(CURRENT)" should be replaced with something else
myLabel.config(text = message)
root = Tk()
root.title("My title")
root.geometry("400x400")
myLabel = Label(root, text="Scroll up and down", justify="center")
myLabel.pack()
myText = scrolledtext.ScrolledText(root, wrap=WORD)
myText.pack()
myText.insert('insert', testtext)
myText.bind("<KeyRelease>", update_visible_text_index)
root.mainloop()
Upvotes: 1
Views: 997
Reputation: 385940
Is there a way to get the start and end index of the visible text in a tkinter text widget?
Yes, and the information you need is in the answer you pointed to which you thought wasn't useful. You can use an index of the form @x,y to get the index at the given pixel position. You can use an x,y of 0,0 for the upper left corner, and then compute the height of the widget and use that for the y coordinate of the bottom of the window. Use the index modifier linestart
to adjust the index to the first character of that line.
Note: this may not be pixel perfect and might think the first line is one line above what you see (ie: it may report 20 even if it looks like it's 21). However, I think you can improve the precision by taking into account the borderwidth
and highlightthickness
. It looks like the way you want to use this that being off by one line won't matter.
I've modified your code slightly to update the position whenever you scroll in addition to whenever you release a key to make it easier to test.
from tkinter import *
def update_visible_text_index(widget):
y = widget.winfo_height()
bd = int(widget.cget("borderwidth"))
start_index = widget.index(f"@0,{bd} linestart")
end_index = widget.index(f"@0,{y} linestart")
message = f"Index of current visible text: {start_index}-{end_index}"
myLabel.config(text = message)
def scrollbar_proxy(*args):
vsb.set(*args)
update_visible_text_index(myText)
root = Tk()
root.title("My title")
root.geometry("400x400")
myLabel = Label(root, text="Scroll up and down", justify="center")
myLabel.pack()
myText = Text(root, yscrollcommand=scrollbar_proxy)
vsb = Scrollbar(root, command=myText.yview)
vsb.pack(side="right", fill="y")
myText.pack(side="left", fill="both", expand=True)
for lineno in range(200):
myText.insert("end", f"Line #{lineno+1}\n")
myText.bind("<KeyRelease>", lambda e: update_visible_text_index(e.widget))
root.mainloop()
Upvotes: 1