Dynamic text color

Dave McCormick mackrackit at gmail.com
Thu Dec 31 10:24:44 EST 2009


John,

Thank you for the tips.
I was changing the line-column index to a FLOAT because the search would 
return the starting position (pos) of the string, then by making it a 
FLOAT and adding the string length I was able to get the end position.
If "red" was on line 1 column 0..
          Tbox.tag_add("red", pos, float(pos)+.03)
       =
          Tbox.tag_add("red", 1.0, 1.3)
It was all I could come up with.

You have convinced me about the re.finditer for this,  I think... 
Still in the prototyping mode:

       def get_position(event):
                pos = Tbox.get(1.0, END)
                match = [ matchobj.span() for matchobj in 
re.finditer("red", pos) ]
                print "match ",match  #debug to shell

Gives all of START,END pairs just fine. It is the last hint about 
line-column indexes that I am have problems with.  All of the 
documentation I can find about "text.tag_add()" uses line-column for 
coordinates.
If I count characters from the beginning how do I know what line the 
text is on? 

Would you mind making your last hint a bit stronger...

Thanks again!
Dave
 


John Posner wrote:
> 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