如何删除最后一个 line/component/icon/widget/etc。来自 JTextPane
How to remove the last line/component/icon/widget/etc. from JTextPane
我有一个庞大的 Java 项目,它使用 UI 这样的控制台。对于控制台,我使用 JTextPane。最近我需要一些方法来分别删除第一行和最后一行。我删除第一行的方法非常简单,如下
public void removeFirstLine() {
try {
Element root = outputArea.getDocument().getDefaultRootElement();
Element first = root.getElement(0);
outputArea.getDocument().remove(first.getStartOffset(), first.getEndOffset());
outputArea.setCaretPosition(outputArea.getDocument().getLength());
} catch (BadLocationException e) {
ErrorHandler.handle(e);
}
}
但是,当我尝试删除最后一行(NOT OF TEXT I REPEAT NOT OF TEXT)时,我的问题就来了。此行可以是可附加到 JTextPane 的任何内容,例如自定义组件、文本字符串、图标等。如果有人知道如何删除附加到 JTextPane 的最后一个“东西”,我将永远感激您。
编辑:添加最小的可重现示例:
import javax.swing.*;
import javax.swing.text.*;
public class Test {
public static void main(String[] args) {
new Test();
}
private static final String ELEM = AbstractDocument.ElementNameAttribute;
private static final String ICON = StyleConstants.IconElementName;
private static final String COMP = StyleConstants.ComponentElementName;
private JTextPane outputArea;
Test() {
try {
//init pane
outputArea = new JTextPane();
//insert component
JTextField c = new JTextField(20);
Style cs = outputArea.getStyledDocument().addStyle("name", null);
StyleConstants.setComponent(cs, c);
outputArea.getStyledDocument().insertString(outputArea.getStyledDocument().getLength(), "string", cs);
//new line
println("");
//add string
println("this is a string added to the pane");
//add image
outputArea.insertIcon(new ImageIcon("/path/to/image.png"));
//new line
println("");
//before
printContents();
//----------------------------
//call removeLastLine() as many times as needed and it should remove the last added "thing"
//regardless of the order added (ex: component, text, icon should function the same as text, text, text, component obviously)
//changes should be reflected here
printContents();
} catch (Exception e) {
e.printStackTrace();
}
}
public void removeLastLine() {
//TODO remove last line of text, last component, last image icon, etc.
}
public void println(String Usage) {
try {
StyledDocument document = (StyledDocument) outputArea.getDocument();
document.insertString(document.getLength(), Usage + "\n", null);
outputArea.setCaretPosition(outputArea.getDocument().getLength());
}
catch (Exception e) {
e.printStackTrace();
}
}
public void printContents() {
try {
ElementIterator iterator = new ElementIterator(outputArea.getStyledDocument());
Element element;
while ((element = iterator.next()) != null) {
System.out.println(element);
AttributeSet as = element.getAttributes();
if (as.containsAttribute(ELEM, ICON)) {
System.out.println(StyleConstants.getIcon(as).getClass());
}
else if (as.containsAttribute(ELEM, COMP)) {
System.out.println(StyleConstants.getComponent(as).getClass());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
以下是我以前使用的代码,用于删除文本:
public void removeLastLine() {
// We use start minus 1 to make sure we remove the newline
// character of the previous line
Element root = outputArea.getDocument().getDefaultRootElement();
Element line = root.getElement(root.getElementCount() - 1);
int start = line.getStartOffset();
int end = line.getEndOffset();
try
{
outputArea.getDocument().remove(start - 1, end - start);
}
catch(BadLocationException ble)
{
System.out.println(ble);
}
}
似乎也适用于其他对象,因为“之后”的输出与“之前”的输出不同。
我会让你验证文本窗格是否按预期更新。
中获取了代码
编辑:
上面的代码在尝试删除第一行时不起作用,因为起始偏移量将为负数。
以下是也处理删除第一行的更新版本:
import java.awt.*;
import javax.swing.*;
import javax.swing.*;
import javax.swing.text.*;
public class Test {
public static void main(String[] args) {
new Test();
}
private static final String ELEM = AbstractDocument.ElementNameAttribute;
private static final String ICON = StyleConstants.IconElementName;
private static final String COMP = StyleConstants.ComponentElementName;
private JTextPane outputArea;
Test() {
try {
//init pane
outputArea = new JTextPane();
JButton button = new JButton("Remove Last Line");
button.addActionListener((e) -> removeLastLine());
JFrame frame = new JFrame();
frame.add( new JScrollPane(outputArea) );
frame.add( button, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
println("first line");
//insert component
JTextField c = new JTextField(20);
Style cs = outputArea.getStyledDocument().addStyle("name", null);
StyleConstants.setComponent(cs, c);
outputArea.getStyledDocument().insertString(outputArea.getStyledDocument().getLength(), "string", cs);
//new line
println("");
//add string
println("this is a string added to the pane");
//add image
outputArea.insertIcon(new ImageIcon("about16.gif"));
//new line
println("\nsecond last line");
} catch (Exception e) {
e.printStackTrace();
}
}
public void removeLastLine()
{
// We use start minus 1 to make sure we remove the newline
// character of the previous line
Element root = outputArea.getDocument().getDefaultRootElement();
Element line = root.getElement(root.getElementCount() - 1);
int start = line.getStartOffset();
int end = line.getEndOffset();
try
{
int offset = start - 1;
int length = end - start;
// removing the first line
if (offset < 0)
{
offset = 0;
length -= 1;
}
outputArea.getDocument().remove(offset, length);
}
catch(BadLocationException ble)
{
System.out.println(ble);
}
}
public void println(String Usage) {
try {
StyledDocument document = (StyledDocument) outputArea.getDocument();
document.insertString(document.getLength(), Usage + "\n", null);
outputArea.setCaretPosition(outputArea.getDocument().getLength());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
我用整个下午写的以下代码解决了这个问题。
/**
* Removes the last "thing" addeed to the JTextPane whether it's a component,
* icon, or string of multi-llined text.
*
* In more detail, this method figures out what it'll be removing and then determines how many calls
* are needed to {@link StringUtil#removeLastLine()}
*/
public void removeLast() {
boolean removeTwoLines = false;
LinkedList<Element> elements = new LinkedList<>();
ElementIterator iterator = new ElementIterator(outputArea.getStyledDocument());
Element element;
while ((element = iterator.next()) != null) {
elements.add(element);
}
int leafs = 0;
for (Element value : elements)
if (value.getElementCount() == 0)
leafs++;
int passedLeafs = 0;
for (Element value : elements) {
if (value.getElementCount() == 0) {
if (passedLeafs + 3 != leafs) {
passedLeafs++;
continue;
}
if (value.toString().toLowerCase().contains("icon") || value.toString().toLowerCase().contains("component")) {
removeTwoLines = true;
}
}
}
if (removeTwoLines) {
removeLastLine();
}
removeLastLine();
}
/**
* Removes the last line added to the linked JTextPane. This could appear to remove nothing,
* but really be removing just a newline (line break) character.
*/
public void removeLastLine() {
try {
LinkedList<Element> elements = new LinkedList<>();
ElementIterator iterator = new ElementIterator(outputArea.getStyledDocument());
Element element;
while ((element = iterator.next()) != null) {
elements.add(element);
}
int leafs = 0;
for (Element value : elements)
if (value.getElementCount() == 0)
leafs++;
int passedLeafs = 0;
for (Element value : elements) {
if (value.getElementCount() == 0) {
if (passedLeafs + 2 != leafs) {
passedLeafs++;
continue;
}
outputArea.getStyledDocument().remove(value.getStartOffset(),
value.getEndOffset() - value.getStartOffset());
}
}
} catch (BadLocationException ignored) {}
catch (Exception e) {
e.printStackTrace();
}
}
完整代码可以在下面查看:https://github.com/NathanCheshire/Cyder/blob/master/src/cyder/utilities/StringUtil.java
我有一个庞大的 Java 项目,它使用 UI 这样的控制台。对于控制台,我使用 JTextPane。最近我需要一些方法来分别删除第一行和最后一行。我删除第一行的方法非常简单,如下
public void removeFirstLine() {
try {
Element root = outputArea.getDocument().getDefaultRootElement();
Element first = root.getElement(0);
outputArea.getDocument().remove(first.getStartOffset(), first.getEndOffset());
outputArea.setCaretPosition(outputArea.getDocument().getLength());
} catch (BadLocationException e) {
ErrorHandler.handle(e);
}
}
但是,当我尝试删除最后一行(NOT OF TEXT I REPEAT NOT OF TEXT)时,我的问题就来了。此行可以是可附加到 JTextPane 的任何内容,例如自定义组件、文本字符串、图标等。如果有人知道如何删除附加到 JTextPane 的最后一个“东西”,我将永远感激您。
编辑:添加最小的可重现示例:
import javax.swing.*;
import javax.swing.text.*;
public class Test {
public static void main(String[] args) {
new Test();
}
private static final String ELEM = AbstractDocument.ElementNameAttribute;
private static final String ICON = StyleConstants.IconElementName;
private static final String COMP = StyleConstants.ComponentElementName;
private JTextPane outputArea;
Test() {
try {
//init pane
outputArea = new JTextPane();
//insert component
JTextField c = new JTextField(20);
Style cs = outputArea.getStyledDocument().addStyle("name", null);
StyleConstants.setComponent(cs, c);
outputArea.getStyledDocument().insertString(outputArea.getStyledDocument().getLength(), "string", cs);
//new line
println("");
//add string
println("this is a string added to the pane");
//add image
outputArea.insertIcon(new ImageIcon("/path/to/image.png"));
//new line
println("");
//before
printContents();
//----------------------------
//call removeLastLine() as many times as needed and it should remove the last added "thing"
//regardless of the order added (ex: component, text, icon should function the same as text, text, text, component obviously)
//changes should be reflected here
printContents();
} catch (Exception e) {
e.printStackTrace();
}
}
public void removeLastLine() {
//TODO remove last line of text, last component, last image icon, etc.
}
public void println(String Usage) {
try {
StyledDocument document = (StyledDocument) outputArea.getDocument();
document.insertString(document.getLength(), Usage + "\n", null);
outputArea.setCaretPosition(outputArea.getDocument().getLength());
}
catch (Exception e) {
e.printStackTrace();
}
}
public void printContents() {
try {
ElementIterator iterator = new ElementIterator(outputArea.getStyledDocument());
Element element;
while ((element = iterator.next()) != null) {
System.out.println(element);
AttributeSet as = element.getAttributes();
if (as.containsAttribute(ELEM, ICON)) {
System.out.println(StyleConstants.getIcon(as).getClass());
}
else if (as.containsAttribute(ELEM, COMP)) {
System.out.println(StyleConstants.getComponent(as).getClass());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
以下是我以前使用的代码,用于删除文本:
public void removeLastLine() {
// We use start minus 1 to make sure we remove the newline
// character of the previous line
Element root = outputArea.getDocument().getDefaultRootElement();
Element line = root.getElement(root.getElementCount() - 1);
int start = line.getStartOffset();
int end = line.getEndOffset();
try
{
outputArea.getDocument().remove(start - 1, end - start);
}
catch(BadLocationException ble)
{
System.out.println(ble);
}
}
似乎也适用于其他对象,因为“之后”的输出与“之前”的输出不同。
我会让你验证文本窗格是否按预期更新。
中获取了代码编辑:
上面的代码在尝试删除第一行时不起作用,因为起始偏移量将为负数。
以下是也处理删除第一行的更新版本:
import java.awt.*;
import javax.swing.*;
import javax.swing.*;
import javax.swing.text.*;
public class Test {
public static void main(String[] args) {
new Test();
}
private static final String ELEM = AbstractDocument.ElementNameAttribute;
private static final String ICON = StyleConstants.IconElementName;
private static final String COMP = StyleConstants.ComponentElementName;
private JTextPane outputArea;
Test() {
try {
//init pane
outputArea = new JTextPane();
JButton button = new JButton("Remove Last Line");
button.addActionListener((e) -> removeLastLine());
JFrame frame = new JFrame();
frame.add( new JScrollPane(outputArea) );
frame.add( button, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
println("first line");
//insert component
JTextField c = new JTextField(20);
Style cs = outputArea.getStyledDocument().addStyle("name", null);
StyleConstants.setComponent(cs, c);
outputArea.getStyledDocument().insertString(outputArea.getStyledDocument().getLength(), "string", cs);
//new line
println("");
//add string
println("this is a string added to the pane");
//add image
outputArea.insertIcon(new ImageIcon("about16.gif"));
//new line
println("\nsecond last line");
} catch (Exception e) {
e.printStackTrace();
}
}
public void removeLastLine()
{
// We use start minus 1 to make sure we remove the newline
// character of the previous line
Element root = outputArea.getDocument().getDefaultRootElement();
Element line = root.getElement(root.getElementCount() - 1);
int start = line.getStartOffset();
int end = line.getEndOffset();
try
{
int offset = start - 1;
int length = end - start;
// removing the first line
if (offset < 0)
{
offset = 0;
length -= 1;
}
outputArea.getDocument().remove(offset, length);
}
catch(BadLocationException ble)
{
System.out.println(ble);
}
}
public void println(String Usage) {
try {
StyledDocument document = (StyledDocument) outputArea.getDocument();
document.insertString(document.getLength(), Usage + "\n", null);
outputArea.setCaretPosition(outputArea.getDocument().getLength());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
我用整个下午写的以下代码解决了这个问题。
/**
* Removes the last "thing" addeed to the JTextPane whether it's a component,
* icon, or string of multi-llined text.
*
* In more detail, this method figures out what it'll be removing and then determines how many calls
* are needed to {@link StringUtil#removeLastLine()}
*/
public void removeLast() {
boolean removeTwoLines = false;
LinkedList<Element> elements = new LinkedList<>();
ElementIterator iterator = new ElementIterator(outputArea.getStyledDocument());
Element element;
while ((element = iterator.next()) != null) {
elements.add(element);
}
int leafs = 0;
for (Element value : elements)
if (value.getElementCount() == 0)
leafs++;
int passedLeafs = 0;
for (Element value : elements) {
if (value.getElementCount() == 0) {
if (passedLeafs + 3 != leafs) {
passedLeafs++;
continue;
}
if (value.toString().toLowerCase().contains("icon") || value.toString().toLowerCase().contains("component")) {
removeTwoLines = true;
}
}
}
if (removeTwoLines) {
removeLastLine();
}
removeLastLine();
}
/**
* Removes the last line added to the linked JTextPane. This could appear to remove nothing,
* but really be removing just a newline (line break) character.
*/
public void removeLastLine() {
try {
LinkedList<Element> elements = new LinkedList<>();
ElementIterator iterator = new ElementIterator(outputArea.getStyledDocument());
Element element;
while ((element = iterator.next()) != null) {
elements.add(element);
}
int leafs = 0;
for (Element value : elements)
if (value.getElementCount() == 0)
leafs++;
int passedLeafs = 0;
for (Element value : elements) {
if (value.getElementCount() == 0) {
if (passedLeafs + 2 != leafs) {
passedLeafs++;
continue;
}
outputArea.getStyledDocument().remove(value.getStartOffset(),
value.getEndOffset() - value.getStartOffset());
}
}
} catch (BadLocationException ignored) {}
catch (Exception e) {
e.printStackTrace();
}
}
完整代码可以在下面查看:https://github.com/NathanCheshire/Cyder/blob/master/src/cyder/utilities/StringUtil.java