6

On most systems, the content in my JLabel just shows fine. It is also resided in a way that it should be always big enough to show its content text because I basically do this:

label.setText(text);
label.setFont(new Font(fontName, 0, 12));
int width = label.getFontMetrics(label.getFont()).stringWidth(text);
int height = 21; // this should always be enough
label.setBounds(new Rectangle(x, y, width, height));

But on some systems (not my own so I cannot really debug it that easy), it cuts the text and shows "..." at the end.

You can see the full code here and you can see the example here (Abbildungen_Bijektiv_X3).

I also have some similar case for JButton.

How can I force Swing to not do that? (Even if it thinks that the component is too small.)

Where exactly does Swing handle this? I browsed through the code of JButton and some related classes but I didn't really found the code where it cuts the text and adds the ellipsis.

Albert
  • 65,406
  • 61
  • 242
  • 386

3 Answers3

4

There should be no need to set the bounds of the label.

That is the job of a layout manager. Learn to use layout managers and you won't have this problem.

Edit:

Layout managers use:

label.setSize( label.getPreferredSize() );
camickr
  • 321,443
  • 19
  • 166
  • 288
  • 1
    Why? Post your SSCCE that demonstrates the problem. I hope you don't expect us to read through a 1,000 lines of code to try and understand what you are attempting to do. – camickr Mar 21 '11 at 16:07
  • 2
    It is all designed in such a manner that I have to construct the layout myself. And I also don't want to discuss here now wether I should completely redesign the whole thing from scratch. Also, where is the problem at all? Doing/calculating the layout is some quite trivial task. Only because Java tries to behave somehow intelligent makes it problematic here. And I am only asking about how I can disable that. – Albert Mar 21 '11 at 16:33
  • Ah, that `getPreferredSize()` seems to be an easy and clean way for a `JLabel` to get the real size where it will always fit. In case of the `JButton`, I want to have a predefined size and I am quite sure that my text should fit in there but it still does "...". How can I force it to not do that? – Albert Mar 21 '11 at 16:56
  • Do you know where it actually does the ellipsis handling in the code? I.e. in which class? Because then I might see how I could disable that. – Albert Mar 21 '11 at 17:09
  • "It is all designed in such a manner that I have to construct the layout myself." The is the whole point of a layout manager. You put the special layout code in the layout mananger. You are reinventing the wheel. Buttons are more complicated than labels because they have Borders. You probably forgetting to allow for that. – camickr Mar 21 '11 at 18:35
  • 1
    Layouting is really trivial in my case. Anyway, that is off-topic to the problem itself. – Albert Mar 21 '11 at 20:03
  • So use a layout manager and don't reinvent the wheel. You are writing custom code to size a component and it doesn't work the way you expect so the question is why are you overriding the default code. If you would use the layout manager properly then you would not have this problem. So no it is not off topic. – camickr Mar 21 '11 at 20:38
  • 1
    The sizing/layouting works *exactly* the way I want it. Really the only problem I have is that it adds the ellipsis. – Albert Mar 21 '11 at 20:44
2

I am doing this now (for buttons but you could do it in a similar way for other controls):

static public class ButtonUI extends MetalButtonUI {
    public static ComponentUI createUI(JComponent c) {
        return new ButtonUI();
    }

    @Override public void paint(Graphics g, JComponent c) {
        JSimpleLabel.activateAntiAliasing(g);

        AbstractButton b = (AbstractButton) c;
        ButtonModel model = b.getModel();

        String text = b.getText();
        clearTextShiftOffset();

        // perform UI specific press action, e.g. Windows L&F shifts text
        if (model.isArmed() && model.isPressed()) {
            paintButtonPressed(g,b); 
        }

        FontMetrics metrics = g.getFontMetrics();
        Rectangle2D stringBounds = metrics.getStringBounds(text, g);
        g.drawString(text,
                (b.getWidth() - (int)stringBounds.getWidth()) / 2,
                metrics.getLeading() + metrics.getMaxAscent() + (b.getHeight() - (int)stringBounds.getHeight()) / 2);

        if (b.isFocusPainted() && b.hasFocus()) {
            Rectangle viewRect = new Rectangle();
            final int inset = 1;
            viewRect.x = inset;
            viewRect.y = inset;
            viewRect.width = b.getWidth() - (inset + viewRect.x) - 1;
            viewRect.height = b.getHeight() - (inset + viewRect.y) - 1;
            g.setColor(getFocusColor());
            g.drawRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
        }
    }       
}

public void init() {
    try {
        UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel() {
            private static final long serialVersionUID = 1L;
            @Override public UIDefaults getDefaults() {
                UIDefaults table = super.getDefaults();
                table.put("ButtonUI", ButtonUI.class.getName());
                return table;
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
    // ...
}
Albert
  • 65,406
  • 61
  • 242
  • 386
  • Could you add some more info on where is the trick that achieved what you wanted? – Matthieu Nov 10 '16 at 17:05
  • 1
    @Matthieu: By overwriting the look-and-feel, I can handle the text-drawing myself, and calling `g.drawString` will not add an ellipsis (that is handled somewhere else by the standard look-and-feel). – Albert Nov 11 '16 at 07:19
  • This solution depends on using Metal (which means that your are stuck with it), and also font sizes, layout manager, layout configuration, etc. This won't be a problem until any of these changes, then the button will look wrong, or the text may spill beyond the button border. A better fix would be to adjust the button's layout settings inside the JPanel where it lives. – toolforger Sep 10 '18 at 09:09
  • @toolforger: If you know a better solution, maybe post it as a separate answer? – Albert Sep 25 '18 at 14:18
  • I don't know how to write a good answer. I'd have to go by a lot of assumptions wrt. what LayoutManager is the right one for the reader, and it would be wrong in at least 50% of cases. Covering all possible LayoutManagers would become a 5-page essay, and I don't have time for that. – toolforger Sep 25 '18 at 21:01
0

You could use a cross platform look and feel (Like Nimbus) to stop this occuring

tofarr
  • 7,682
  • 5
  • 22
  • 30
  • Use `UIManager.setLookAndFeel(...)` and select one of the provided look and feel implementations (MetalLookAndFeel should be truely cross platform). – Thomas Mar 21 '11 at 16:03
  • Or use `UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());` – Thomas Mar 21 '11 at 16:05
  • @Thomas: It seems like this disables anti-aliased font. Can I avoid that? – Albert Mar 21 '11 at 16:40
  • I'm not sure but the LaF might not support anti-aliased fonts (which JRE version are you using btw?). However, you might try and download another LaF (look [here](http://www.taranfx.com/best-java-swing-look-and-feel-themes-professional-casual-top-10) for example .) – Thomas Mar 21 '11 at 16:49
  • @Thomas: I use Java 1.6.0. And I think I found a good way to work around the anti-aliasing issue. I'll add some information [here](http://stackoverflow.com/questions/5353904/java-applet-no-antialiased-font-in-browser-but-in-appletviewer) about it. – Albert Mar 21 '11 at 17:06