Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Truncated chinese labels in buttons

14 views
Skip to first unread message

Francois Vogel

unread,
Dec 20, 2008, 7:30:37 AM12/20/08
to
Hi,

I have built a dialog with several buttons arranged in a stack and I
want the width of all buttons to be the same.
Moreover, this dialog can be displayed in many languages and I'm using
the msgcat package for handling the translations.

To set the same width for the buttons I'm using the msgcat::mcmax
command as advertised in the msgcat help page. I get the max length of
the translated strings that have to be show in the buttons. After
digging into the source code I found out that mcmax is just
calculating [string length $str] and returning the max of them.

This works apparently OK for languages using ascii characters. But now
I have a chinese translation and the width calculated by mcmax is no
longer the right one. The longest label gets truncated.

Here is a simplified example in wish (chinese strings noted in \uxxx
to avoid mangling by ascii readers):

#set str1 "尋找下一個 - Find N"
set str1 "\u5C0B\u627E\u4E0B\u4E00\u500B - Find N"
#set str2 "取代 - Replace"
set str2 "\u53D6\u4EE3 - Replace"
set len1 [string length $str1]
set len2 [string length $str2]
# emulate mcmax
if {$len1 < $len2} {set best $len1} else {set best $len2}
# display
button .b1 -text $str1 -anchor w -width $best
button .b2 -text $str2 -anchor w -width $best
pack .b1 .b2


The truncation shown on the first label is the problem.

On the other hand if I do not give the -width option to the button
command, then each button correctly shows untruncated labels.

Is this a bug of msgcat?

How can I handle this? This is on WinXPTcl 8.4.15 or 8.5.6b1 as well.

Thanks for any hint.
Francois

Uwe Klein

unread,
Dec 20, 2008, 8:18:20 AM12/20/08
to
# dont use pack:
# pack .b1 .b2


# don't fix the widht:
button .bb1 -text $str1 -anchor w
button .bb2 -text $str2 -anchor w

grid .b1 -column 1 -row 1
grid .b2 -column 1 -row 2

# make the buttons hug the left and right border
# of their grid column via "-sticky we"
grid .bb1 -column 2 -row 3 -sticky we
grid .bb2 -column 2 -row 4 -sticky we


grid columnconfigure . 1 -weight 1
grid columnconfigure . 2 -weight 1


#################

use grid as geometry manager
It will provide more happiness to the programmer.

beware : do not use grid and pack on the same master.

uwe

Francois Vogel

unread,
Dec 20, 2008, 11:04:59 AM12/20/08
to
Uwe Klein said on 20/12/2008 14:18:

> use grid as geometry manager

Thanks for replying. I have studied your code and indeed this works
for me too.

Nevertheless, I would say that the behavior I see is a bug.
The msgcat man page states that:

"Given several source strings, ::msgcat::mcmax returns the length of
the longest translated string. This is useful when designing localized
GUIs, which may require that all buttons, for example, be a fixed
width (which will be the width of the widest button)."

This is exactly what I'm trying to achieve. Using grid looks like a
workaround to me. You suggest using grid because the above statement
from msgcat is not always true.

My understanding is that mcmax should be fixed, or its man page
explain that the result returned by msgcat will be OK with -width only
under certain conditions (that need to be clarified).

Do you agree with my understanding?
Is it worth to file a bug report on this?


> beware : do not use grid and pack on the same master.

