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

JLabel Text Cutoff

538 views
Skip to first unread message

Eric Douglas

unread,
Mar 4, 2020, 1:06:55 PM3/4/20
to
Is there an easy way to show text on a JLabel cutoff from the left?
I've tried every method and parameter I can think of but when the text runs out of the control it just wants to cut it off from the right.
sample:
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;

public class TestLabel {

public static void main(String[] args) {
JFrame f = new JFrame();
f.setPreferredSize(new Dimension(600,480));
f.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
String text = "too long text to fit in control";

JLabel lbl_1 = new JLabel();
lbl_1.setPreferredSize(new Dimension(70,20));
lbl_1.setHorizontalAlignment(SwingConstants.TRAILING);
lbl_1.setText(text);
f.getContentPane().add(lbl_1);

f.pack();
f.setVisible(true);
}
}

I see text displayed as "too long te..."
I want to see text displayed like "...in control"

Daniele Futtorovic

unread,
Mar 4, 2020, 1:23:22 PM3/4/20
to
The code you're looking for is in
sun.swing.SwingUtilities2#clipString
called by (ultimately)
javax.swing.plaf.basic.BasicLabelUI#layout

Looking at that method, I don't think there's any built-in way of having
the clipping occur at the start of the string:
> return string + clipString;
always appends.

--
DF.

Daniele Futtorovic

unread,
Mar 4, 2020, 1:24:13 PM3/4/20
to
(Code from OpenJDK 1.8)

--
DF.

Eric Sosman

unread,
Mar 4, 2020, 1:25:18 PM3/4/20
to
On 3/4/2020 1:06 PM, Eric Douglas wrote:
> Is there an easy way to show text on a JLabel cutoff from the left?
> I've tried every method and parameter I can think of but when the text runs out of the control it just wants to cut it off from the right.

Haven't tried it myself, but have you looked at
setHorizontalTextPosition()? Also, try setComponentOrientation().

If those don't work out and you really need the effect,
you could (I guess) get the label's Font and FontMetrics,
measure the as-rendered width of the string, and set the
label's text to as much of the tail as will fit. (If I
were doing this a lot, I'd subclass JLabel.)

--
eso...@comcast-dot-net.invalid
Three hundred twenty-two days to go.

Eric Douglas

unread,
Mar 4, 2020, 3:15:52 PM3/4/20
to
On Wednesday, March 4, 2020 at 1:23:22 PM UTC-5, Daniele Futtorovic wrote:
> The code you're looking for is in
> sun.swing.SwingUtilities2#clipString
> called by (ultimately)
> javax.swing.plaf.basic.BasicLabelUI#layout
>
> Looking at that method, I don't think there's any built-in way of having
> the clipping occur at the start of the string:
> > return string + clipString;
> always appends.
>
> --
> DF.

So there isn't a method that simply does that?
I would have thought that should be the default if the control isn't wide enough for the text and you tell it to align the text to the right side of the control.
So the workaround I came up with sounds ugly.

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Window;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class TestLabel {

public class MyTextControl extends JLabel {
private static final long serialVersionUID = 1L;
private String cText = "";

public String getTextString() {
return cText;
}

@Override
public void setText(final String text) {
cText = text;
String dispText = "";
final Font fnt = getFont();
setToolTipText(null);
if (fnt != null) {
Window f = SwingUtilities.getWindowAncestor(this);
final FontRenderContext frc;
if (f == null) {
frc = new FontRenderContext(null, true, true);
} else {
frc = f.getGraphics().getFontMetrics().getFontRenderContext();
}
final Rectangle2D textSize = fnt.getStringBounds(text, frc);
Dimension cs = getPreferredSize();
if (textSize.getWidth() <= cs.getWidth()) {
dispText = text;
} else {
setToolTipText(text);
Rectangle2D r2d2 = new Rectangle2D.Double();
String dots = "...";
final Rectangle2D dotSize = fnt.getStringBounds(dots, frc);
if (text.length() > 0) {
char[] chars = text.toCharArray();
for (int n = chars.length - 1; n >= 0; n--) {
final Rectangle2D charSize = fnt.getStringBounds(String.valueOf(chars[n]), frc);
if (r2d2.getWidth() + charSize.getWidth() + dotSize.getWidth() > cs.getWidth()) {
break;
}
dispText = chars[n] + dispText;
r2d2 = fnt.getStringBounds(dispText, frc);
}
dispText = dots + dispText;
}
}
}
super.setText(dispText);
}
}

public static void main(final String[] args) {
EventQueue.invokeLater(() -> {
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setVisible(true);
f.setPreferredSize(new Dimension(600, 480));
f.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
final String text = "too long text to fit in control";

TestLabel lbl = new TestLabel();
final MyTextControl lbl_1 = lbl.new MyTextControl();
lbl_1.setPreferredSize(new Dimension(50, 20));
f.getContentPane().add(lbl_1);
lbl_1.setText(text);

final MyTextControl lbl_2 = lbl.new MyTextControl();
lbl_2.setPreferredSize(new Dimension(70, 20));
f.getContentPane().add(lbl_2);
lbl_2.setText(text);

final MyTextControl lbl_3 = lbl.new MyTextControl();
lbl_3.setPreferredSize(new Dimension(100, 20));
f.getContentPane().add(lbl_3);
lbl_3.setText(text);

f.pack();
});
}
}

