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

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

НО это не работает с использованием длинной строки без пробелов: например, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".

Если я установлю 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);
}
}

person Jacopo    schedule 17.04.2015    source источник
comment
1) Чтобы быстрее получить помощь, опубликуйте MCVE (минимальный полный проверяемый пример) или SSCCE (краткий, автономный, правильный пример). 2) Есть приложение. получение полной строки HTML (от <HTML ..> до </HTML>) или только строки в формате HTML (например, часть тела документа)? Если второе, задайте ширину элемента BODY в стилях и пусть необходимая высота рассчитывается по метке.   -  person Andrew Thompson    schedule 17.04.2015


Ответы (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>");
person Freek de Bruijn    schedule 17.04.2015