tkinter text width

J

James Stroud

Hello All,

I would like for a tkinter text widget to be aware of how big the frame that
contains it is, then I would like for it to reset its width to the
appropriate number of characters when this frame changes size.

I can get a cget("width") for the text, but this does not dynamically reflect
the visible width.

One way I can think of is getting the size of the font used in the widget then
getting the width of the frame with cget then doing the appropriate math and
configuring the text widget upon resize events.

I'm thinking that there must be a more straightforward way.

Any ideas?

James


--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
E

Eric Brunel

Hello All,

I would like for a tkinter text widget to be aware of how big the frame that
contains it is, then I would like for it to reset its width to the
appropriate number of characters when this frame changes size.

Errr... This is supposed to be the regular behaviour. How do you create your Text widget? Do you specify a width and height? If you do not, the default width and height are 80 and 24 respectively, and the widget won't resize to less than that. If you want a Text widget to be the smallest as possible in its container, you can do something like:

-----------------------------------------------------
from Tkinter import *

root = Tk()

t = Text(root, width=1, height=1)
t.pack(fill=BOTH, expand=1)

root.geometry('500x200')

root.mainloop()
-----------------------------------------------------

The "trick" is to create the Text as small as possible (width=1, height=1), make it fill its whole container (pack(fill=BOTH, expand=1)), then set the dimensions for the container window (geometry('500x200')). You'll get a Text that will shrink and expand as much as you like.

Is it what you were after?

HTH
 
J

James Stroud

The "trick" is to create the Text as small as possible (width=1, height=1),
make it fill its whole container (pack(fill=BOTH, expand=1)), then set the
dimensions for the container window (geometry('500x200')). You'll get a
Text that will shrink and expand as much as you like.

Is it what you were after?

This is more or less what I would like, but I would also like to probe the
Text to see how many characters it thinks it can display within the container
window. I am formatting text dynamically and so I rely on the width. I am not
after the built in "wrap" option, it does not do what I want. But, say if
wrap were turned on, it would be good to know how many characters the Text
would wrap at.

James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
J

Jeremy Bowers

This is more or less what I would like, but I would also like to probe the
Text to see how many characters it thinks it can display within the container
window. I am formatting text dynamically and so I rely on the width. I am not
after the built in "wrap" option, it does not do what I want. But, say if
wrap were turned on, it would be good to know how many characters the Text
would wrap at.

I have extensive experience with trying to get text containers to do this.
It is not easy. You have two choices:

1. Give up. You can't tell anyhow if you're using a proportional font.

2. Use a fixed-width font and manually wrap. (It's pretty easy then, you
can ask the font for how wide any char is and do the math from there.)

I have 70 line function that tries to replicate the Tk wrapping algorithm
in the proportional text case, and it *still* doesn't work. For one thing,
I actually found some bugs in the wrapping code (if a Unicode character
gets into just the right position, it can actually run off the right end
of the text widget, even if the widget is being wrapped), so completely
matching the layout seems infeasible.

I would strongly, strongly suggest finding another way to do what you are
trying to do. I have blown many, many hours on this problem, and I found
no simple logic. The edge cases kill you; while Tk is consistent (same
text, same wrap every time), sometimes it wraps a word if it goes up to
the edge, sometimes if it's one pixel off, damned if I can find a pattern
(probably has something to do with trying to space the letters out,
kerning or one of its simpler friends), and it probably changes
periodically anyhow... and note based on this I can't even guarantee #2
above, if you get unlucky.

Basically, I'm pretty sure you can't do this.
 
J

James Stroud

Thank you to everybody helping me. I think I am almost there...

2. Use a fixed-width font and manually wrap. (It's pretty easy then, you
can ask the font for how wide any char is and do the math from there.)

How might I query the size of a fixed-width font in pixles? It appears that
the width of the font in points does not correlate with its width in pixels
based on some simple expriments I have done. Using cget("font") on the Text
gives back a string with the point size.
[snip some things to worry about]
Basically, I'm pretty sure you can't do this.

My setup is not very complicated, so I don't think I have to worry about
kerning, unicode, etc.. I am using a fixed width font (courier) only, and
only one size and am also quite comfortable with giving away several pixels
at the end of a line for "rounding errors" and will filter for a limited
alphabet consisting only of the numbers, the captial letters, and the space.

I think I can do this given these limitations.

James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
J

Jeremy Bowers

Thank you to everybody helping me. I think I am almost there...



How might I query the size of a fixed-width font in pixles? It appears that
the width of the font in points does not correlate with its width in pixels
based on some simple expriments I have done. Using cget("font") on the Text
gives back a string with the point size.

Ah, in that case you want the measure attribute of the font object.

http://www.pythonware.com/library/tkinter/introduction/x4671-methods.htm
[snip some things to worry about]
Basically, I'm pretty sure you can't do this.

My setup is not very complicated, so I don't think I have to worry about
kerning, unicode, etc.. I am using a fixed width font (courier) only, and
only one size and am also quite comfortable with giving away several pixels
at the end of a line for "rounding errors" and will filter for a limited
alphabet consisting only of the numbers, the captial letters, and the space.

I think I can do this given these limitations.