Daniele Futtorovic

unread,
Mar 4, 2020, 3:39:57 PM3/4/20
to
On 2020-03-04 21:15, Eric Douglas wrote:
> On Wednesday, March 4, 2020 at 1:23:22 PM UTC-5, Daniele Futtorovic wrote:
>> The code you're looking for is in
>> sun.swing.SwingUtilities2#clipString
>> called by (ultimately)
>> javax.swing.plaf.basic.BasicLabelUI#layout
>>
>> Looking at that method, I don't think there's any built-in way of having
>> the clipping occur at the start of the string:
>>> return string + clipString;
>> always appends.
>>
> So there isn't a method that simply does that?
> I would have thought that should be the default if the control isn't wide enough for the text and you tell it to align the text to the right side of the control.

They probably could have added that -- and for all I know perhaps they
have, somewhere.

But in their defense, I wouldn't say that this kind of functionality
should /obviously/ be there. The label clipping is really just a crutch.
It doesn't make much sense for a label to be clipped in the first place
-- and if your UI relies on that, I would say the fault is more with
your UI.
I found it at times (when I was still doing UIs) helpful to use the path
of least resistance with respects to the library; mostly, they knew what
they were doing, much more so, I found, than me. Don't underestimate how
much UIs rely, to be effective, on paradigms and implicit assumptions.

Lastly, note that what I've seen in the wild for labels that didn't fit
their space, were animations to scroll the text back and forth (or
looping around) through the available space. It's a bit trickier (since
it involves background tasks), but works decently as a widget.

> So the workaround I came up with sounds ugly.

Seems fairly par for the course of Swing code to me.

> final MyTextControl lbl_1 = lbl.new MyTextControl();

Ugh. Here's a tip: don't do this. Don't ever do this. I mean the
qualified `new`. Make that inner class static. If you absolutely can't
(and you always can), then create an instance method in the enclosing
that returns a new instance of the inner class. But qualified new should
be avoided IMO.

--
DF.

Eric Douglas

unread,
Mar 4, 2020, 3:59:41 PM3/4/20
to
On Wednesday, March 4, 2020 at 3:39:57 PM UTC-5, Daniele Futtorovic wrote:
> But in their defense, I wouldn't say that this kind of functionality
> should /obviously/ be there. The label clipping is really just a crutch.
> It doesn't make much sense for a label to be clipped in the first place
> -- and if your UI relies on that, I would say the fault is more with
> your UI.
> I found it at times (when I was still doing UIs) helpful to use the path
> of least resistance with respects to the library; mostly, they knew what
> they were doing, much more so, I found, than me. Don't underestimate how
> much UIs rely, to be effective, on paradigms and implicit assumptions.
>
The use case here is a button that allows the user to select a file, then a text control showing what file they selected. Obviously we can't show the full file name with path, it likely wouldn't fit on the screen much less in half the screen. I thought they'd rather see the end of file name .ext instead of "C:\Documents and Settings...".

> Lastly, note that what I've seen in the wild for labels that didn't fit
> their space, were animations to scroll the text back and forth (or
> looping around) through the available space. It's a bit trickier (since
> it involves background tasks), but works decently as a widget.
>
Sounds curious.

> > So the workaround I came up with sounds ugly.
>
> Seems fairly par for the course of Swing code to me.
>
> > final MyTextControl lbl_1 = lbl.new MyTextControl();
>
> Ugh. Here's a tip: don't do this. Don't ever do this. I mean the
> qualified `new`. Make that inner class static. If you absolutely can't
> (and you always can), then create an instance method in the enclosing
> that returns a new instance of the inner class. But qualified new should
> be avoided IMO.
>
> --
> DF.

That is not part of a real API, just to make this runnable test class. That's how Eclipse told me to write that, with trying to instantiate the control from the static main method, having the control class declared within the test class. In the real API of course it's not instantiated from the main method and the control class is in it's own file.

Daniele Futtorovic

unread,
Mar 4, 2020, 4:26:40 PM3/4/20
to
On 2020-03-04 21:59, Eric Douglas wrote:
> The use case here is a button that allows the user to select a file, then a text control showing what file they selected. Obviously we can't show the full file name with path, it likely wouldn't fit on the screen much less in half the screen. I thought they'd rather see the end of file name .ext instead of "C:\Documents and Settings...".

Makes sense. But how about a simple tooltip?

--
DF.
0 new messages