Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #83178 > unrolled thread

apostrophe not considered with tkinter's wordstart and wordend

Started byravas <ravas@outlook.com>
First post2015-01-03 12:28 -0800
Last post2015-01-24 21:20 -0800
Articles 10 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  apostrophe not considered with tkinter's wordstart and wordend ravas <ravas@outlook.com> - 2015-01-03 12:28 -0800
    Re: apostrophe not considered with tkinter's wordstart and wordend Peter Otten <__peter__@web.de> - 2015-01-03 22:06 +0100
    Re: apostrophe not considered with tkinter's wordstart and wordend Rick Johnson <rantingrickjohnson@gmail.com> - 2015-01-04 16:33 -0800
      Re: apostrophe not considered with tkinter's wordstart and wordend ravas <ravas@outlook.com> - 2015-01-05 00:01 -0800
        Re: apostrophe not considered with tkinter's wordstart and wordend Rick Johnson <rantingrickjohnson@gmail.com> - 2015-01-05 05:20 -0800
          Re: apostrophe not considered with tkinter's wordstart and wordend Christian Gollwitzer <auriocus@gmx.de> - 2015-01-22 23:26 +0100
            Re: apostrophe not considered with tkinter's wordstart and wordend Rick Johnson <rantingrickjohnson@gmail.com> - 2015-01-24 18:56 -0800
              Re: apostrophe not considered with tkinter's wordstart and wordend ravas <ravas@outlook.com> - 2015-01-24 19:17 -0800
                Re: apostrophe not considered with tkinter's wordstart and wordend Rick Johnson <rantingrickjohnson@gmail.com> - 2015-01-24 19:57 -0800
                  Re: apostrophe not considered with tkinter's wordstart and wordend ravas <ravas@outlook.com> - 2015-01-24 21:20 -0800

#83178 — apostrophe not considered with tkinter's wordstart and wordend

Fromravas <ravas@outlook.com>
Date2015-01-03 12:28 -0800
Subjectapostrophe not considered with tkinter's wordstart and wordend
Message-ID<e6143cd5-3475-431a-b2cf-17fd9659681c@googlegroups.com>
When I place my mouse over a word (and I press something) 
I want the program to analyze the word.
Tkinter almost provides the perfect option:
self.text.get('current wordstart', 'current wordend')

Unfortunately apostrophes are not considered using wordstart and wordend.
http://infohost.nmt.edu/tcc/help/pubs/tkinter/
Says: 
"For the purposes of this operation, a word is either 
a string of consecutive letter, digit, or underbar (_) characters, 
or a single character that is none of these types."

The easy work around is to highlight the word and use:
self.text.get('sel.first', 'sel.last')

However, it seems like it could be an easy improvement 
if we could include the apostrophe in the list of word characters.
Is it possible that this could be added in an upcoming version of Python -- 
or is this a Tk issue?

----
Windows 7 & Python 3.4

[toc] | [next] | [standalone]


#83180

FromPeter Otten <__peter__@web.de>
Date2015-01-03 22:06 +0100
Message-ID<mailman.17359.1420319198.18130.python-list@python.org>
In reply to#83178
ravas wrote:

> When I place my mouse over a word (and I press something)
> I want the program to analyze the word.
> Tkinter almost provides the perfect option:
> self.text.get('current wordstart', 'current wordend')
> 
> Unfortunately apostrophes are not considered using wordstart and wordend.
> http://infohost.nmt.edu/tcc/help/pubs/tkinter/
> Says:
> "For the purposes of this operation, a word is either
> a string of consecutive letter, digit, or underbar (_) characters,
> or a single character that is none of these types."
> 
> The easy work around is to highlight the word and use:
> self.text.get('sel.first', 'sel.last')
> 
> However, it seems like it could be an easy improvement
> if we could include the apostrophe in the list of word characters.
> Is it possible that this could be added in an upcoming version of Python
> -- or is this a Tk issue?

I think it is.

<http://www.tcl.tk/man/tcl8.6/TkCmd/text.htm#M41> does not mention a way to 
configure the set of word chars either:

"""
?submodifier? wordstart
Adjust the index to refer to the first character of the word containing the 
current index. A word consists of any number of adjacent characters that are 
letters, digits, or underscores, or a single character that is not one of 
these. If the display submodifier is given, this only examines non-elided 
characters, otherwise all characters (elided or not) are examined.
"""