What would happen in such a case (ok, I'll try and check it myself)?

But what exactly do you mean by "master"? Is it a toplevel? I think I
can have a toplevel with two frames in it, one of them containing
packed widgets and the other one showing gridded widgets, is this not
true?

Thanks again,
Francois

Uwe Klein

unread,
Dec 20, 2008, 12:08:05 PM12/20/08
to
Francois Vogel wrote:

> My understanding is that mcmax should be fixed, or its man page explain
> that the result returned by msgcat will be OK with -width only under
> certain conditions (that need to be clarified).

msgcat has imho no bug. the width in chars is correct.
try the following ( add at bottom of your example )

after 2000 .b1 configure -width 0
after 3000 .b2 configure -width $best

watch what happens after 2 seconds and after 3 seconds.


The width you configure for the button widget seems to translate
to a width in pixels to the current font and normal char width.
This gets reevaluated if you reconfigure the button.
( and it breaks your design target ;-(


>
> Do you agree with my understanding?
> Is it worth to file a bug report on this?

filing bugs is never a bad thing.


>
>
>> beware : do not use grid and pack on the same master.
>
>
> What would happen in such a case (ok, I'll try and check it myself)?

The geometry managers depart on a game of poker, nobody wins.
The gui job has been forgotten about .
(i.e. an endless loop fixing the geometry to two tastes )


>
> But what exactly do you mean by "master"? Is it a toplevel? I think I

the "master" is the grided widget. in your case the toplevel.

> can have a toplevel with two frames in it, one of them containing packed
> widgets and the other one showing gridded widgets, is this not true?

yes


uwe

Francois Vogel

unread,
Dec 20, 2008, 2:08:49 PM12/20/08
to
Uwe Klein said on 20/12/2008 18:08:

> msgcat has imho no bug. the width in chars is correct.

Yes it is. This is the first thing I checked. mcmax returns the
correct number of chars.

At the same time, -width for buttons containing text is supposed to
receive a number measured in chars:

"Command-Line Name: -width
Specifies a desired width for the button. [...]; for text it is in
characters. If this option isn't specified, the button's desired width
is computed from the size of the image or bitmap or text being
displayed in it."

True, it does not really say what's happening when you specify this
option.
My assumption was that when you give a width in chars that is equal to
[string length $buttonlabel], then $buttonlabel will not get truncated.
Now I understand that when -width $x is given then the button width
will be $x characters, but even if $x == [string length $buttonlabel],
anything can happen wrt truncation.

Is this the reason why when I configure my button with -width [mcmax
...] I may see truncated text? This is still unclear to me.

If the above turns out to be true, what is the correct use of mcmax
then? Since I can't feed the result from mcmax to -width, what is the
use case for mcmax (especially, considering what is said in its man page)?

Francois

Uwe Klein

unread,
Dec 20, 2008, 2:36:33 PM12/20/08
to
Francois Vogel wrote:

> If the above turns out to be true, what is the correct use of mcmax
> then? Since I can't feed the result from mcmax to -width, what is the
> use case for mcmax (especially, considering what is said in its man page)?

My guess is nobody anticipated that you would combine narrow latin
type chars with (wider) pictogramm style chars ;-)

I don't know which basic charset the button widget assumes for width calculation
with the content unknown. ( probably the fitting width for ascii ? )

uwe

Jan Kandziora

unread,
Dec 20, 2008, 5:08:22 PM12/20/08
to
Uwe Klein schrieb:

> Francois Vogel wrote:
>
>> If the above turns out to be true, what is the correct use of mcmax
>> then? Since I can't feed the result from mcmax to -width, what is the
>> use case for mcmax (especially, considering what is said in its man
>> page)?
>
> My guess is nobody anticipated that you would combine narrow latin
> type chars with (wider) pictogramm style chars ;-)
>
No. ::msgcat::mcmax just don't deal with glyph widths at all. It doesn't
know the size of each glyph, it just counts chars. You will run into the
same problem with any (latin) non-fixed-width font. And you don't want to
use a fixed-width font for your GUI, it's ugly.

::msgcat::mcmax is completely useless for the case described in the msgcat
manpage. Just discard that advice.


> I don't know which basic charset the button widget assumes for width
> calculation with the content unknown. ( probably the fitting width for
> ascii ? )
>

The widget reports its actual width depending on its content. If there is no
content, it use a default size.

Usually, you don't have to know the display width of a certain string. Just
let the geometry manager (grid preffered) do its work. If you want all the
buttons to be the same width, use the "-sticky ew" (east-west) option when
gridding a button. The button will horizontally fit into it's grid cell
entirely then.

Kind regards

Jan


Christian Gollwitzer

unread,
Dec 21, 2008, 5:31:20 AM12/21/08
to
Francois Vogel schrieb:

> Using grid looks like a
> workaround to me. You suggest using grid because the above statement
> from msgcat is not always true.

No. Using grid is the far better approach. It takes the layout off from
your shoulders. You shouldn't worry about pixels and geometry
calculation, exactly this *is* the job of the geometry managers.

For completeness, it should be mentioned, that also pack can manage the
width of the buttons automatically. Just change the last line of your
example to:

pack .b1 .b2 -expand yes -fill x

With grid, it's just easier to manage the behaviour of a more
complicated layout, when the toplevel is resized by the user.

Christian

suchenwi

unread,
Dec 22, 2008, 3:54:52 AM12/22/08
to
On 20 Dez., 13:30, Francois Vogel <fsvogelnew5NOS...@free.fr> wrote:
> This works apparently OK for languages using ascii characters. But now
> I have a chinese translation and the width calculated by mcmax is no
> longer the right one. The longest label gets truncated.

As others have said, the length of a string in characters isn't
tightly correlated to its width in pixels. As a quick workaround, here
is a custom function (oversimplifying) that counts Unicodes above
\u3000 as having a width of 2:

proc strlen2 str {
set res [string length $str]
foreach c [split $str ""] {
if {$c > "\u3000"} {incr res}
}
return $res
}
73 % strlen2 hello
5
28 % strlen2 (北京)
6

Andreas Leitgeb

unread,
Dec 22, 2008, 4:51:16 AM12/22/08
to
suchenwi <richard.suchenw...@siemens.com> wrote:
> On 20 Dez., 13:30, Francois Vogel <fsvogelnew5NOS...@free.fr> wrote:
>> This works apparently OK for languages using ascii characters. But now
>> I have a chinese translation and the width calculated by mcmax is no
>> longer the right one. The longest label gets truncated.
> As others have said, the length of a string in characters isn't
> tightly correlated to its width in pixels. As a quick workaround, here
> is a custom function (oversimplifying) that counts Unicodes above
> \u3000 as having a width of 2:

Probably a good heuristic.

Anyway, there is also a chance that no font is found to display those
characters and thus they get displayed as "\u3456\u4567..." literally.
Ok, so if that happens then the far-east glyphs are unlegible anyway,
but due to "\u3456" taking even more space to print than the real glyph
it means that the latin text following it will most likely be clipped
away at the end of the button.

Using grid and have the button determine it's size itself is most likely
the best way.

I've seen by far too many clipped texts in badly written GUIs (mostly
non-tcl apps), already.

PS: as a sidenote, as it appeared somewhere in this thread: would it
be feasible for geometry managers to recognize the presence of other
geometry managers for the same master, and either refuse instantly, or
switch to some kind of passive mode only propagating size-changes inwards?

Donal K. Fellows

unread,
Dec 22, 2008, 4:53:50 AM12/22/08
to
suchenwi wrote:
> As others have said, the length of a string in characters isn't
> tightly correlated to its width in pixels. As a quick workaround, here
> is a custom function (oversimplifying) that counts Unicodes above
> \u3000 as having a width of 2:
>
> proc strlen2 str {
> set res [string length $str]
> foreach c [split $str ""] {
> if {$c > "\u3000"} {incr res}
> }
> return $res}
>
> 73 % strlen2 hello
> 5
> 28 % strlen2 (北京)
> 6

The other thing is that it's really best to try to think in terms of
the font that you're using. The [font measure] command makes this
easier.

proc strlenf {font string} {
set width [font measure $font $string]
set width0 [font measure $font "0"]
return [expr {int(ceil(double($width)/$width0))}]
}

Testing, first with a fixed width font then a variable width one...
% strlenf {Courier 10} abcde
5
% strlenf {Times 10} aaaaaa
6
% strlenf {Times 10} mmmmmm
10
% strlenf {Times 10} iiiiii
4

Donal.

peter....@gmail.com

unread,
Dec 22, 2008, 11:43:32 AM12/22/08
to
On 22 Dec, 10:51, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at>
wrote:

>
> PS: as a sidenote, as it appeared somewhere in this thread:  would it
>  be feasible for geometry managers to recognize the presence of other
>  geometry managers for the same master, and either refuse instantly, or
>  switch to some kind of passive mode only propagating size-changes inwards?

I have a patch for that, though I haven't had time to finish it.
I hope to get it in for one of the 8.6 betas.

I once had a grid/pack fight hang my entire desktop. Debugging that
with
a reboot in the loop was tedious enough to get started on that
patch ;-)

