gpt4 book ai didi

java - Java 7 中的 JEditorPane 换行

转载 作者:搜寻专家 更新时间:2023-11-01 01:53:40 25 4
gpt4 key购买 nike

首先我希望这不是我开始新话题的问题。老实说,我不知道如何根据已经回答的问题提出问题,所以我做了这个。

我是 Java 的新手,我的问题如下。我正在编写一个小聊天程序,我正在使用带有 HTMLEditorKitJEditorPane 来显示不同颜色的文本、显示笑脸和显示超链接。

我的问题是,经过一些研究我发现问题可能是由于 Java7,我无法让换行正常工作。我希望文本自动换行并在超过组件宽度的字符串中间换行。自动换行效果很好,但是如果有人输入很长的字符串,JEditorPane 会展开,您需要调整框架的大小才能在屏幕上显示所有内容,这是我不希望发生的事情。

我已经尝试了一些解决这个问题的方法,但它们只允许字母换行,这样自动换行就不再有效了。除此之外,我希望用户能够通过按 Enter 来换行他的文本。为此,我在文本中添加了\n 并进行了修复,这将不再影响结果,所有内容都将显示在一行中。

我觉得我已经花了数年时间在网络上寻找解决方案,但现在对我的情况毫无用处,尤其是因为它似乎一直都是相同的解决方案。我希望你们能帮助我。

这意味着总结:

我有什么:

  • 如果长字符串由空格分隔,则换行
  • 如果您使用 Windows 并且您的输入包含通过按回车创建的换行,它们也会换行
  • 如果您输入一个很长的不带空格的字符串,面板会展开,您需要调整框架的大小
  • HTML 格式允许我显示不同的颜色以及超链接和表情符号

我需要什么:

  • 像现在这样的自动换行行为,以防万一,但字母换行仅适用于长字符串未用空格分隔的情况,以防止面板展开。
  • 通过在输入区域中按 ENTER 手动添加换行,或者如果我将预先格式化的文本复制到输入面板中
  • HTML 格式化,就像我已经做的那样

我尝试过的和没有帮助的:

jtextpane doesn't wrap textJTextPane is not wrapping text

这里有一些代码可以自己尝试。左下角是一个输入区域,用于输入一些文本。您还可以通过按回车键添加换行。单击按钮后,您将在上方区域看到文本。

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

最佳答案

好的!所以,我终于得到了你在工作中遇到的一切问题。它需要一些研究和大量的试验和错误,但这里是:

这是我做的:

  • 将 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) {
}

}

以下是我用来解决这个问题的(大部分)链接:

Enabling word wrap in a JTextPane with HTMLDocument

自定义包装是这两者的组合:

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

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

删除 JTextArea 的键绑定(bind):

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

如果您有任何问题,请在下方发表评论。我会回答他们。我真诚地希望这能解决您的问题

关于java - Java 7 中的 JEditorPane 换行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17533451/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com