[toc] | [prev] | [next] | [standalone]


#83223

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2015-01-04 16:33 -0800
Message-ID<655cce0d-2db3-4a0d-ab3d-64d5db5e1634@googlegroups.com>
In reply to#83178
On Saturday, January 3, 2015 2:28:18 PM UTC-6, ravas wrote:

> Is it possible that this could be added in an upcoming
> version of Python -- or is this a Tk issue?

A quick look at the Tkinter.Text.get source code will answer
that question for you:

py> import inspect
py> from Tkinter import Text
py> print inspect.getsource(Text.get)
    def get(self, index1, index2=None):
        """Return the text from INDEX1 to INDEX2 (not included)."""
        return self.tk.call(self._w, 'get', index1, index2)

As you can see, this method is just a dumb wrapper. There is
no "python-side" processing going on here. Which is true for
just about the entire Tkinter module.

I'm not sure if you can edit the pre-defined "word capture
patterns" that exist within TK (never had the need to find
out), but you could implement any pattern matching you want
by binding the correct events and then processing the
"target string" on the Python side. 

However, i would say that not allowing customization of
patterns is a major flaw of the API, and one more reason why
Tkinter is a rusty old "Clostridium tetani infected" anchor
around Python's neck!

   FOR GUIDO'S SAKE, BE SURE YOUR IMMUNIZATIONS ARE UP TO DATE!

[toc] | [prev] | [next] | [standalone]


#83225

Fromravas <ravas@outlook.com>
Date2015-01-05 00:01 -0800
Message-ID<714d9211-9b50-4e62-a7dd-25ff94a32d8a@googlegroups.com>
In reply to#83223
Thanks guys :-]

Rick Johnson:
> but you could implement any pattern matching you want
> by binding the correct events and then processing the
> "target string" on the Python side. 

I'm curious about what events you would use.
The only work around I thought of is to
create a word list and then apply tags & use tag_bind().

[toc] | [prev] | [next] | [standalone]


#83239

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2015-01-05 05:20 -0800
Message-ID<f1bcb866-b07f-478d-83a4-dcf4b2b096e5@googlegroups.com>
In reply to#83225
On Monday, January 5, 2015 2:01:22 AM UTC-6, ravas wrote:
> I'm curious about what events you would use. The only work
> around I thought of is to create a word list and then
> apply tags & use tag_bind().

Well i'm not sure what you are doing exactly, so i'll have
to take some liberties here, but i don't foresee "tag_bind"
as helping you. In order to use the binding applied to a
tag, you'll first have to apply the tag to the range of the
text containing the "target word"... (Ahhh, the old "quid
pro quo brings back a good memory!)

    https://www.youtube.com/watch?v=qr2bKXBV67o

then and only then could you expect an event to fire. I was
thinking more of binding on the "widget level". Here is what
you said earlier:

> When I place my mouse over a word (and I press something)
> I want the program to analyze the word. Tkinter almost
> provides the perfect option: but [...]

From *that* description, a simple binding of "<Button-1>" to
a callback will give you the chance to process the "word" on
the Python side. Of course, that's easier said than done my
friend!

O:-)

Because (in your case) you cannot rely on the "TK wordstart
pattern" to define the edges correctly,  you'll have to
capture the entire line, THEN compute the location of the
cursor within the sub-string ("local offset in absolute
terms"), THEN back pedal until you find the first space (or
whatever defines the start of a word in your app), THEN use
the re module (or some other method) to find the end of the
word (if it exists at all), THEN if it does, do something.

*GASP*! Of course all this could be avoided if those short-
sighted TK folks would have allowed the programmer to define
the pattern! 

ಠ_ಠ

One thing to consider though: left-mouse-down is a common
event for most of us --except for those few immortals among
us who have sworn to a "mouse free life"[1] and have
officially completed space cadet training--  and you don't
want Python doing all that work for nothing! So unless you
can justify all that processing for every left-mouse-down
event, i would suggest using another event.

[1]: Of which the phrase would make for interesting
satirical replacement of the chorus in: little orphan
Annie's, "it's a hard knock life".

    It's a mouse free life, for us...
    It's a mouse free life, for us...
    Instead of clicks, WE get pecks...
    It's a mouse free life!

[toc] | [prev] | [next] | [standalone]


#84283

