Java JLabel Высота с несколькими строками

Привет, у меня есть проблема в коде ниже (в основном в методе "append(String str)"). Я хочу показать сообщения, полученные в формате HTML (поэтому мне нужно использовать JLabel). Без установки tac.preferredSize вот что я получаю:

НО это не работает, используя длинную строку без пробелов: например, "аааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа

Если я установлю tac.preferredSize, высота пузырька не увеличивается:

Как я могу преодолеть эти проблемы? (работает с макетом / размерами и не изменяет строку ввода)

Вот код:

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();
}
}

И пузырьковый класс:

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);
}
}

1 ответ

Решение

Если вы разбиваете слова, которые являются слишком длинными, добавляя пробелы, я думаю, что большинство ваших проблем решены. Некоторые небольшие изменения в размерах leftArrowBubble а также tac компоненты также будут полезны.

Вы можете заменить следующие строки в append метод:

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>");

с помощью следующего кода (вы также можете взглянуть на разделенную строку на подстроки равной длины в Java, чтобы найти больше способов разбить строку на равные части):

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>");

Значение для maximumSize может быть рассчитан с использованием метрик шрифта (см. Как получить правильную ширину строки из FontMetrics в JAVA для получения дополнительной информации), но я использовал здесь фиксированное значение для простоты.

Было бы неплохо связать размеры leftArrowBubble, tacи ширина в HTML-строке, например:

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>");
Другие вопросы по тегам