15

Is it possible to achieve automatic word wrap of texts in JButtons? I am having few dynamic buttons which I create on runtime. I want to put word wrap feature on the buttons so that I can see some better test on buttons. Is it possible to do that?

Vini.g.fer
  • 11,639
  • 16
  • 61
  • 90
Deepak
  • 6,684
  • 18
  • 69
  • 121

4 Answers4

25

This example uses Java's inbuilt CSS rendering abilities to to do the 'heavy lifting' of determining when to do a line break. It uses a JLabel, but the same principles apply to any component that will render HTML.

FixedWidthText.java

import javax.swing.*;

class FixedWidthText {

    public static void showLabel(int width, String units) {
        String content1 = "<html>"
                + "<body style='background-color: white; width: ";
        String content2 = "'>"
                + "<h1>Fixed Width</h1>"
                + "<p>Body width fixed at ";
        String content3
                = " using CSS.  "
                + "Java's HTML"
                + " support includes support"
                + " for basic CSS.</p>";
        final String content = content1 + width + units
                + content2 + width + units + content3;
        Runnable r = () -> {
            JLabel label = new JLabel(content);
            JOptionPane.showMessageDialog(null, label);
        };
        SwingUtilities.invokeLater(r);
    }

    public static void main(String[] args) {
        showLabel(160, "px");
        showLabel(200, "px");
        showLabel(50, "%");
    }
}

Screen shots

160px

enter image description here

200px

enter image description here

50%

enter image description here

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
16

Use HTML...

button.setText("<html><center>"+"This is a"+"<br>"+"swing button"+"</center></html>");
Romain Hippeau
  • 24,113
  • 5
  • 60
  • 79
  • yes i know that but if i generate the buttons dynamically its hard for me to do this. I said i will generate the buttons on runtime.. i might have to write another method to handle the text and break it if its too long , which i thought was a tedious option. Is there any better way to do this ? – Deepak Apr 23 '11 at 18:52
  • @Deepak: some suggestions can be found here: http://www.javaworld.com/javaworld/javaqa/2000-03/01-qa-button.html – Hovercraft Full Of Eels Apr 23 '11 at 18:58
  • its better to write my own class to handle auto line breaks. I did it by splitting the text on empty spaces between text and i inserted
    between them. thanks for your reply!!
    – Deepak Apr 23 '11 at 19:02
  • 3
    I don't advise using HTML with any Swing component. There are many bugs in HTML rendering in Swing. Also, baseline support won't work when using HTML, hence LayoutManagers won't be able to align components correctly. – jfpoilpret Apr 24 '11 at 00:52
1

The easiest thing to do is to modify another Component that supports word wrap so that it acts as a Button. I made a simple class which manipulates JTextArea to act as Button.

 public class MultiLineButton extends JTextArea implements MouseListener    {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Color defaultColor;
    private Color highlight, lightHighlight;
    private BtnState state;
    private List<ActionListener> actionListeners;

    public MultiLineButton(String text, Color defaultColor) {
        this.setEditable(false);
        this.setText(text);
        this.setLineWrap(true);
        this.setWrapStyleWord(true);
        this.addMouseListener(this);
        this.setBorder(new EmptyBorder(5, 10, 5, 10));
        state = BtnState.NORMAL;
        this.defaultColor = defaultColor;
        this.setBackground(defaultColor);
        highlight = new Color(122, 138, 153);
        lightHighlight = new Color(184, 207, 229);
        // clickedColor = new Color(r, g, b);/
        actionListeners = new ArrayList<>();
    }

    @Override
    public Color getSelectionColor() {
        return getBackground();
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
        setBackground(lightHighlight);
        state = BtnState.CLICKED;
        repaint();
    }   

    @Override
    public void mouseReleased(MouseEvent e) {
        for (ActionListener l : actionListeners) {
            l.actionPerformed(new ActionEvent(this,     ActionEvent.ACTION_PERFORMED, this.getText()));
        }
        setBackground(defaultColor);
        state = BtnState.NORMAL;
        repaint();
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        state = BtnState.HOVERED;
        repaint();
    }

    @Override
    public void mouseExited(MouseEvent e) {
        setBackground(defaultColor);
        state = BtnState.NORMAL;
        repaint();
    }

    @Override
    public void paintBorder(Graphics g) {
        super.paintBorder(g);
        Graphics g2 = g.create();
        g2.setColor(highlight);
        switch (state) {
        case NORMAL:
            g2.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
            break;
        case HOVERED:
            g2.drawRect(1, 1, getWidth() - 3, getHeight() - 3);
            g2.setColor(lightHighlight);
            g2.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
            g2.drawRect(2, 2, getWidth() - 5, getHeight() - 5);
            break;
        case CLICKED:
            Border b = new BevelBorder(BevelBorder.LOWERED);
            b.paintBorder(this, g2, 0, 0, getWidth(), getHeight());
            break;
        }
        g2.dispose();
    }

    public void addActionListener(ActionListener l) {
        actionListeners.add(l);
    }

    public List<ActionListener> getActionListeners() {
        return actionListeners;
    }
}

BtnState is simply an enum with the Constants NORMAL, HOVERED, CLICKED

Most of the code is just used to make the JTextArea look like a JButton and it works quite fine. One drawback is that you loose the ability of modifying it via ButtonModels, but for the most applications this will be enough.

Alexander Daum
  • 741
  • 4
  • 14
-3
@Override
public void paint(Graphics pGraphics)
{
    super.paint(pGraphics);

    Graphics2D g2d = (Graphics2D) pGraphics;
    FontRenderContext frc = g2d.getFontRenderContext();

    String itemName = item.getName();
    AttributedString attributedString = new AttributedString(itemName);
    attributedString.addAttribute(TextAttribute.FONT, getFont());
    AttributedCharacterIterator iterator = attributedString.getIterator();

    LineBreakMeasurer measurer = new LineBreakMeasurer(iterator, frc);
    float wrappingWidth = getSize().width - 15;

    StringBuilder stringBuilder = new StringBuilder("<html><center>");

    int previousIndex = 0;
    while (measurer.getPosition() < itemName.length())
    {
      if (previousIndex != 0) stringBuilder.append("<br>");
      stringBuilder.append(itemName.substring(previousIndex, measurer.getPosition()));
      previousIndex = measurer.getPosition();

      measurer.nextLayout(wrappingWidth);
    }

    if (previousIndex < itemName.length())
    {
      if (previousIndex != 0) stringBuilder.append("<br>");
      stringBuilder.append(itemName.substring(previousIndex));
    }

    stringBuilder.append("</center></html>");
    setText(stringBuilder.toString());
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 5
    This is not a very helpful answer. Throwing code at the reader doesn't help understand, what the problem is, what has been done to resolve it, and why. – IInspectable Jan 17 '16 at 21:42