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