Jarad
Jarad

Reputation: 18953

Tkinter Text Tagging Range From Start And End Indices Values From wordstart to wordend?

I am attempting to modify some amazing code provided by Bryan Oakley that highlights (tags) words in a tkinter Text widget on a ButtonRelease-1 event.

Instead of highlighting a single word, I'd like to click some text, drag my mouse to another area on the same line (left or right), and highlight that full range from that ranges wordstart and wordend boundaries.

For example, if I click the end of the first line after tk in the code below, drag my mouse to the p of the word import and release my mouse button, I want the tag to expand to capture the full range from 1.0 to 1.20.

The below code uses two tk.StringVar to capture start and end strings but from those two indices obtained, how would I apply these start and end points to the range and then expand to highlight up to the wordstart and wordend range?

import tkinter as tk

class Example(tk.Frame):
  def __init__(self, parent):
    tk.Frame.__init__(self, parent)
    self.text = tk.Text(self, wrap="none")
    self.text.pack(fill="both", expand=True)
    self.start = tk.StringVar()
    self.end = tk.StringVar()

    self.text.bind("<Button-1>", self.button_down)
    self.text.bind("<ButtonRelease-1>", self.button_up)
    #self.text.bind("<B1-Motion>", self._on_click)
    self.text.tag_configure("highlight", background="green", foreground="black")

    with open(__file__, "rU") as f:
      data = f.read()
      self.text.insert("1.0", data)

  def button_down(self, event):
    self.start.set(self.text.index('@%s,%s' % (event.x, event.y)))
    print(self.start.get())

  def button_up(self, event):
    self.end.set(self.text.index('@%s,%s' % (event.x, event.y)))
    print(self.end.get())

if __name__ == "__main__":
  root = tk.Tk()
  Example(root).pack(fill="both", expand=True)
  root.mainloop()

Upvotes: 4

Views: 1957

Answers (2)

Jarad
Jarad

Reputation: 18953

Posting "my" solution (based 99% on Bryan's code and help). If user highlights mouse from left-to-right vs right-to-left, I wasn't sure the "best" way to handle that so I compared the indexes as floats to see which was greater or less than and handled the wordstart and wordend accordingly.

import tkinter as tk

class Example(tk.Frame):
  def __init__(self, parent):
    tk.Frame.__init__(self, parent)
    self.text = tk.Text(self, wrap="none")
    self.text.pack(fill="both", expand=True)
    self.text.bind("<Button-1>", self.button_down)
    self.text.bind("<ButtonRelease-1>", self.button_up)

    self.text.tag_configure("highlight", background="green", foreground="black")

    with open(__file__, "rU") as f:
      data = f.read()
      self.text.insert("1.0", data)

  def button_down(self, event):
    self.xy_down = self.text.index('@%s,%s' % (event.x, event.y))
    self.start = self.text.index('@%s,%s' % (event.x, event.y))

  def button_up(self, event):
    self.stop = self.text.index('@%s,%s' % (event.x, event.y))
    self.xy_up = self.text.index('@%s,%s' % (event.x, event.y))
    if self.xy_down == self.xy_up:
      self.text.tag_remove('highlight', 1.0, 'end')
      self.text.tag_add("highlight", 'insert wordstart', 'insert wordend')
    elif float(self.start) > float(self.stop):
      #print('Highlight right to left')
      self.begin = self.text.index('%s wordend' % (self.start))
      self.end = self.text.index('%s wordstart' % (self.stop))
      self.text.tag_remove('highlight', 1.0, 'end')
      self.text.tag_add("highlight", self.end, self.begin)
      print(self.start, self.stop, self.begin, self.end)
    elif float(self.start) < float(self.stop):
      #print('Highlight left to right')
      self.begin = self.text.index('%s wordstart' % (self.start))
      self.end = self.text.index('%s wordend' % (self.stop))
      self.text.tag_remove('highlight', 1.0, 'end')
      self.text.tag_add("highlight", self.begin, self.end)

if __name__ == "__main__":
  root = tk.Tk()
  Example(root).pack(fill="both", expand=True)
  root.mainloop()

Upvotes: 1

Bryan Oakley
Bryan Oakley

Reputation: 386325

You can append "wordstart" or "wordend" to any valid index. Also, you don't need to use a StringVar -- it adds complexity and provides no extra value over a normal variable:

Here's one way to do it:

def button_down(self, event):
    self.start = self.text.index('@%s,%s wordstart' % (event.x, event.y))

def button_up(self, event):
    self.end = self.text.index('@%s,%s wordend' % (event.x, event.y))

    self.text.tag_add("highlight", self.start, self.end)

Upvotes: 7

Related Questions