Как выделить текущую строку текстового виджета? - PullRequest
4 голосов
/ 14 марта 2012

Я работаю над простым редактором кода GUI на Python и хочу, чтобы строка текста, на которой находится курсор, постоянно выделялась.

Прямо сейчас, мой TextEditorкласс выглядит так:

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)

Как я могу это сделать?

Ответы [ 3 ]

6 голосов
/ 15 марта 2012

В tkinter нет ничего встроенного, что напрямую поддерживает это. Однако для большинства целей достаточно написать функцию, которая опрашивает позицию курсора и обновляет подсветку через равные промежутки времени.

Например:

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()

Очевидно, что чем больше интервал, тем больше будет «лагов», и чем короче интервал, тем больше будет задействовано ЦП, но между крайними точками, где практически нет заметного лага, и довольно незаметное отставание довольно большое, и незаметное увеличение загрузки процессора.

Есть еще один способ сделать это, не включая опрос и абсолютно надежный. Вы можете перемещать выделение точно, когда курсор вставки фактически перемещается, но это требует написания некоторого встроенного кода Tcl для создания прокси фактического виджета tk, который скрыт в реализации объекта Tkinter Text.

Наконец, третий способ - установить пользовательские привязки для всех возможных событий, которые изменяют местоположение курсора. Хотя это возможно, трудно получить 100% правильность, поскольку вы должны учитывать все события, которые изменяют положение курсора, а также обрабатывать места в вашем коде, которые могут перемещать курсор без использования события. Тем не менее, использование привязок - это очень хорошее решение, оно просто требует немного больше работы.

2 голосов
/ 10 мая 2015

Абсолютно нет необходимости опрашивать , как говорит Брайан Оукли в своем ответе , и при этом вам не нужно встраивать код Tcl в код Python. Мое решение состоит в том, чтобы просто привязать события, которые могут в конечном итоге переместить курсор, а именно <Key> и <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()
0 голосов
/ 21 июля 2018

Просто чтобы расширить ответ Брайана Окли: простое выделение текущей строки становится проблемой, когда вы хотите выделить какой-то текст, который включает часть, но не всю, текущей строки, потому что часть текущей строки выбрана окрашены с использованием цвета текущей строки, а не цвета выделенного текста, поэтому с трудом видно, какая часть текущей строки выбрана.

Поэтому я изменил пример кода Брайана, чтобы НЕ выделять текущую строку, если какой-либо текст выделен:

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):
        '''Rehighlights the 'current line' every "interval" milliseconds'''
        self.text.tag_remove("current_line", 1.0, "end")

        # If text is selected, DON'T highlight the current line.
        try:
            text = self.text.get(tk.SEL_FIRST, tk.SEL_LAST)
        except tk.TclError:
            self.text.tag_add("current_line",
                                "insert linestart", "insert lineend+1c")

        self.after(interval, self._highlight_current_line)

app = MyApp()
app.mainloop()

Надеюсь, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...