Как получить JLabel с возможностью многострочного использования? HTML действительно единственный путь? - PullRequest
3 голосов
/ 25 января 2020

Я думаю, что ответ "ты не можешь", но я многое не знаю о Swing. Итак:

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

Неудачные подходы до сих пор:

JLabel("a\nb"); просто не работает, и я не могу представить, почему, потому что это должен быть единственный правильный ответ. JLabel задокументирован для отображения текста, который ему вручают . Но, очевидно, не перевод строки.

У JLabel есть еще одна отвратительная проблема: если текст начинается с <html>, он снова не отображает текст, который ему вручается, - он переосмысливает его как HTML. Мало того, что документация не упоминает об этом, но теперь у меня есть проблема, что, если пользователям разрешено вводить текст, который появляется в JLabel (и они есть), они могут придерживаться форматирования тегов и вызывать всякие хитрости (и они будут).

Я не вижу способа отключить это; поэтому, чтобы получить точное отображение заданного текста, мне нужно предварительно подготовить текст, чтобы сделать полное цитирование HTML, плюс изменить \ n на <br>, а затем обернуть все в <html>...</html>. Я не могу найти ничего в ядре Java, которое бы цитировало - очевидно, вам приходится писать самостоятельно или полагаться на другие библиотеки, такие как apache? Рекомендуемый метод экранирования HTML в Java дает множество причин не полагаться на сторонние библиотеки здесь. И теперь мой код java будет содержать механизм размещения HTML, чтобы я мог надежно отображать текст? Я очень хотел бы избежать этого недокументированного хака. Fr agile.

JTextArea будет обрабатывать многострочный текст, и его можно установить только для чтения. Но я не понимаю, как сказать, чтобы он уменьшился до размера, необходимого для размещения только текста. (JLabel по крайней мере сделал это правильно. [Редактировать: или нет - я вернулся к JLabel, и теперь метки центрируются в своем ряду или расширяются до полного размера - я явно где-то пропускаю настройку]) Я думаю, что должно быть способ сказать ему, чтобы остановить расширение для заполнения строк, но как мне это сделать? setSize(1,1) не делает этого. Я чувствую, что правильный путь лежит по этому пути, но мне нужен указатель, чтобы он автоматически изменял размеры до минимальных размеров.

Или есть какой-то лучший компонент для этого? Есть ли способ визуализировать текстовую строку как изображение минимального размера? Я мог бы отобразить это в JLabel ...

Я также стараюсь не сканировать весь текст и составлять вертикальную рамку с выравниванием по левому краю JLabels, по одному на строку - вероятно, возможно, но определенно более сложно, чем я хочу когда есть (может быть?) более простое решение.

Обратите внимание, что я не могу жестко указать размер любого компонента. Описания компонентов генерируются сервером и отправляются в приложение, которое генерирует виджеты на основе описаний на лету и добавляет их в контейнеры Box. Сервер не может выполнять вычисления в пикселях; Мне нужно полагаться на Swing, чтобы сделать макет просто на основе порядка вещей в коробках. И в большинстве случаев это означает, что виджеты должны занимать минимально возможный размер.

Как мне?

По указанию я попробовал это. Появилась только одна панель, и у нее не было границы, поэтому я не вижу, сколько места она бы заняла.

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.BorderFactory; 
import javax.swing.border.Border;

public class MainTextPane {
    public static void main(final String[] args) {
        Border loweredbevel = BorderFactory.createLoweredBevelBorder();

        final JTextPane pane = new JTextPane();
        pane.setText("Hello, this is a\ntwo lined string!");
        final JTextPane pane2 = new JTextPane();
        pane2.setText("Next!");
        pane.setBorder(loweredbevel); //no effect
        pane2.setBorder(loweredbevel); //no effect


        final JFrame frame = new JFrame("TextPane with new lines.");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(pane);
        frame.getContentPane().add(pane2); //clobbered previous pane
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

1 Ответ

1 голос
/ 25 января 2020

Просто используйте JTextPane, что JEditorPane. Если вы хотите предпочитаемый размер, просто звоните getPreferredSize() в любое время (после настройки текста). Вы можете установить его в редактируемый или нет, и скопировать-вставить из него легко, и он будет обрабатывать новые строки. Он не должен быть сложным, если вы используете его простым способом:

import javax.swing.JFrame;
import javax.swing.JTextPane;

public class MainTextPane {
    public static void main(final String[] args) {
        final JTextPane pane = new JTextPane();
        pane.setText("Hello, this is a\nnew lined string! Hope JTextPane is what we are looking for here.");

        final JFrame frame = new JFrame("TextPane with new lines.");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(pane);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Если вы собираетесь загрузить его с произвольным текстом, я бы предложил использовать его внутри JScrollPane и настройте предпочтительный размер JScrollPane в соответствии с вашими потребностями.

Также протестирован JEditorPane, и он не будет таким простым, как JTextPane.

Если У вас есть дополнительные требования, сообщите нам об этом в комментариях или обновите свой вопрос.

Изменить 1

Что касается предоставленного вами кода, вы видите, что первая панель clobbers the второй, потому что вы добавили их обоих на панель содержимого без установки LayoutManager. Попробуйте установить для LayoutManager значение FlowLayout (например, расположив две панели рядом друг с другом).

Что касается границы скоса, я вижу это ясно, но оно действительно немного тонкое, поэтому, вероятно, поэтому вы его не видели. Я также запустил ваш предоставленный код, и он виден, но не легко. В любом случае, попробуйте этот код:

import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.BorderFactory; 
import javax.swing.border.Border;

public class MainTextPane {
    public static void main(final String[] args) {
        Border loweredbevel = BorderFactory.createLoweredBevelBorder();

        final JTextPane pane = new JTextPane();
        pane.setText("Hello, this is a\ntwo lined string!");
        final JTextPane pane2 = new JTextPane();
        pane2.setText("Next!");
        pane.setBorder(loweredbevel);
        pane2.setBorder(loweredbevel);


        final JFrame frame = new JFrame("TextPane with new lines.");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new FlowLayout()); //Added this line of code...
        frame.getContentPane().add(pane);
        frame.getContentPane().add(pane2);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
...