Sounds like it.

What I did was set up unit test that threw random snippets at the text
widget, and compared how many lines my code thought the widget should
have, vs. what the widget claimed to have. This is how I discovered that
some unicode was wrapped incorrectly. You can get what the widget claims
to have by asking it for the geometric position of the last character with
the bbox method of the Text widget.

This is, however, probably not the answer you are looking for, because you
only get a bounding box if the text is currently visible on the screen.
This makes it fairly difficult to use to ask the widget *how far* off the
screen the text is. If it were that easy I would have said so earlier
:) But you may find that useful too, as you cobble together a solution.
 
E

Eric Brunel

[snip]
How might I query the size of a fixed-width font in pixles? It appears that
the width of the font in points does not correlate with its width in pixels
based on some simple expriments I have done.

This is the case on all platforms, but far more sensible on Windows: Windows attempts to be "clever" and corrects the font size you give depending on your screen resolution so that a 12 point font is supposed to be actually 12/72 inches *on screen* (obviously ignoring the fact that this is almost never what you want, since all other dimensions are in screen points by default...). Other platforms than Windows are supposed to do this too, but (fortunately) it seems to fail and the computed factor is very close to 1 (I got something like 1.04 on Linux, whatever the screen resolution was).

To avoid this, you can try to use the winfo_* methods to get the screen resolution (I thought there was a more straightforward way, but the only way I see is to do someWidget.winfo_screenwidth() / someWidget.winfo_screenmmwidth(), with the usual adjustement to get inches instead of millimeters). You can then use this adjustement on all the dimensions you compute so that it will be consistent with the font sizes you get.

The other solution is to turn the adjustement off. You can do this at tk level with the command "tk scaling 1". Unfortunately, this command does not seem to be directly available at Tkinter level, so you'll have to do:
someWidget.tk.call('tk', 'scaling', 1)
After doing that, all your font sizes should be in screen points. But be aware that *all* your fonts will seem to shrink (the screen resolutions these days are usually closer to 92 dpi than to 72...). So you may have to do some adjustements on other parts of your application (the biggest problem I got was with menu items).

HTH
 
D

Dennis Lee Bieber

This is the case on all platforms, but far more sensible on Windows: Windows attempts to be "clever" and corrects the font size you give depending on your screen resolution so that a 12 point font is supposed to be actually 12/72 inches *on screen* (obviously ignoring the fact that this is almost never

Pardon? Since when has Windows attempted to scale fonts for
screen display based on screen resolution?

The older Macs were fixed at 72 pixels per inch -- with the
result that the /only/ way to increase the resolution was to physically
change to a larger monitor. This is why they were so popular for DTP --
the on-screen view WAS the same size as the printed view.

Windows display properties defaults to an /assumed/ 96 pixels
per inch regardless of the screen resolution (right-click the desktop
background, properties, Settings/Advanced, General). This is why
changing to a low-resolution (like the recovery mode screen on W98) on a
large monitor results in such a pixilated, large-character, display.

I'm currently running a 20" flat-panel at 1600x1200. It also
appears to be about 12" vertical display region, making for
100pixels/inch. If I set it to 800x600, it would be running at 50pixels
per inch -- even though Windows is still assuming 96ppi for rendering. A
12pt typeface would be just under 1/8" on normal, but 1/4" on the low
resolution setting.

--
 
E

Eric Brunel

Pardon? Since when has Windows attempted to scale fonts for
screen display based on screen resolution?

The older Macs were fixed at 72 pixels per inch -- with the
result that the /only/ way to increase the resolution was to physically
change to a larger monitor. This is why they were so popular for DTP --
the on-screen view WAS the same size as the printed view.

Windows display properties defaults to an /assumed/ 96 pixels
per inch regardless of the screen resolution (right-click the desktop
background, properties, Settings/Advanced, General). This is why
changing to a low-resolution (like the recovery mode screen on W98) on a
large monitor results in such a pixilated, large-character, display.

I'm currently running a 20" flat-panel at 1600x1200. It also
appears to be about 12" vertical display region, making for
100pixels/inch. If I set it to 800x600, it would be running at 50pixels
per inch -- even though Windows is still assuming 96ppi for rendering. A
12pt typeface would be just under 1/8" on normal, but 1/4" on the low
resolution setting.

Sorry for that: my mistake. Anyway, the problem remains; the ouput for the "tk scaling" command on Windows and Linux is as follows:

[Windows]
% tk scaling
1.33202228777

[Linux]
% tk scaling
1.04285347703

(all of this tested with tcl/tk 8.3 - Windows is Win2k, Linux is an old Mandrake 8.0).

So this means that when you ask for a 12 point font, Windows will give you a 12 * 1.33202228777 = 16 screen pixels font and Linux a 12 * 1.04285347703 = 12 or 13 screen pixels font, depending on how the size is rounded. But the dimensions you set for all widgets are in screen pixels, unless explicitely given in another unit. So either you do a "tk scaling 1" at the beginning of all your apps, or you specify all widget diemnsions as '100p' instead of just 100 for example. If you don't do either, all your texts will look really bigger on Windows than on Linux.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,816
Latest member
nipsseyhussle

Latest Threads

Top