How to highlight the current line of a text widget?

I am working on a simple graphical code editor in Python, and I want the line of text that the cursor is sitting on to be constantly highlighted.

Now my TextEditor class looks like this:

 class TextEditor: def __init__(self, container): self.scrollbar = Scrollbar(container) self.scrollbar.pack(side=RIGHT, fill=Y) self.textbox = Text(container, height=40, undo=True, width=80, font=tkFont.Font(family="Consolas", size=12)) self.textbox.pack(side=LEFT) self.textbox.config(yscrollcommand=self.scrollbar.set) self.scrollbar.config(command=self.textbox.yview) 

How can i do this?

+4
source share
2 answers

Nothing is built into tkinter that directly supports this. However, something that is sufficient for most purposes would be to write a function that will query the cursor position and update the highlight at regular intervals.

For instance:

 import Tkinter as tk class MyApp(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) self.text = tk.Text(self) self.text.pack(side="top", fill="both", expand=True) self.text.tag_configure("current_line", background="#e9e9e9") self._highlight_current_line() def _highlight_current_line(self, interval=100): '''Updates the 'current line' highlighting every "interval" milliseconds''' self.text.tag_remove("current_line", 1.0, "end") self.text.tag_add("current_line", "insert linestart", "insert lineend+1c") self.after(interval, self._highlight_current_line) app = MyApp() app.mainloop() 

Obviously, the longer the interval, the greater the โ€œlagโ€, and the shorter the interval, the more the processor will be used, but there will be a rather large sweet spot between the extremes, where there is almost no noticeable delay and an imperceptible bump in CPU usage.

There is another way to do this, which does not include a survey and is absolutely flawless. You can move the selection exactly when the insertion cursor really moves, but it includes writing some Tcl inline code to create a proxy for the real tk widget, which is hidden in the implementation of the Tkinter Text object.

Finally, the third way is to set up custom bindings for all possible events that change the location of the cursor. Although itโ€™s possible, itโ€™s difficult to get 100% right, because you have to take into account all the events that change the cursor position, as well as process places in the code that can move the cursor without using the event. However, using bindings is a great solution, it requires a bit more work.

+6
source

There is absolutely no need to interrogate what Brian Oakley says in his answer , and you do not need to embed Tcl code in your Python code. My solution is to simply bind events that can cause the cursor to move, namely <Key> and <Button-1> .

 import tkinter as tk class CurrentHighlightedLineText(tk.Text): """Text widget with current line highlighted""" def __init__(self, root, *args, **kwargs): tk.Text.__init__(self, root, *args, **kwargs) self.tag_configure('currentLine', background='#e9e9e9') self.bind('<Key>', lambda _: self.highlightCurrentLine()) self.bind('<Button-1>', lambda _: self.highlightCurrentLine()) self.highlightCurrentLine(delay=0) def highlightCurrentLine(self, delay=10): def delayedHighlightCurrentLine(): self.tag_remove('currentLine', 1.0, "end") self.tag_add('currentLine', 'insert linestart', 'insert lineend+1c') # This bound function is called before the cursor actually moves. # So delay checking the cursor position and moving the highlight 10 ms. self.after(delay, delayedHighlightCurrentLine) if __name__ == "__main__": root = tk.Tk() text = CurrentHighlightedLineText(root) text.grid(row=0, column=0, sticky='nesw') root.grid_rowconfigure(0, weight=1) root.grid_columnconfigure(0, weight=1) root.mainloop() 
+2
source

Source: https://habr.com/ru/post/1401240/


All Articles