/Peter

Joe English

unread,
Dec 22, 2008, 1:01:21 PM12/22/08
to
Andreas Leitgeb asked:

> PS: as a sidenote, as it appeared somewhere in this thread: would it
> be feasible for geometry managers to recognize the presence of other
> geometry managers for the same master, and either refuse instantly, or
> switch to some kind of passive mode only propagating size-changes inwards?

Yes, that's feasible, it would just take a medium-sized
overhaul of the geometry management infrastructure.

--Joe English

Francois Vogel

unread,
Dec 22, 2008, 6:32:42 PM12/22/08
to
Many thanks to all who bothered to look at this problem. Your help was
appreciated and I could move forward very significantly.

Here a few remaining questions.


Jan Kandziora said on 20/12/2008 23:08:


> ::msgcat::mcmax is completely useless for the case described in the msgcat
> manpage. Just discard that advice.

Which I did.
Side note: Without being capable to find *any* use then to mcmax. At
least the use case described in its man page should be removed since
it's very misleading.
Anyway.

> Usually, you don't have to know the display width of a certain string. Just
> let the geometry manager (grid preffered) do its work.

This is now what I'm using in almost all dialogs of my application and
it works nicely.


My remaining problem is that I have a dialog containing a table (sort
of a matrix), with elements being labels, buttons, entries, checkboxes
and spinboxes.

