Перенос строки JEditorPane в Java7

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

Я новичок в Java, и моя проблема заключается в следующем. Я пишу небольшую программу для чата и использую JEditorPane с HTMLEditorKit для отображения текста разными цветами, для отображения смайлов и отображения гиперссылок.

Моя проблема в том, что после некоторых исследований я обнаружил, что проблема может быть связана с Java7, я не могу заставить перенос строк работать должным образом. Я хочу, чтобы текст переносился по словам и переносился в середине строк, превышающих ширину компонента. Перенос слов работает нормально, но если кто-то вводит довольно длинную строку, JEditorPane расширяется, и вам нужно изменить размер фрейма, чтобы все отображалось на экране, чего я не хочу.

Я пробовал несколько исправлений для этой проблемы, но они позволяют только перенос букв, так что перенос слов больше не работает. Кроме того, я хочу, чтобы пользователь мог переносить свой текст, нажимая Enter. Для этого я добавляю \n к тексту, и с исправлениями это больше не повлияет на результат, и все будет отображаться в одной строке.

У меня такое ощущение, что я провел годы в Интернете, чтобы найти решение, но пока ничего не помогло в моем случае, тем более, что это все время было одно и то же исправление. Я надеюсь, что вы, ребята, можете мне помочь.

Вкратце это означает:

Что у меня есть:

  • Строка переносит слова в случае длинных строк, разделенных пробелами
  • если вы используете Windows, и ваш ввод содержит переносы строк, созданные нажатием Enter, они также будут переноситься
  • Если вы введете очень длинную строку без пробелов, панель будет расширена, и вам придется изменить размер рамки.
  • Форматирование HTML позволяет отображать различные цвета, а также гиперссылки и смайлики.

Что мне нужно:

  • Поведение переноса слов, как на данный момент, в случае, если это возможно, но перенос букв ТОЛЬКО в случае длинных строк, не разделенных пробелами, чтобы предотвратить расширение панели.
  • Добавленные вручную переносы строк, сделанные нажатием ENTER в области ввода или копированием предварительно отформатированного текста на панель ввода
  • Форматирование HTML, как я уже делал

Что я пробовал и что не помогло:

jtextpane не переносит текст и JTextPane не переносит текст

Вот некоторый код, чтобы попробовать это самостоятельно. В левом нижнем углу находится поле ввода для ввода текста. Вы также можете добавить перенос строки, нажав Enter. После нажатия на кнопку вы увидите текст в области выше.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;

