Dynamic text color

John Posner jjposner at optimum.net
Wed Dec 30 17:18:50 EST 2009


On Wed, 30 Dec 2009 12:58:06 -0500, Dave McCormick <mackrackit at gmail.com>  
wrote:

> Hi All,
>
> I am new to Python and the list so I hope  I am posting this correctly...
>
> I am working on a way to have text automatically formated in a Tkiniter  
> Text widget and would like some input on my code.
> Currently I am using Python 2.5 because the server I use has that  
> installed. Tkinter is tk8.4.
>
> Most of the time when I type red, blue, or green the code works as  
> expected.  When I copy paste text into the widget the last line is  
> parsed with part of the previous lines
> So I guess the problem is in the "looping"?
>
> Here is my code:
> from Tkinter import *
> root = Tk()
> def get_position(event):
>     start = 1.0

A couple of problems here: you define "start", but then never use it.  
Worse, it looks like you don't understand that a line-column index into a  
Tkinter Text widget is a STRING, not a FLOAT.


>     while 1:               pos = Tbox.search("red",END,backwards=TRUE)

I suggest that you use Tbox.get() instead of Tbox.search(), and then use  
Python's more powerful text-search tools. More on this below.


>         if not pos:
>             break
>         red = pos + "-1c"
>         Tbox.tag_add("red", pos, float(pos)+.03)
>         Tbox.tag_config("red", foreground="red")

You don't want to define the "red" tag every time get_position() is  
executed -- that is, every time the user presses a key. Define the  
red/green/blue tags just once, right after you create the Text widget.


>              pos = Tbox.search("blue",END,backwards=TRUE)
>         if not pos:
>             break
>         blue = pos + "-1c"
>         Tbox.tag_add("blue", pos, float(pos)+.04)
>         Tbox.tag_config("blue", foreground="blue")
>
>         pos = Tbox.search("green",END,backwards=TRUE)
>         if not pos:
>             break
>         green = pos + "-1c"
>         Tbox.tag_add("green", pos, float(pos)+.05)
>         Tbox.tag_config("green", foreground="green")

The previous 6 lines are almost identical to the 6 lines that precede  
them. This is fine for prototyping, but when you find yourself writing  
code like this, think about using a loop or a parameterized function call.  
For example, you might write this function:

   def insert_color_markup(color):
       ...

... and then call it as many times as you need to:

   insert_color_markup("red")
   insert_color_markup("green")
   insert_color_markup("blue")

Now, about those text-search tools: the "re" (regular expression) module  
include the function "finditer". This is a real power tool, combining  
regular expressions and Python iterators -- both of which can be  
intimidating to newcomers. But it's just what you want, IMHO. I hope the  
following annotated IDLE transcript convinces you:

Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit  
(Intel)] on win32
>>> import re

>>> text = """The red ball is red, not green. On other other
... hand, the green ball has both red and blue highlights.
... Thank you.
... """

>>> re.finditer("red", text)
<callable-iterator object at 0x00CC46D0>

     ... not too exciting, but this is better:

>>> list(re.finditer("red", text))
[<_sre.SRE_Match object at 0x00C01F70>, <_sre.SRE_Match object at  
0x00C06E20>, <_sre.
SRE_Match object at 0x00C06E58>]

     ... this list indicates that we got three hits on the word "red"

>>> [ matchobj.span() for matchobj in re.finditer("red", text) ]
[(4, 7), (16, 19), (77, 80)]

     ... paydirt: a list of (start,end) pairs for an invocation of  
Text.tag_add()

One more hint: forget about the line-column indexes into the contexts of a  
Text widget. Just count characters from the beginning, e.g.:

    "1.0 + %d chars" % start_position

>         break
>
> Tbox = Text(root,width=40, height=15, wrap=CHAR)
> Tbox.grid(column=0, row=0, sticky=(N+W+E+S))
> root.grid_columnconfigure(0, weight=1)
> root.grid_rowconfigure(0, weight=1)
> Tbox.bind("<KeyRelease>", get_position)
> Tbox.focus()
> root.mainloop()
>
> Thank you,
> Dave

I hope this set of hints is helpful, and not too disjointed, terse, or  
cryptic. I think this is a cute little app!

-John



More information about the Python-list mailing list