The problem is with the spinbox. I want the width of this spinbox to
be just large enough to show any of its elements unclipped, without
resizing the cell whenever I change the spinbox active element.

My approach was to pass all possible items of the spinbox (which are
predefined) to mcmax, which gave what to feed in -width.

Now I don't want to use -width anymore, and want to replace pack by grid.

This new approach works only if the active item in the spinbox is the
widest (in pixels), otherwise the spinbox widget gets gridded with a
size corresponding to the size of the currently active item, and when
I switch this item to a widest item, this one gets clipped. Ouch.

How can I grid my spinboxes so that they have minimum width and so
that anything they can display will not get clipped?

I have thought about several options, such as:

- use grid columnconfigure -minsize, but what would be the size to
feed in there (without using mcmax)?

- save the currently selected item in the spinbox, search for the
longest ([string length ...]) item of the spinbox, select it, grid the
spinbox, select back the item initially selected. What a mess...


Other suggestions, perhaps?

Thanks a lot.
Francois

Francois Vogel

unread,
Dec 22, 2008, 6:43:38 PM12/22/08
to
Donal K. Fellows said on 22/12/2008 10:53:

> The other thing is that it's really best to try to think in terms of
> the font that you're using. The [font measure] command makes this
> easier.
>
> proc strlenf {font string} {
> set width [font measure $font $string]
> set width0 [font measure $font "0"]
> return [expr {int(ceil(double($width)/$width0))}]
> }

Hmmm, I see what you mean here.
Measure $string in pixels, arbitrarily decide that one char is the
width of the character "0" and divide to know how many such characters
the given $string is wide.

This can lead to unexpected results:
% strlenf {Times 10} 北京
5
% strlenf {Times 30} 北京
4

In this case I guess I should use a reference character different than
zero.
This remark points to a weakness of your proposal IMHO: the result
depends on the character set that $string is using. The choice of the
reference character is important and should be made by proc strlenf in
consistency with the characters that $string is composed of.
Further headaches...

Francois

Bryan Oakley

unread,
Dec 22, 2008, 7:24:23 PM12/22/08
to
On Dec 22, 5:32 pm, Francois Vogel <fsvogelnew5NOS...@free.fr> wrote:

> Side note: Without being capable to find *any* use then to mcmax. At
> least the use case described in its man page should be removed since
> it's very misleading.

I can think of at least one. If your data comes from or goes to or
defines a database with a fixed field size for one of these messages,
you want to make sure you've met the storage requirements.

Just think of msgcat::mcmax as returning storage requirements, not
screen requirements.

Bryan Oakley

unread,
Dec 22, 2008, 7:30:55 PM12/22/08
to