@SuppressWarnings("serial")
public class LineWrapTest extends JFrame implements ActionListener, KeyListener {

private JButton btnSend;
private JTextArea textAreaIn;
private JEditorPane textAreaOut;
private HTMLEditorKit kit;
private HTMLDocument doc;

public LineWrapTest() {

    this.setSize(600, 500);
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.setLocationRelativeTo(null);
    this.setTitle("Linewrap Test");
}

/**
 * Not important for problem
 */
public void paintScreen() {

    this.setLayout(new BorderLayout());

    this.add(this.getPanelOut(), BorderLayout.CENTER);
    this.add(this.getPanelIn(), BorderLayout.SOUTH);

    this.textAreaIn.requestFocusInWindow();
    this.setVisible(true);
}

/**
 * Not important for problem
 * 
 * @return panelOut
 */
private JPanel getPanelOut() {

    JPanel panelOut = new JPanel();
    panelOut.setLayout(new BorderLayout());

    this.textAreaOut = new JEditorPane();
    this.textAreaOut.setEditable(false);
    this.textAreaOut.setContentType("text/html");

    this.kit = new HTMLEditorKit();
    this.doc = new HTMLDocument();

    StyleSheet styleSheet = this.kit.getStyleSheet();
    this.kit.setStyleSheet(styleSheet);

    this.textAreaOut.setEditorKit(this.kit);
    this.textAreaOut.setDocument(this.doc);

    TitledBorder border = BorderFactory.createTitledBorder("Output");
    border.setTitleJustification(TitledBorder.CENTER);

    panelOut.setBorder(border);
    panelOut.add(this.textAreaOut);

    return panelOut;
}

/**
 * Not important for problem
 * 
 * @return panelIn
 */
private JPanel getPanelIn() {

    JPanel panelIn = new JPanel();
    panelIn.setLayout(new BorderLayout());

    this.textAreaIn = new JTextArea();
    this.textAreaIn.setLineWrap(true);
    this.textAreaIn.setWrapStyleWord(true);

    TitledBorder border = BorderFactory.createTitledBorder("Input");
    border.setTitleJustification(TitledBorder.CENTER);

    panelIn.setBorder(border);
    panelIn.add(this.getBtnSend(), BorderLayout.EAST);
    panelIn.add(this.textAreaIn, BorderLayout.CENTER);

    return panelIn;
}

/**
 * Not important for problem
 * 
 * @return btnSend
 */
private JButton getBtnSend() {

    this.btnSend = new JButton("Send");
    this.btnSend.addActionListener(this);

    return this.btnSend;
}

private void append(String text) {

    try {
        this.kit.insertHTML(this.doc, this.doc.getLength(), text, 0, 0, null);
    } catch (BadLocationException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private String getHTMLText() {

    String txtIn = this.textAreaIn.getText().trim().replaceAll(SEPARATOR, "<br/>");

    StringBuffer htmlBuilder = new StringBuffer();

    htmlBuilder.append("<HTML>");
    htmlBuilder.append(txtIn);
    htmlBuilder.append("</HTML>");

    return htmlBuilder.toString();
}

@Override
public void actionPerformed(ActionEvent e) {

    if (e.getSource() == this.btnSend) {
        this.append(this.getHTMLText());
        this.textAreaIn.setText("");
        this.textAreaIn.requestFocusInWindow();
    }
}

public static void main(String[] args) {

    LineWrapTest test = new LineWrapTest();
    test.paintScreen();
}

@Override
public void keyPressed(KeyEvent e) {

    if (e.getKeyCode() == KeyEvent.VK_ENTER)
        if (!this.textAreaIn.getText().trim().isEmpty())
            this.textAreaIn.setText(this.textAreaIn.getText() + SEPARATOR);
}

@Override
public void keyReleased(KeyEvent e) {
}

@Override
public void keyTyped(KeyEvent e) {
}
}

ОБНОВЛЕНИЕ: основано на некоторых частях http://java-sl.com/tip_java7_text_wrapping_bug_fix.html

Каким-то образом я понял это, чтобы шагнуть немного ближе к своей цели. Я попытался объединить исправление для HTMLEditorKit с исправлением StlyedEditorKit. Но я должен быть честным, я понятия не имею, что я на самом деле там делал :( Печально то, что ручной перенос строк больше не работает с этим в качестве замены HTMLEditorKit. Может быть, вы можете использовать это как база для лучшей реализации.

Чтобы использовать его в моем примере, просто создайте новый класс в проекте с помощью CustomEditorKit и замените HTMLEditorKit в примере этим CustomEditorKit. Вы заметите, что перенос слов и букв теперь работает, но если вы нажмете ENTER, чтобы получить свой собственный перенос строк, это изменение больше не будет отображаться на панели вывода, и все будет отображаться в одной строке. Еще одна странная проблема заключается в том, что если вы измените размер кадра, линии иногда будут накладываться друг на друга.

import javax.swing.SizeRequirements;
import javax.swing.text.Element;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.InlineView;
import javax.swing.text.html.ParagraphView;

@SuppressWarnings("serial")
public class CustomEditorKit extends HTMLEditorKit {

@Override
public ViewFactory getViewFactory() {

    return new HTMLFactory() {
        @Override
        public View create(Element e) {
            View v = super.create(e);
            if (v instanceof InlineView) {
                return new InlineView(e) {
                    @Override
                    public int getBreakWeight(int axis, float pos, float len) {
                        return GoodBreakWeight;
                    }

                    @Override
                    public View breakView(int axis, int p0, float pos, float len) {
                        if (axis == View.X_AXIS) {
                            this.checkPainter();
                            this.removeUpdate(null, null, null);
                        }
                        return super.breakView(axis, p0, pos, len);
                    }
                };
            }
            else if (v instanceof ParagraphView) {
                return new ParagraphView(e) {
                    @Override
                    protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
                        if (r == null) {
                            r = new SizeRequirements();
                        }
                        float pref = this.layoutPool.getPreferredSpan(axis);
                        float min = this.layoutPool.getMinimumSpan(axis);
                        // Don't include insets, Box.getXXXSpan will include them. 
                        r.minimum = (int) min;
                        r.preferred = Math.max(r.minimum, (int) pref);
                        r.maximum = Integer.MAX_VALUE;
                        r.alignment = 0.5f;
                        return r;
                    }

                };
            }
            return v;
        }
    };
    }
}

person BenGe89    schedule 08.07.2013    source источник
comment
Хорошо, вот что у меня происходит с приведенным выше кодом. JTextArea отлично переносится. Длинные строки и слова переносятся на следующую строку. JEditorPane переносит слова, пока не будет расширен длинной строкой. Затем для переноса слов предложение должно быть длиннее, чем строка, которая расширяет компонент. Нажатие ввода не вызывает пользовательский перенос в настоящий момент, используя универсальный разделитель строк. Что вы хотите: перенос JEditorPane для длинных строк без добавления пробелов, как это делает JTextArea, чтобы он не расширялся. Кроме того, нажав введите пользовательскую обертку в JEpane.   -  person Patrick Sebastien    schedule 09.07.2013


Ответы (2)


В ПОРЯДКЕ! Итак, я, наконец, получил все, что у вас были проблемы с работой. Потребовалось некоторое исследование и много проб и ошибок, но вот оно:

Вот что я сделал:

  • Поместите JEditorPane в JScrollPane, чтобы вы могли прокручивать вверх и вниз по мере увеличения сообщения.
  • Добавлен пользовательский перенос слов. Пользовательский перенос слов будет переносить слова и длинные слова в нужном месте слова. Вы были правы, это ошибка текущей версии Java. http://bugs.sun.com/view_bug.do?bug_id=7125737
  • Добавлена ​​возможность для пользователя переходить на новую строку, нажимая Enter. Однако это мешало пользовательскому переносу слов, поэтому вам может не понравиться, как я этого добился. В примере кода я предлагаю другие варианты.
  • Сохранены ваши возможности HTMLDocument. У меня был соблазн не делать этого, но я нашел обходной путь, чтобы его можно было сохранить.
  • Приложение по-прежнему использует JEditorPane, но вы можете переключить его на JTextPane, если хотите. Я попробовал оба, и они оба были функциональными.

Итак, вот код. Это немного долго, и вы можете изменить его в зависимости от ваших предпочтений. Я прокомментировал, где я внес изменения, и попытался их объяснить.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SizeRequirements;
import javax.swing.border.TitledBorder;
import javax.swing.text.*;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.InlineView;
import javax.swing.text.html.StyleSheet;

@SuppressWarnings("serial")
public class LineWrapTest extends JFrame implements ActionListener, KeyListener {

    //This is the separator.
    private String SEPARATOR = System.getProperty("line.separator");
    private JButton btnSend;
    private JTextArea textAreaIn;
    private JEditorPane textAreaOut;
    private JScrollPane outputScrollPane;
    private HTMLEditorKit kit;
    private HTMLDocument doc;


    public LineWrapTest() {

        this.setSize(600, 500);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        this.setTitle("Linewrap Test");
    }

    /**
     * Not important for problem
     */
    public void paintScreen() {

        this.setLayout(new BorderLayout());

        this.add(this.getPanelOut(), BorderLayout.CENTER);
        this.add(this.getPanelIn(), BorderLayout.SOUTH);

        this.textAreaIn.requestFocusInWindow();
        this.setVisible(true);
    }


    /**
     * Not important for problem
     * 
     * @return panelOut
     */
    private JPanel getPanelOut() {

        JPanel panelOut = new JPanel();
        panelOut.setLayout(new BorderLayout());

        this.textAreaOut = new JEditorPane();
        this.textAreaOut.setEditable(false);
        this.textAreaOut.setContentType("text/html");

        //I added this scroll pane.
        this.outputScrollPane = new JScrollPane(this.textAreaOut);

        /*
         * This is a whole whack of code.  It's a combination of two sources.
         * It achieves the wrapping you desire: by word and longgg strings
         * It is a custom addition to HTMLEditorKit
         */
        this.kit = new HTMLEditorKit(){
           @Override 
           public ViewFactory getViewFactory(){ 

               return new HTMLFactory(){ 
                   public View create(Element e){ 
                      View v = super.create(e); 
                      if(v instanceof InlineView){ 
                          return new InlineView(e){ 
                              public int getBreakWeight(int axis, float pos, float len) { 
                                  //return GoodBreakWeight;
                                  if (axis == View.X_AXIS) {
                                      checkPainter();
                                      int p0 = getStartOffset();
                                      int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
                                      if (p1 == p0) {
                                          // can't even fit a single character
                                          return View.BadBreakWeight;
                                      }
                                      try {
                                          //if the view contains line break char return forced break
                                          if (getDocument().getText(p0, p1 - p0).indexOf(SEPARATOR) >= 0) {
                                              return View.ForcedBreakWeight;
                                          }
                                      }
                                      catch (BadLocationException ex) {
                                          //should never happen
                                      }  

                                  }
                                  return super.getBreakWeight(axis, pos, len);
                              } 
                              public View breakView(int axis, int p0, float pos, float len) { 
                                  if (axis == View.X_AXIS) {
                                      checkPainter();
                                      int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
                                      try {
                                          //if the view contains line break char break the view
                                          int index = getDocument().getText(p0, p1 - p0).indexOf(SEPARATOR);
                                          if (index >= 0) {
                                              GlyphView v = (GlyphView) createFragment(p0, p0 + index + 1);
                                              return v;
                                          }
                                      }
                                      catch (BadLocationException ex) {
                                          //should never happen
                                      }

                                  }
                                  return super.breakView(axis, p0, pos, len);
                            } 
                          }; 
                      } 
                      else if (v instanceof ParagraphView) { 
                          return new ParagraphView(e) { 
                              protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { 
                                  if (r == null) { 
                                        r = new SizeRequirements(); 
                                  } 
                                  float pref = layoutPool.getPreferredSpan(axis); 
                                  float min = layoutPool.getMinimumSpan(axis); 
                                  // Don't include insets, Box.getXXXSpan will include them. 
                                    r.minimum = (int)min; 
                                    r.preferred = Math.max(r.minimum, (int) pref); 
                                    r.maximum = Integer.MAX_VALUE; 
                                    r.alignment = 0.5f; 
                                  return r; 
                                } 

                            }; 
                        } 
                      return v; 
                    } 
                }; 
            } 
        }; 

        this.doc = new HTMLDocument();

        StyleSheet styleSheet = this.kit.getStyleSheet();
        this.kit.setStyleSheet(styleSheet);

        this.textAreaOut.setEditorKit(this.kit);
        this.textAreaOut.setDocument(this.doc);

        TitledBorder border = BorderFactory.createTitledBorder("Output");
        border.setTitleJustification(TitledBorder.CENTER);

        panelOut.setBorder(border);

        //I changed this to add the scrollpane, which now contains
        //the JEditorPane
        panelOut.add(this.outputScrollPane);

        return panelOut;
    }

    /**
     * Not important for problem
     * 
     * @return panelIn
     */
    private JPanel getPanelIn() {

        JPanel panelIn = new JPanel();
        panelIn.setLayout(new BorderLayout());

        this.textAreaIn = new JTextArea();
        this.textAreaIn.setLineWrap(true);
        this.textAreaIn.setWrapStyleWord(true);

        //This disables enter from going to a new line.  Your key listener does that.
        this.textAreaIn.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "none");
        //For the key listener to work, it needs to be added to the component
        this.textAreaIn.addKeyListener(this);

        TitledBorder border = BorderFactory.createTitledBorder("Input");
        border.setTitleJustification(TitledBorder.CENTER);

        panelIn.setBorder(border);
        panelIn.add(this.getBtnSend(), BorderLayout.EAST);
        panelIn.add(this.textAreaIn, BorderLayout.CENTER);

        return panelIn;
    }

    /**
     * Not important for problem
     * 
     * @return btnSend
     */
    private JButton getBtnSend() {

        this.btnSend = new JButton("Send");
        this.btnSend.addActionListener(this);

        return this.btnSend;
    }


    private void append(String text) {

        try {
            this.kit.insertHTML(this.doc, this.doc.getLength(), text, 0, 0, null);
        } catch (BadLocationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String getHTMLText() {
        //I tried to find a work around for this but I couldn't.  It could be done
        //by manipulating the HTMLDocument but it's beyond me.  Notice I changed
        //<br/> to <p/>.  For some reason, <br/> no longer went to the next line
        //when I added the custom wrap.  <p/> seems to work though.
        String txtIn = this.textAreaIn.getText().trim().replaceAll(SEPARATOR, "<p/>");

        //My IDE recommends you use StringBuilder instead, that's up to you.
        //I am not sure what the difference would be.
        StringBuffer htmlBuilder = new StringBuffer();

        htmlBuilder.append("<HTML>");
        htmlBuilder.append(txtIn);
        htmlBuilder.append("</HTML>");

        return htmlBuilder.toString();
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getSource() == this.btnSend) {
            this.append(this.getHTMLText());
            this.textAreaIn.setText("");
            this.textAreaIn.requestFocusInWindow();
        }
    }

    public static void main(String[] args) {
        LineWrapTest test = new LineWrapTest();
        test.paintScreen();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER){
            if (!this.textAreaIn.getText().trim().isEmpty()) {
                //I made this work by defining the SEPARATOR.
                //You could use append(Separator) instead if you want.
                this.textAreaIn.setText(this.textAreaIn.getText() + SEPARATOR);
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

}

Вот (большинство) ссылок, которые я использовал для решения этой проблемы:

Включение переноса слов в JTextPane с HTMLDocument

Индивидуальная обертка представляет собой комбинацию этих двух:

http://java-sl.com/tip_html_letter_wrap.html

http://java-sl.com/wrap.html

Удаление привязки клавиш для JTextArea:

http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html

Если у вас есть какие-либо вопросы, просто оставьте комментарий ниже. Я отвечу на них. Я искренне надеюсь, что это решит ваши проблемы

person Patrick Sebastien    schedule 08.07.2013
comment
Привет, Алан, спасибо за подробный ответ. Особенно сепаратор был для меня новым. Но твой фикс мне не помогает. У меня нет проблем с переносом слов или полосой прокрутки, мне нужно и то, и другое, перенос слова и буквы. Вы написали, что у вас возникли проблемы с моим примером кода, что пошло не так? У меня работает :/ - person BenGe89; 09.07.2013
comment
@ BenGe89 Возможно, я неправильно понял ваш вопрос. Не могли бы вы отредактировать его, чтобы было более понятно, что именно вам нужно и в чем ваши проблемы? Когда я запустил ваш код, все, что появилось, было пустым окном с кнопкой внизу справа. - person Patrick Sebastien; 09.07.2013
comment
Я отредактировал OP, надеюсь, теперь это прояснит ситуацию. Я также добавил некоторые границы в пример и краткое описание в ОП. Я также удалил часть с полосой прокрутки, поскольку она не имеет большого отношения к проблеме, извините, что ввела ее в заблуждение. Короче говоря, я хочу то, что у меня уже есть, но, если возможно, со словом переноса поведения Java6, иначе оберните букву для HTMLEditorKit. Пример показывает только проблему. Я еще не добавил line.separator, так как замена не сработала. Нажав Enter, я хочу, чтобы программа создала собственный перенос строки. - person BenGe89; 09.07.2013
comment
@ BenGe89 Хорошо, спасибо за редактирование. Я посмотрю и посмотрю, есть ли какое-либо решение, которое я могу придумать, и соответствующим образом отредактирую свой ответ. Если я не могу понять это, мне, возможно, придется удалить свой ответ. - person Patrick Sebastien; 09.07.2013
comment
Большое тебе спасибо! Очень ценю вашу помощь в этом! Тем временем я снова попробовал кое-что. Не большим успехом, но небольшим успехом стала комбинация исправления для HTMLEditorKit и StyledEditorKit. Я добавил это под свой пример, может быть, вы можете взять какую-то информацию из этого, я не могу :/ Мне определенно нужно погрузиться в Java глубже... Кстати, вы знаете лучший способ создавать собственные переносы строк, чем я 'я делаю? Не очень нравится способ замены (String, String), особенно потому, что он не работает с line.separator. - person BenGe89; 09.07.2013
comment
@BenGe89 BenGe89 Итак, я провел полный анализ вашего приложения на ручке и бумаге, поэтому я чувствую, что хорошо понимаю структуру. На данный момент я исправил некоторые проблемы, но есть еще некоторые вещи, о которых мне нужно позаботиться. Я чувствую, что могу исправить это, но я хочу знать: Имеет ли значение, используете ли вы JEditorPane или JTextPane , исходя из предоставленной мной ссылки. в Оракл? - person Patrick Sebastien; 09.07.2013
comment
Я провел несколько тестов и пока не вижу никаких различий при использовании JTextPane вместо JEditorPane. Так что я думаю, это не имеет значения, и, насколько я понимаю, TextPane или EditorPane является более или менее своего рода контейнером, и документ выполняет свою работу, не так ли? Короче говоря, я не думаю, что это имеет значение. Еще раз спасибо! - person BenGe89; 09.07.2013
comment
@BenGe89 Оки Док. Смотрите мой ответ. Это должно быть то, что вы ищете. Если у вас есть какие-либо вопросы, дайте мне знать. Я знаю, что не должен говорить такие вещи, но я потратил почти 6-8 часов на выяснение этого, поэтому, если ответ сработает для вас, когда вы наберете достаточно репутации, я бы искренне хотел, чтобы мой ответ проголосовал, ха-ха. - person Patrick Sebastien; 10.07.2013
comment
Вот и все! Работает как часы. Спасибо большое, теперь ты мой герой. Я попытался заменить ‹br/› на ‹p/› в своем CustomEditorKit, и это тоже сработало, но я больше верю в вашу реализацию, поэтому я предпочитаю использовать вашу. Я не могу отблагодарить вас достаточно. Что касается StringBuffer/Builder, на самом деле между ними нет реальной разницы, но StringBuffer является потокобезопасным, а Builder — нет. - person BenGe89; 10.07.2013

Я нашел смертельно лучшее решение: <br> правильно обрабатывается HTMLEditorKit, но в сообщении Патрика Себастьяна упоминается, что это не так. Это потому, что его ViewFactory угрожает всему объекту InlineView как переносимому, но BRView также является InlineView. Смотрите мое решение ниже:

class WrapColumnFactory extends HTMLEditorKit.HTMLFactory {

        @Override
        public View create(Element elem) {
            View v = super.create(elem);

            if (v instanceof LabelView) {

                // the javax.swing.text.html.BRView (representing <br> tag) is a LabelView but must not be handled
                // by a WrapLabelView. As BRView is private, check the html tag from elem attribute
                Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
                if ((o instanceof HTML.Tag) && o == HTML.Tag.BR) {
                    return v;
                }

                return new WrapLabelView(elem);
            }

            return v;
        }
    }

    class WrapLabelView extends LabelView {

        public WrapLabelView(Element elem) {
            super(elem);
        }

        @Override
        public float getMinimumSpan(int axis) {
            switch (axis) {
                case View.X_AXIS:
                    return 0;
                case View.Y_AXIS:
                    return super.getMinimumSpan(axis);
                default:
                    throw new IllegalArgumentException("Invalid axis: " + axis);
            }
        }

    }
person Ludovic Pecquot    schedule 27.10.2014
comment
Это лучшее (самое простое, а также наиболее полное) решение проблемы, которое я нашел. Я разделил это решение на компоненты как ответ на аналогичный вопрос. - person vallismortis; 11.08.2015