FromChristian Gollwitzer <auriocus@gmx.de>
Date2015-01-22 23:26 +0100
Message-ID<m9rtd8$15e$1@dont-email.me>
In reply to#83239
Am 05.01.15 um 14:20 schrieb Rick Johnson:
> *GASP*! Of course all this could be avoided if those short-
> sighted TK folks would have allowed the programmer to define
> the pattern!
>
> ಠ_ಠ

Well, it turns out you actually can. We don't have Guido's time machine, 
but still there is a configuration option in Tk, albeit a very obscure 
one: you have to set the global Tcl variables tcl_wordchars and 
tcl_nonwordchars after loading Tk to a regexp which defines the word 
boundaries:

	http://wiki.tcl.tk/1655

Strangely, there is a different preset for Windows and X11. The Windows 
preset - consider everything besides space as part of the word - makes 
more sense to me than the Unix default, which only counts letters, 
numbers and underscores as part of the word. To set the Windows preset, 
do this:

tk.eval('set tcl_wordchars {\S}');
tk.eval('set tcl_nonwordchars {\s}');

(untested in Python, only tested directly from a wish shell)


	Christian

[toc] | [prev] | [next] | [standalone]


#84546

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2015-01-24 18:56 -0800
Message-ID<c1bc4c74-0360-4816-884a-4ebff24e2bab@googlegroups.com>
In reply to#84283
On Thursday, January 22, 2015 at 4:26:29 PM UTC-6, Christian Gollwitzer wrote:

> Well, it turns out you actually can. We don't have Guido's
> time machine, but still there is a configuration option in
> Tk, albeit a very obscure one: you have to set the global
> Tcl variables tcl_wordchars and tcl_nonwordchars after
> loading Tk to a regexp which defines the word boundaries:
> 
> 	http://wiki.tcl.tk/1655
> 
> Strangely, there is a different preset for Windows and
> X11. The Windows preset - consider everything besides
> space as part of the word - makes more sense to me than
> the Unix default, which only counts letters, numbers and
> underscores as part of the word. To set the Windows
> preset, do this:
> 
> tk.eval('set tcl_wordchars {\S}');
> tk.eval('set tcl_nonwordchars {\s}');
> 
> (untested in Python, only tested directly from a wish shell)

Hmm. Thanks for posting this, but i could not get it to
work??? I tried all sorts of sensible patterns but
nothing works.

Below is a simple testing app with bindings which highlight the
word under the mouse like the OP requested. If you can modify
the word boundaries so that it captures the equivalent of this
pattern r"'\w+'", then i will write a wrapper method for the
Tkinter module for arbitrarily modifying the boundaries. 

Here is the code, happy hacking ;-)

## START CODE ##

import Tkinter as tk
from Tkconstants import YES, BOTH, END

SIDX = '1.0'
STR = """
My humble dictators,
ask not what the 'boot_lickers' can do for you,
ask what *YOU* can do to for *YOUR* community!
"""

class MyText(tk.Text):
    def __init__(self, master, **kw):
        tk.Text.__init__(self, master, **kw)
        self.bind("<Button-1>", self.evtButtonOneDown)
        self.tag_add('hit', END)
        self.tag_config('hit', background='red')

    def evtButtonOneDown(self, event):
        sLC = self.index('current wordstart')
        eLC = self.index('current wordend')
        print 'hitspan from {0!r} to {1!r}'.format(sLC, eLC)
        self.tag_remove('hit', SIDX, 'end')
        self.tag_add('hit', sLC, eLC)
        
if __name__ == '__main__':
    root = tk.Tk()
##    root.eval("set tcl_wordchars {psst: over here!}")
##    root.eval("set tcl_nonwordchars {psst: and here too!}")
    et = MyText(root, undo=True)
    et.insert(SIDX, STR)
    et.pack(fill=BOTH, expand=YES)
    root.mainloop()
    
## END CODE ##

[toc] | [prev] | [next] | [standalone]


#84547

Fromravas <ravas@outlook.com>
Date2015-01-24 19:17 -0800
Message-ID<b1ea0c95-38aa-47b8-a8a2-dd80c3dcb8a5@googlegroups.com>
In reply to#84546
We resolved it over at the comp.lang.tcl group.
It turns out what Christian suggested affects what is selected when you double click a word. He later discovered a different method for producing what I want.
Below is my test code that implements both of these things
(tested with Python 3.4 and PyCharm).

