Tkinter or Python issue?

Discussion in 'Python' started by Ron Provost, Oct 19, 2005.

  1. Ron Provost

    Ron Provost Guest

    Hello,

    I'm using python 2.4.2 on Win XP Pro. I'm trying to understand a behavior
    I'm seeing in some Tkinter code I have. I've reduced my question to a small
    piece of code:


    #####BEGIN CODE
    #################
    import Tkinter as Tk
    import tkFont

    sampleText = """Here is a test string. This is more text
    Here is a second line of text. How much
    more can I type. I can't think of anything else to type.
    """

    root = Tk.Tk( )
    t = Tk.Text( root )
    t.pack( )

    t.insert( Tk.END, sampleText )

    t.tag_config( 'AB', font=tkFont.Font( family='ariel', size=24,
    weight=tkFont.BOLD ) )
    t.tag_config( 'TBU', font=tkFont.Font( family='times', size=10,
    weight=tkFont.BOLD, underline=1 ) )

    t.tag_add( 'AB', '1.8', '1.15' )
    t.tag_add( 'TBU', '2.10', '2.30' )

    root.mainloop( )
    #################
    #######END CODE

    Now when I run this I expect to see a small bit of the sampleText in ariel
    bold and another bit in times bold underline, instead I see both bits in the
    later style. Interestingly, if I create the Font objects before calling
    t.tag_config() (i.e. replace the two t.tag_config( ) lines with the
    following):


    f1 = font=tkFont.Font( family='ariel', size=24, weight=tkFont.BOLD )
    f2 = font=tkFont.Font( family='times', size=10, weight=tkFont.BOLD,
    underline=1 )
    t.tag_config( 'AB', font=f1 )
    t.tag_config( 'TBU', font=f2 )


    In rerunning the code, I see each bit of text now styled differently. This
    is the behavior that I both expect and want. Does anybody know why the two
    bits of code result in different behavior? Is it a Python thing or a
    Tkinter thing?

    Thanks for your feedback.

    Ron
     
    Ron Provost, Oct 19, 2005
    #1
    1. Advertising

  2. "Ron Provost" <> wrote in message
    news:98i5f.3686$vS1.1306@dukeread03...
    > [snip]
    > t.insert( Tk.END, sampleText )
    >
    > t.tag_config( 'AB', font=tkFont.Font( family='ariel', size=24,
    > weight=tkFont.BOLD ) )
    > t.tag_config( 'TBU', font=tkFont.Font( family='times', size=10,
    > weight=tkFont.BOLD, underline=1 ) )
    >
    > t.tag_add( 'AB', '1.8', '1.15' )
    > t.tag_add( 'TBU', '2.10', '2.30' )
    >
    > root.mainloop( )
    > [snip]


    tkFont.Font(...) is a class instance, while you need font description.
    Try:
    t.tag.config( 'TBU', font=('times', 12, 'bold','underline') )
    t.tag_config( 'AB', font=('arial',24,'bold') )

    Eugene
     
    Eugene Druker, Oct 19, 2005
    #2
    1. Advertising

  3. Ron Provost

    Eric Brunel Guest

    On Tue, 18 Oct 2005 22:30:33 -0400, Ron Provost <> wrote:

    > Hello,
    >
    > I'm using python 2.4.2 on Win XP Pro. I'm trying to understand a behavior
    > I'm seeing in some Tkinter code I have. I've reduced my question to a small
    > piece of code:
    >
    >
    > #####BEGIN CODE
    > #################
    > import Tkinter as Tk
    > import tkFont
    >
    > sampleText = """Here is a test string. This is more text
    > Here is a second line of text. How much
    > more can I type. I can't think of anything else to type.
    > """
    >
    > root = Tk.Tk( )
    > t = Tk.Text( root )
    > t.pack( )
    >
    > t.insert( Tk.END, sampleText )
    >
    > t.tag_config( 'AB', font=tkFont.Font( family='ariel', size=24,
    > weight=tkFont.BOLD ) )
    > t.tag_config( 'TBU', font=tkFont.Font( family='times', size=10,
    > weight=tkFont.BOLD, underline=1 ) )


    Here is what I think is happening:
    - The first tag_config creates a font using tkFont.Font. At tcl level, this font is not known as an object as in Python, but just as a font name, which is a string. This name happens to be built using the internal identifier for the Python object.
    - Once this tag_config is over, no Python variable references your tkFont.Font instance anymore. It is is fact still known at tcl level (via the font name), but Python doesn't know that. So the reference counter for your tkFont.Font instance falls to 0, and the object is discarded.
    - The second tag_config seems to create a new font using tkFont.Font. Unfortunately, since the previous font has been discarded, the space occupied by this font is reused for the new font. So the new font happens to have the same internal identifier as the font object created by the first tkFont.Font. So its name is in fact the same as your previous font, and is registered as such at tcl level. So in fact, you didn't create a new font at tcl level, but modified the previous one.

    All this actually happens by accident. If you add something allocating some memory between the two tag_config, you'll certainly see your code working. It works when I run it myself...

    [snip]
    > f1 = font=tkFont.Font( family='ariel', size=24, weight=tkFont.BOLD )
    > f2 = font=tkFont.Font( family='times', size=10, weight=tkFont.BOLD,
    > underline=1 )
    > t.tag_config( 'AB', font=f1 )
    > t.tag_config( 'TBU', font=f2 )


    You should now see why it works here: your first tkFont.Font is remembered at Python level in a variable. So it is not discarded once the tag_config is over. So the second tkFont.Font is not allocated at the same location, so it doesn't have the same id, and it doesn't have the same name at tcl level. This is the general solution to the problem: keep your fonts in Python variables, so they won't be discarded and their names will never be re-used. You could have written:

    f1 = font=tkFont.Font( family='ariel', size=24, weight=tkFont.BOLD )
    t.tag_config( 'AB', font=f1 )
    f2 = font=tkFont.Font( family='times', size=10, weight=tkFont.BOLD, underline=1 )
    t.tag_config( 'TBU', font=f2 )

    This should still work. The order is not important; it's just the fact that your fonts are actually known at Python level which prevents Tkinter to reuse their name.

    BTW, this is a variant of a well known problem biting newbies regularly, documented here:
    http://tkinter.unpythonic.net/wiki/Images

    It's basically the same problem for images: it does not suffice to reference an image at tcl level; it must also be referenced at Python level or it will be discarded by Python and you won't be able to use it in your widgets.

    HTH
    --
    python -c "print ''.join([chr(154 - ord(c)) for c in 'U(17zX(%,5.zmz5(17;8(%,5.Z65\'*9--56l7+-'])"
     
    Eric Brunel, Oct 19, 2005
    #3
  4. Eugene Druker wrote:

    > tkFont.Font(...) is a class instance, while you need font description.


    Font instances are font descriptors.

    >>> f = tkFont.Font(family="ariel", size=24, weight=tkFont.BOLD)
    >>> f

    <tkFont.Font instance at 0x00A3AC60>
    >>> print f

    font10726496

    > t.tag.config( 'TBU', font=('times', 12, 'bold','underline') )
    > t.tag_config( 'AB', font=('arial',24,'bold') )


    the problem here is a variation of the old garbage collection problem (Tcl
    uses names as references, so the fact that Tk uses an object isn't enough to
    keep Python's GC away from it). the solution is to hold on to the objects
    in Python.

    </F>
     
    Fredrik Lundh, Oct 19, 2005
    #4
  5. In article <>,
    "Eric Brunel" <> wrote:

    >You should now see why it works here: your first tkFont.Font is remembered at
    >Python level in a variable. So it is not discarded once the tag_config is
    >over. So the second tkFont.Font is not allocated at the same location, so it
    >doesn't have the same id, and it doesn't have the same name at tcl level. This
    >is the general solution to the problem: keep your fonts in Python variables,
    >so they won't be discarded and their names will never be re-used.


    Yes. I consider this dangerous behavior, by the way and submitted a
    patch (that was not accepted) that would prevent this garbage collection.

    tkFont is Tkinter's interface to tk named fonts. If you create a tkFont
    instance for a named font and then let it disappear, the named font
    disappears, even if other tkFont instances exist that map the same named
    font.

    -- Russell
     
    Russell E. Owen, Oct 19, 2005
    #5
    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. Jeff Epler
    Replies:
    0
    Views:
    533
    Jeff Epler
    Aug 20, 2004
  2. Jeff Epler
    Replies:
    0
    Views:
    482
    Jeff Epler
    Aug 23, 2004
  3. Pierre Dagenais
    Replies:
    0
    Views:
    350
    Pierre Dagenais
    Aug 3, 2008
  4. Hidekazu IWAKI
    Replies:
    1
    Views:
    418
    Peter Otten
    Dec 14, 2009
  5. Hidekazu IWAKI
    Replies:
    0
    Views:
    553
    Hidekazu IWAKI
    Dec 15, 2009
Loading...

Share This Page