I think the reason Donal suggested zero as the reference character is
that is what is used by Tk internally. It's been years since I looked
at the sources so I could be wrong. Even if you get the "right"
reference character the answer won't be precise. If you have more
characters wider than the reference, or narrower, the answer will be
skewed.

The only truly precise solution is to use font measure on each string
(or use a fixed width font). Do that, then create the widget exactly
as many pixels as you know you need. You can create a text-based
widget a fixed number of pixels by packing it in a frame, turning
geometry propagation off in that frame, then setting the frame to the
desired size.

Jan Kandziora

unread,
Dec 24, 2008, 6:43:31 PM12/24/08
to
Francois Vogel schrieb:

>
> The problem is with the spinbox. I want the width of this spinbox to
> be just large enough to show any of its elements unclipped, without
> resizing the cell whenever I change the spinbox active element.
>
I assume you want to use a readonly spinbox? If not, you'd have to attach a
horizontal scrollbar to it.


> How can I grid my spinboxes so that they have minimum width and so
> that anything they can display will not get clipped?
>
> I have thought about several options, such as:
>
> - use grid columnconfigure -minsize, but what would be the size to
> feed in there (without using mcmax)?
>
> - save the currently selected item in the spinbox, search for the
> longest ([string length ...]) item of the spinbox, select it, grid the
> spinbox, select back the item initially selected. What a mess...
>

That's the way to go. But string length won't help you. It has the same
problem as ::msgcat::mcmax. You have to use font measure with a font that
contains all characters in use.

% font measure mincho "??Jan???"

Kind regards

Jan

Donal K. Fellows

unread,
Dec 26, 2008, 3:57:41 AM12/26/08
to
Jan Kandziora wrote:
> That's the way to go. But string length won't help you. It has the same
> problem as ::msgcat::mcmax. You have to use font measure with a font that
> contains all characters in use.

Actually, you should use the font that you're going to display the
characters in and let Tk's font fallback mechanism take care of the
details. Of course, which font you use to display might be affected by
which characters are being used...

Donal.

Andreas Leitgeb

unread,
Dec 28, 2008, 4:31:40 AM12/28/08
to
> On 22 Dec, 10:51, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
>> PS: as a sidenote, as it appeared somewhere in this thread:  would it
>>  be feasible for geometry managers to recognize the presence of other
>>  geometry managers for the same master, and either refuse instantly, or
>>  switch to some kind of passive mode only propagating size-changes inwards?

peter....@gmail.com <peter....@gmail.com> wrote:
> I have a patch for that, though I haven't had time to finish it.
> I hope to get it in for one of the 8.6 betas.

Joe English wrote in a sibling-post:


> Yes, that's feasible, it would just take a medium-sized
> overhaul of the geometry management infrastructure.

As a layman in this area I see two somewhat conflicting statements,
and both hadn't any discussion/comments following it so far.

How's the patch doing, Peter?

peter....@gmail.com

unread,
Dec 29, 2008, 5:36:07 PM12/29/08
to
On Dec 28, 10:31 am, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at>
wrote:

> > On 22 Dec, 10:51, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> >> PS: as a sidenote, as it appeared somewhere in this thread:  would it
> >>  be feasible for geometry managers to recognize the presence of other
> >>  geometry managers for the same master, and either refuse instantly, or
> >>  switch to some kind of passive mode only propagating size-changes inwards?
> peter.spj...@gmail.com <peter.spj...@gmail.com> wrote:
> > I have a patch for that, though I haven't had time to finish it.
> > I hope to get it in for one of the 8.6 betas.
>
> Joe English wrote in a sibling-post:
>
> > Yes, that's feasible, it would just take a medium-sized
> > overhaul of the geometry management infrastructure.
>
> As a layman in this area I see two somewhat conflicting statements,
> and both hadn't any discussion/comments following it so far.
>
> How's the patch doing, Peter?

I cleaned up what I had and put it at:

https://sourceforge.net/tracker/index.php?func=detail&aid=2475855&group_id=12997&atid=312997

Looking at it now I can't remember why I didn't think it was
complete...
Feedback is welcome.

/Peter

0 new messages