import tkinter
import tkinter.messagebox as messagebox

class Creator(object):

    def __init__(self):

        root = self.root = tkinter.Tk()
       
        # Main Frame
        f_main = tkinter.Frame(root, borderwidth=6, relief='flat')
        f_main.grid(row=0, column=0, sticky='nsew')

        # Text widget, its font and frame
        f_txt = tkinter.Frame(f_main, borderwidth=2, relief="sunken")
        f_txt.config(width=768, height=768)

        f_txt.grid_propagate(False)  # ensures a consistent GUI size
        f_txt.pack(padx=4, pady=4, side="bottom", fill="both", expand=True)

        my_txt = tkinter.Text(f_txt, name='t')
        my_txt.config(undo=True, wrap='word')
        my_txt.grid(row=0, column=0, sticky="nsew")
        self.text = my_txt

        # Scrollbar and config
        f_scroll = tkinter.Frame(root, borderwidth=4, relief="groove")
        f_scroll.grid(row=0, column=1, sticky='nsew')
        scrollbar = tkinter.Scrollbar(f_scroll, command=my_txt.yview)
        scrollbar.pack(side='left', fill='y', pady=2, padx=0, expand=True)

        my_txt.config(yscrollcommand=scrollbar.set)
        scrollbar.columnconfigure(0, weight=1)

        # Stretchable
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
        f_main.columnconfigure(0, weight=1)
        f_main.rowconfigure(0, weight=1)
        f_txt.rowconfigure(0, weight=1)
        f_txt.columnconfigure(0, weight=1)

        my_txt.bind("<ButtonRelease-3>", self.test)
        my_txt.focus_set()

    def test(self, event=None):
        txt = str(self.text)
        a = "::tk::TextPrevPos {} current tcl_wordBreakBefore".format(txt)
        b = "::tk::TextNextPos {} current tcl_wordBreakAfter".format(txt)
        ind1 = self.root.tk.eval(a)
        ind2 = self.root.tk.eval(b)
        x = self.text.get(ind1, ind2)
        messagebox.showinfo('info', x)

# ===========================================================================
# start up
# ===========================================================================

GUI = Creator()
GUI.root.tk.eval("catch {tcl_endOfWord}")
GUI.root.tk.eval("catch {tcl_startOfPreviousWord}")
GUI.root.tk.eval("set tcl_wordchars {[[:alnum:]']}")
GUI.root.tk.eval("set tcl_nonwordchars {[^[:alnum:]']}")
GUI.root.mainloop()

[toc] | [prev] | [next] | [standalone]


#84550

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2015-01-24 19:57 -0800
Message-ID<f7664734-b001-4b56-a0cd-38c8e2125da8@googlegroups.com>
In reply to#84547
On Saturday, January 24, 2015 at 9:17:57 PM UTC-6, ravas wrote:
> We resolved it over at the comp.lang.tcl group. It turns
> out what Christian suggested affects what is selected when
> you double click a word. He later discovered a different
> method for producing what I want. Below is my test code
> that implements both of these things

Great. I did not run the code so i'll take your word that
it solved the issue for you. *wink* 

However, i must admit i did find your design a bit strange
to my eyes though. It seems you may be encapsulating too
much in that Creator class, whilst not exposing enough.  I
wonder why you did not subclass a tk.Text? 

Also, instead of packing multiple frames into a "master
grid" you could just use the grid for everything and remove
all those frames -- might help reduce some syntactical
density.

But hey, if you're happy, no need to change it! Working code
is better than incomprehensible code. In any event, i'm
happy you guys sorted it out. Posting a solution for the
next guy is always a good thing to do. 

[toc] | [prev] | [next] | [standalone]


#84555

Fromravas <ravas@outlook.com>
Date2015-01-24 21:20 -0800
Message-ID<9b69dde6-eb25-40f3-bb00-5f21a0ec134c@googlegroups.com>
In reply to#84550
I copied the GUI creation from my personal text editor. 
The scrollbar and stretchability could have been left out, for sure. 
You're only seeing a portion of a more complex GUI.

After writing several Tkinter applications, 
I decided that subclassing without a clear reason 
only had the effect of polluting the namespace of my class. 
I like seeing only my attributes and methods during code completion.

Thanks for your interest and help.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web