Jacopo
Jacopo

Reputation: 97

Java JLabel Height with multiple lines

Hi I've got a problem in the code below ( in method "append(String str)" mostly). I want to show messages received in HTML format (so I need to use JLabel). Without setting tac.preferredSize here is what I get: enter image description here

BUT it isn't working using long string without blank spaces: such as "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".

If I set tac.preferredSize the height of the bubble isn't increasing: enter image description here

How can I overcome these problems? (working on layout/sizes and not modifying input string)

Here's the code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ClientGUI extends JFrame implements ActionListener {

private static final long serialVersionUID = 1L;
private JLabel label;
private JTextField tf;
private JPanel chatPanel;
private JScrollPane scroll;

ClientGUI() {
    super("Chat Client");
    label = new JLabel("You can write messages below:", SwingConstants.CENTER);
    chatPanel = new JPanel();

    tf = new JTextField("");
    tf.setBackground(Color.WHITE);
    tf.requestFocus();
    tf.setVisible(true);
    tf.addActionListener(this);

    chatPanel.setLayout(new BoxLayout(chatPanel, BoxLayout.PAGE_AXIS));
    chatPanel.add(Box.createVerticalGlue());
    JPanel centerPanel = new JPanel(new GridLayout(1,1));

    scroll = new JScrollPane();
    scroll.setViewportView(chatPanel);
    scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
    scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

    centerPanel.add(scroll);

    add(centerPanel, BorderLayout.CENTER);

    JPanel southPanel = new JPanel(new BorderLayout());
    JPanel writeChatPanel = new JPanel(new GridLayout(2,1));
    writeChatPanel.add(label);
    writeChatPanel.add(tf);
    southPanel.add(writeChatPanel, BorderLayout.NORTH);

    add(southPanel, BorderLayout.SOUTH);

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(600, 600);
    setVisible(true);

    chatPanel.scrollRectToVisible(new Rectangle(chatPanel.getSize()));

}

void append(String str) {
    LeftArrowBubble leftArrowBubble = new LeftArrowBubble();
    leftArrowBubble.setMaximumSize(new Dimension(400,350));
    JLabel tac = new JLabel();
    tac.setMaximumSize(new Dimension(350,400));
    //tac.setPreferredSize(new Dimension(350,50)); //<----------
    System.out.println(str);
    tac.setText("<html><body style='width:  350px; padding:15px;display:block;'>"+str+"</body></html>");

    tac.setOpaque(false);
    leftArrowBubble.add(tac, BorderLayout.NORTH);

    chatPanel.add(leftArrowBubble);     

    chatPanel.add(Box.createRigidArea(new Dimension(0,5)));
    Rectangle rect = chatPanel.getBounds();
    Rectangle r2 = scroll.getViewport().getVisibleRect();
    chatPanel.scrollRectToVisible(new Rectangle((int) rect.getWidth(), 
            (int) rect.getHeight(), (int) r2.getWidth(), (int) r2.getHeight()));
    revalidate();
    repaint();
}
public void actionPerformed(ActionEvent e) {    
        // just have to send the message
        append(tf.getText());               
        tf.setText("");
        return;
}
public static void main(String[] args) {
    new ClientGUI();
}
}

And the bubble class:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import javax.swing.BoxLayout;
import javax.swing.JPanel;

public class LeftArrowBubble extends JPanel {
private static final long serialVersionUID = -5389178141802153305L;

public LeftArrowBubble() {
   this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
}

@Override
protected void paintComponent(final Graphics g) {
   final Graphics2D graphics2D = (Graphics2D) g;
   RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
   qualityHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
   graphics2D.setRenderingHints(qualityHints);
   graphics2D.setPaint(new Color(80, 150, 180));
   int width = getWidth();
   int height = getHeight();
   GeneralPath path = new GeneralPath();
   path.moveTo(5, 10);
   path.curveTo(5, 10, 7, 5, 0, 0);
   path.curveTo(0, 0, 12, 0, 12, 5);
   path.curveTo(12, 5, 12, 0, 20, 0);
   path.lineTo(width - 10, 0);
   path.curveTo(width - 10, 0, width, 0, width, 10);
   path.lineTo(width, height - 10);
   path.curveTo(width, height - 10, width, height, width - 10, height);
   path.lineTo(15, height);
   path.curveTo(15, height, 5, height, 5, height - 10);
   path.lineTo(5, 15);
   path.closePath();
   graphics2D.fill(path);
}
}

Upvotes: 0

Views: 1579

Answers (1)

Freek de Bruijn
Freek de Bruijn

Reputation: 3622

If you break up the words that are too long by adding spaces, I think most of your problems are solved. Some small changes to the dimensions of the leftArrowBubble and tac components would be useful as well.

You could replace the following lines in the append method:

leftArrowBubble.setMaximumSize(new Dimension(400,350));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(350,400));
//tac.setPreferredSize(new Dimension(350,50)); //<----------
System.out.println(str);
tac.setText("<html><body style='width:350px;padding:15px;display:block;'>"
            + str + "</body></html>");

by the following code (you can also take a look at Split string to equal length substrings in Java for more ways to split a string in equal parts):

leftArrowBubble.setMaximumSize(new Dimension(500, 500));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(450, 450));
//tac.setPreferredSize(new Dimension(350, 50)); //<----------

final int maximumSize = 56;
String textWithSeparators = "";
final StringTokenizer textTokenizer
    = new StringTokenizer(str, " \t\n\r", true);

while (textTokenizer.hasMoreTokens()) {
    final String part = textTokenizer.nextToken();
    for (int beginIndex = 0; beginIndex < part.length();
         beginIndex += maximumSize)
        textWithSeparators += (beginIndex == 0 ? "" : " ")
            + part.substring(beginIndex,
                             Math.min(part.length(),
                                      beginIndex + maximumSize));
}

System.out.println(textWithSeparators);

tac.setText("<html><body style='width:350px;padding:15px;display:block;'>"
            + textWithSeparators + "</body></html>");

The value for maximumSize could be calculated using font metrics (see How to get the correct String width from FontMetrics in JAVA for more information), but I've used a fixed value here for the sake of simplicity.

It would be nice to link the dimensions of leftArrowBubble, tac, and the width in the html string, like:

final int size = 500;
leftArrowBubble.setMaximumSize(new Dimension(size, size));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(size - 50, size - 50));
// [...]
tac.setText("<html><body style='width:" + (size - 150)
            + "px;padding:15px;display:block;'>"
            + textWithSeparators + "</body></html>");

Upvotes: 1

Related Questions