First of all, I hope this is not a problem, I started a new topic. Tbh I have no clue how to ask a question based on an answer already, so I did it.
I am new to Java and my problem is as follows. I am writing a small chat program, and I use JEditorPane with HTMLEditorKit to display text in different colors, to display emoticons and display hyperlinks.
My problem, and after some research, I found out that the problem may be related to Java7, I can not get linewrap to work properly. I want the text wrapped in a word and wrapped in the middle of lines that are larger than the width of the component. The word wrap works fine, but if someone enters a fairly long line, JEditorPane expands and you need to resize the frame to get everything on the screen, which I don't want.
I tried several fixes for this problem, but they only allow message wrapping, so word wrapping no longer works. In addition, I want the user to be able to complete his text by pressing Enter. To do this, I add \ n to the text and with corrections, this will no longer affect the result, and everything will be displayed on one line.
It seems to me that I spent years on the Internet to find a solution, but unitl now didn’t work for my case, especially since it was the same fix all the time. Hope you guys can help me.
It means:
What I have:
- A line wraps a word in the case of long lines separated by spaces.
- if you use Windows and your input contains lines created by pressing the enter button, they will also wrap
- If you enter a very long line without spaces, the panel expands and you need to resize the frame
- HTML formatting allows me to display different colors, as well as hyperlinks and emoticons.
What I need:
- Work with word wrap, as at the moment, if possible, but wrap letters ONLY in case of long lines, not separated by spaces, to prevent the panel from expanding.
- Manually added streams of lines made by pressing ENTER in the input area or if I copy pre-formatted text to the input panel
- HTML formatting as if I already
What I tried and what did not help:
jtextpane does not wrap text and JTextPane does not wrap text
Here is what code you can try yourself. In the lower left corner is the input area for entering some text. You can also add line wrappers by pressing the enter button. After clicking the button, you will see the text in the area above.
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"); } 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); } 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; } 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; } 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) { } }
UPDATE: base on some parts of http://java-sl.com/tip_java7_text_wrapping_bug_fix.html
Somehow I thought I needed to get a little closer to my goal. I tried to combine the hotfix for HTMLEditorKit with the StlyedEditorKit hotfix. But I have to be honest, I don’t know what I actually did there :( The sad thing is that the manual wraping line no longer works with this as a replacement for HTMLEditorKit. Perhaps you can use this as the basis for a better implementation.
To use it in my example, just create a new class in the project using CustomEditorKit and replace the HTMLEditorKit in the example with this CustomEditorKit. You will notice that word and letter processing works now, but if you press ENTER to get your own line, this change will no longer be displayed on the output panel, and everything will be displayed on one line. Another strange problem is that if you change the frame size, the lines will sometimes be on top of each other.
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);