Tkinter: How to get Label wraplength functionality in Text Box

Discussion in 'Python' started by Mudcat, Oct 28, 2008.

  1. Mudcat

    Mudcat Guest

    I've tried quite a few things to get this correct but have hit a
    couple of sticking points that I can't figure out. I need to ge the
    Text box to function like the 'wraplength' option in a Label.

    I've been able to adjust the height of the text by calculating the
    number of lines needed to display the text. That's fairly simple. I
    know the number of characters in the text and width of the box (which
    is static). From that point I can calculate how many lines of display
    is needed and resize it.

    The problem arises when I use the 'wrap' option of the Text Box so the
    words aren't chopped off. Once the wrapping is done there are dead
    spaces left at the end of the lines which are ignored when the char
    count is done. As a result sometimes the last line is not shown. I can
    always just add +1 to the number, but then sometimes I get an empty
    line. Space is at a premium in this app, so I have to cut everything
    down to use only what's necessary.

    So does anyone know how add in those extra spaces to get this to
    adjust correctly? (Or if there is another way to get the Text Box to
    automatically adjust it's size that I'm not aware of?)

    Thanks
    Mudcat, Oct 28, 2008
    #1
    1. Advertising

  2. On 10/28/08, Mudcat <> wrote:
    > I've tried quite a few things to get this correct but have hit a
    > couple of sticking points that I can't figure out. I need to ge the
    > Text box to function like the 'wraplength' option in a Label.
    >
    > I've been able to adjust the height of the text by calculating the
    > number of lines needed to display the text. That's fairly simple. I
    > know the number of characters in the text and width of the box (which
    > is static). From that point I can calculate how many lines of display
    > is needed and resize it.
    >
    > The problem arises when I use the 'wrap' option of the Text Box so the
    > words aren't chopped off. Once the wrapping is done there are dead
    > spaces left at the end of the lines which are ignored when the char
    > count is done. As a result sometimes the last line is not shown. I can
    > always just add +1 to the number, but then sometimes I get an empty
    > line. Space is at a premium in this app, so I have to cut everything
    > down to use only what's necessary.
    >
    > So does anyone know how add in those extra spaces to get this to
    > adjust correctly? (Or if there is another way to get the Text Box to
    > automatically adjust it's size that I'm not aware of?)
    >


    Are you looking for something like the new "count" command for the
    text widget in tk 8.5 ? "count" can count the number of logical lines
    (irrespective of wrapping), display lines (counts one for each time a
    line wraps) and some other things.


    > Thanks
    >
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >



    --
    -- Guilherme H. Polo Goncalves
    Guilherme Polo, Oct 28, 2008
    #2
    1. Advertising

  3. Mudcat

    Mudcat Guest

    Sounds like that would work really well. Problem is I can't get it to
    work.

    ....
    AttributeError: Text instance has no attribute 'count'
    ....

    I think my usage is correct. I don't have any params at the moment,
    but I was just checking the functionality.

    numlines = widget.count()

    According to the Tk 8.5 documentation it's used just like a normal
    command.
    WIDGET COMMAND
    pathName count ?options? index1 index2
    -chars
    -displaychars
    -displayindices
    -displaylines
    -indices
    -lines
    -xpixels
    -ypixels


    As for the environment, I thought I had everything set up correctly.
    I've got the latest stable version of Python 2.6 (r26:66721, Oct 2
    2008, 11:35:03). I'm implementing the TTK wrappers to access Tk 8.5.
    Although when I check the wrapper I don't see any mods to the Text
    Box. I also don't see this option in the Tkinter.py file.

    Is there something else I need to add to access this new feature?


    On Oct 28, 6:51 pm, "Guilherme Polo" <> wrote:

    >
    > Are you looking for something like the new "count" command for the
    > text widget in tk 8.5 ? "count" can count the number of logical lines
    > (irrespective of wrapping), display lines (counts one for each time a
    > line wraps) and some other things.
    >
    > >  Thanks

    >
    > > --
    > >  http://mail.python.org/mailman/listinfo/python-list

    >
    > --
    > -- Guilherme H. Polo Goncalves
    Mudcat, Oct 29, 2008
    #3
  4. On 10/29/08, Mudcat <> wrote:
    > Sounds like that would work really well. Problem is I can't get it to
    > work.
    >
    > ...
    > AttributeError: Text instance has no attribute 'count'
    > ...
    >


    Yep, it is not there yet.

    > I think my usage is correct. I don't have any params at the moment,
    > but I was just checking the functionality.
    >
    > numlines = widget.count()
    >
    > According to the Tk 8.5 documentation it's used just like a normal
    > command.
    > WIDGET COMMAND
    > pathName count ?options? index1 index2
    > -chars
    > -displaychars
    > -displayindices
    > -displaylines
    > -indices
    > -lines
    > -xpixels
    > -ypixels
    >
    >
    > As for the environment, I thought I had everything set up correctly.
    > I've got the latest stable version of Python 2.6 (r26:66721, Oct 2
    > 2008, 11:35:03). I'm implementing the TTK wrappers to access Tk 8.5.


    Implementing a ttk wrapper won't give you this "count" command, since
    this is a command for an already existing widget (the text widget), it
    is not part of the ttk widgets. Also, there is already a ttk wrapper
    at http://pypi.python.org/pypi/pyttk which is being proposed to be
    included in python's stdlib.

    > Although when I check the wrapper I don't see any mods to the Text
    > Box. I also don't see this option in the Tkinter.py file.
    >
    > Is there something else I need to add to access this new feature?
    >


    You would need to wrap it and add it as a method to the Text class in
    Tkinter. Fortunately it is easily done:

    import Tkinter

    def text_count(self, index1, index2, *options):
    args = ["-%s" % opt for opt in options]
    args.extend([index1, index2])
    return self.tk.call(self._w, "count", *args)

    Tkinter.Text.count = text_count


    Then to try it:


    root = Tkinter.Tk()
    text = Tkinter.Text()
    text.pack()

    text.insert("1.0", "a\nb\c\nd")
    print text.count("1.0", "end", "displaylines", "lines")

    root.mainloop()


    Note that I inverted the order of the arguments here, indices and then
    the options or no options. If it doesn't work saying "count" is not an
    acceptable command then your tkinter is not compiled against tcl/tk
    8.5 or later.

    >
    >
    > On Oct 28, 6:51 pm, "Guilherme Polo" <> wrote:
    >
    > >
    > > Are you looking for something like the new "count" command for the
    > > text widget in tk 8.5 ? "count" can count the number of logical lines
    > > (irrespective of wrapping), display lines (counts one for each time a
    > > line wraps) and some other things.
    > >

    >
    > > > Thanks

    > >
    > > > --
    > > > http://mail.python.org/mailman/listinfo/python-list

    > >

    >
    > > --
    > > -- Guilherme H. Polo Goncalves

    >
    >
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >



    --
    -- Guilherme H. Polo Goncalves
    Guilherme Polo, Oct 29, 2008
    #4
  5. Mudcat

    Mudcat Guest

    I'm not sure why my tkinter would not be compiled against 8.5 since I
    have the latest version. I assumed that Python 2.6 would have it
    without requiring me to do an extra compile.

    However I was able to get it working using the code you gave me.
    Thanks for that. The only problem is that it seems to simply be
    counting newlines (or number of \n). When I use the following:

    numlines = widget.count("1.0", "end", "displaylines", "lines")
    print "Number of lines is ", numlines

    I get this:

    Number of lines is (153, 1)

    So that's not actually the number of lines displayed in the box, just
    the number of newline chars it finds. I couldn't find anything in the
    tk documentation that would give me any other options to count lines
    differently, or number of lines displayed after wrapping.


    On Oct 29, 9:10 am, "Guilherme Polo" <> wrote:

    >
    > You would need to wrap it and add it as a method to the Text class inTkinter. Fortunately it is easily done:
    >
    > importTkinter
    >
    > def text_count(self, index1, index2, *options):
    >     args = ["-%s" % opt for opt in options]
    >     args.extend([index1, index2])
    >     return self.tk.call(self._w, "count", *args)
    >
    > Tkinter.Text.count = text_count
    >
    > Then to try it:
    >
    > root =Tkinter.Tk()
    > text =Tkinter.Text()
    > text.pack()
    >
    > text.insert("1.0", "a\nb\c\nd")
    > print text.count("1.0", "end", "displaylines", "lines")
    >
    > root.mainloop()
    >
    > Note that I inverted the order of the arguments here, indices and then
    > the options or no options. If it doesn't work saying "count" is not an
    > acceptable command then yourtkinteris not compiled against tcl/tk
    > 8.5 or later.
    >
    >
    >
    >
    Mudcat, Oct 30, 2008
    #5
  6. On 10/30/08, Mudcat <> wrote:
    > I'm not sure why my tkinter would not be compiled against 8.5 since I
    > have the latest version. I assumed that Python 2.6 would have it
    > without requiring me to do an extra compile.


    It is not really python's fault if tkinter is compiled against tcl/tk
    8.5 or not. The windows installer for python 2.6 happens to include
    tcl/tk 8.5 and tkinter compiled against them, but ubuntu for example
    doesn't distribute tkinter compiled against tcl/tk 8.5 at the moment.

    >
    > However I was able to get it working using the code you gave me.
    > Thanks for that. The only problem is that it seems to simply be
    > counting newlines (or number of \n). When I use the following:
    >
    > numlines = widget.count("1.0", "end", "displaylines", "lines")
    > print "Number of lines is ", numlines
    >
    > I get this:
    >
    > Number of lines is (153, 1)


    The first is the number of displaylines, the second is the number of lines.

    >
    > So that's not actually the number of lines displayed in the box, just
    > the number of newline chars it finds.


    Not really. displaylines returns the number of lines displayed in the
    text widget, and lines returns the number of newlines found.
    Note that it is important to call "count" only after the text widget
    is being displayed, otherwise displaylines won't work correctly (not
    with tk 8.5.3 at least).

    > I couldn't find anything in the
    > tk documentation that would give me any other options to count lines
    > differently, or number of lines displayed after wrapping.


    Try this and check what you get:


    import Tkinter

    root = Tkinter.Tk()
    text = Tkinter.Text()
    text.pack()

    def test(event):
    print "displaylines:", text.count("1.0", "end", "displaylines")
    print "lines:", text.count("1.0", "end", "lines")

    text.insert("1.0", "a" * 81)
    text.insert("2.0", "b\n")
    text.bind('<Map>', test)

    root.mainloop()


    You should have 3 lines displayed but only 2 "real" lines.


    --
    -- Guilherme H. Polo Goncalves
    Guilherme Polo, Oct 30, 2008
    #6
  7. Mudcat

    Mudcat Guest

    Awesome...there it goes. I guess my main problem was trying to
    evaluate the box before it had been displayed (or all the frame
    propagations were finished). The key was getting the <Map> binding in
    there once I got the count functionality to work. After all
    that...such a simple function:


    def textBoxResize(self, event):
    widget = event.widget
    dispLines = widget.count("1.0", "end", "displaylines")
    widget.config(height=dispLines)


    Thanks for the help!


    On Oct 30, 9:19 am, "Guilherme Polo" <> wrote:
    > On 10/30/08, Mudcat <> wrote:
    >
    > > I'm not sure why my tkinter would not be compiled against 8.5 since I
    > >  have the latest version. I assumed that Python 2.6 would have it
    > >  without requiring me to do an extra compile.

    >
    > It is not really python's fault if tkinter is compiled against tcl/tk
    > 8.5 or not. The windows installer for python 2.6 happens to include
    > tcl/tk 8.5 and tkinter compiled against them, but ubuntu for example
    > doesn't distribute tkinter compiled against tcl/tk 8.5 at the moment.
    >
    >
    >
    > >  However I was able to get it working using the code you gave me.
    > >  Thanks for that. The only problem is that it seems to simply be
    > >  counting newlines (or number of \n). When I use the following:

    >
    > >         numlines = widget.count("1.0", "end", "displaylines", "lines")
    > >         print "Number of lines is ", numlines

    >
    > >  I get this:

    >
    > >  Number of lines is  (153, 1)

    >
    > The first is the number of displaylines, the second is the number of lines.
    >
    >
    >
    > >  So that's not actually the number of lines displayed in the box, just
    > >  the number of newline chars it finds.

    >
    > Not really. displaylines returns the number of lines displayed in the
    > text widget, and lines returns the number of newlines found.
    > Note that it is important to call "count" only after the text widget
    > is being displayed, otherwise displaylines won't work correctly (not
    > with tk 8.5.3 at least).
    >
    > > I couldn't find anything in the
    > >  tk documentation that would give me any other options to count lines
    > >  differently, or number of lines displayed after wrapping.

    >
    > Try this and check what you get:
    >
    > import Tkinter
    >
    > root = Tkinter.Tk()
    > text = Tkinter.Text()
    > text.pack()
    >
    > def test(event):
    >     print "displaylines:", text.count("1.0", "end", "displaylines")
    >     print "lines:", text.count("1.0", "end", "lines")
    >
    > text.insert("1.0", "a" * 81)
    > text.insert("2.0", "b\n")
    > text.bind('<Map>', test)
    >
    > root.mainloop()
    >
    > You should have 3 lines displayed but only 2 "real" lines.
    >
    > --
    > -- Guilherme H. Polo Goncalves
    Mudcat, Oct 30, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Gnarlodious
    Replies:
    4
    Views:
    17,578
    elizas
    May 5, 2010
  2. Praveen
    Replies:
    1
    Views:
    960
    Rob Williscroft
    Nov 5, 2006
  3. CSharpner
    Replies:
    0
    Views:
    1,012
    CSharpner
    Apr 9, 2007
  4. srinivas
    Replies:
    2
    Views:
    193
  5. Knut Krueger
    Replies:
    8
    Views:
    263
    Knut Krueger
    Aug 20, 2013
Loading...

Share This Page