Dynamic text color

John Posner jjposner at optimum.net
Thu Dec 31 11:52:56 EST 2009


On Thu, 31 Dec 2009 10:24:44 -0500, Dave McCormick <mackrackit at gmail.com>
wrote:

> 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.

Yup, Dave, I've dug this kind of hole for myself many times!

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

Notes:

* Variable "pos" should be "text" or "complete_text" or something similar.

* The first argument to the get() function must be a string:

       wrong ... complete_text = Tbox.get(1.0, END)
       right ... complete_text = Tbox.get("1.0", END)

But there's a more important problem. Is this function supposed to handle  
*one* word to be colored red, or *all the words* to be colored red? Here's  
what you want to do on each user keystroke:

     1. Use get() to place the entire contents of the Text widget in a
variable, say "complete_text".

     2. Use re.finditer() to generate START,END pairs for the substrings to
be colored red. You might find it easier to create a list from the  
iterator, though it isn't really necessary:

      start_end_pairs = list(re.finditer("red", complete_text))

     3. Loop over the START,END pairs in this list. In each loop, use
tag_add() to tag one of the substrings.

[OOPS: I apologize if my suggestion in the previous post misled you. I  
described the output of finditer() as "a list of (start,end) pairs for an  
invocation of Text.tag_add()". I should have said "a list of (start,end)  
pairs, *WHICH CAN BE LOOPED OVER, FOR A SERIES OF INVOCATIONS* of  
Text.tag_add()".]

Note that the 3 steps above only handle the color red. So you want to  
place these steps in a function, then call the function for each color:

    insert_color_markup(text, "red")
    insert_color_markup(text, "green")
    insert_color_markup(text, "blue")

For each call, pass in the contents of complete_text as the first argument.

So the function-call hierarchy would be:

  get_position()                    <--- invoked on each keystroke
     insert_color_markup()          <--- called once for each color
        get() then finditer() then loop-driven calls to tag_add()

I hope that makes sense to you!


> 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.

Lie Ryan has already pointed you to clarifying documentation. Be sure to  
bookmark http://infohost.nmt.edu/tcc/help/pubs/tkinter/ in your Web  
browser!

> 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...

The point is that *you don't need to*. Handling the text as a simple  
sequence of characters is much simpler than worrying about line/column  
pairs. (If you were using a different shade of red on different lines, you  
*would* need to worry about line/column pairs.)

One more suggestion, which I forgot to make in the previous round. Your  
code includes this:

    Tbox.grid(column=0, row=0, sticky=(N+W+E+S))
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0, weight=1)

You're working too hard here. This is sufficient:

    Tbox.pack()

Keep at it, Dave. I've posted a complete solution at  
http://cl1p.net/jjp_dynamic_text_color/. But I suggest that you put in a  
couple of more hours of coding before peeking at it.

Best,
John



More information about the Python-list mailing list