我正在创建一个用 Java 编写的文本编辑器,我决定使用 JTextPane 而不是 JTextArea,因为它使我能够使用不同的配色方案创建富文本编辑。但是 JTextPane 没有 setTabSize(int size) 函数,但我可以使用 TabStops 和 TabSet 来实现这一点。
我的第一次尝试
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;
public class Editor extends JFrame {
JTextPane txt;
public Editor() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RichTextEdit rte = new RichTextEdit();
txt = new JTextPane(rte);
txt.setPreferredSize(new Dimension(400,200));
add(new JScrollPane(txt));
Font f = new Font("Monospaced", Font.PLAIN, txt.getFont().getSize());
txt.setFont(f);
FontMetrics fm = txt.getFontMetrics(f);
int width = fm.stringWidth("w");
int tabSize = 4;
TabStop[] tabs = new TabStop[1];
tabs[0] = new TabStop(width*tabSize, TabStop.ALIGN_LEFT, TabStop.LEAD_NONE);
TabSet tabset = new TabSet(tabs);
StyleContext cont = StyleContext.getDefaultStyleContext();
AttributeSet a = cont.addAttribute(SimpleAttributeSet.EMPTY,
StyleConstants.TabSet, tabset);
txt.setParagraphAttributes(a, false);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
此尝试仅在光标位于文档开头时有效。如果我开始在 JTextPane 中输入内容然后按 Tab,它只会向上移动到第 4 位。所以,如果我输入两个字母,插入符号只会在制表符上移动两个字符。之后,每次按下它只会移动一个字符。
我的第二次尝试:我所做的只是添加另一个选项卡,如果我在一行上按两次选项卡,只要该行上没有其他字符,它就会起作用。基本上与我的第一次尝试相同,除了它允许按下两个标签(等于 8 个字符长)
TabStop[] tabs = new TabStop[2];
tabs[0] = new TabStop(width * tabSize, TabStop.ALIGN_LEFT, TabStop.LEAD_NONE);
tabs[1] = new TabStop(width * tabSize * 2, TabStop.ALIGN_LEFT, TabStop.LEAD_NONE);
我必须将第二个制表符乘以 2 才能使制表符空间移动另外 4 个字符。
我的最后一次尝试是能够获取给定行上的字符数量。(我已经完成了)然后在该行中添加 4 个字符。因此,如果用户在 JTextPane 中键入:123456 并按下选项卡,它只会在末尾添加 4 个空格,但是在初始设置后尝试 setParagraphAttributes 时我一直收到错误消息。所以我的想法是它已经有了 AttributeSet,然后要么更改值或删除 AttributeSet,然后使用更新的 TabSize 添加它。这是我到目前为止所拥有的:
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.util.Enumeration;
import javax.swing.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;
import javax.swing.text.Utilities;
public class Editor extends JFrame {
JTextPane txt;
public Editor() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RichTextEdit rte = new RichTextEdit();
txt = new JTextPane(rte);
txt.setPreferredSize(new Dimension(400,200));
add(new JScrollPane(txt));
txt.setFont(new Font("Monospaced", Font.PLAIN, 16));
txt.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent arg0) {
// TODO Auto-generated method stub
Update();
}
});
Update();
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void Update() {
int caretPosition = txt.getCaretPosition();
Element root = txt.getDocument().getDefaultRootElement();
int n = root.getElementIndex(caretPosition) + 1;
Element child = root.getElement(n-1);
int start = child.getStartOffset();
int end = child.getEndOffset();
int length = end - start;
int j = (length >0) ? length - 1 : 0;
System.out.println(n);
System.out.println(caretPosition);
System.out.println(j);
System.out.println("----------");
Font f = new Font("Monospaced", Font.PLAIN, txt.getFont().getSize());
FontMetrics fm = txt.getFontMetrics(f);
int width = fm.stringWidth("w");
int tabSize = (j > 0) ? j + 4 : 4;
TabStop[] tabs = new TabStop[1];
tabs[0] = new TabStop(width * tabSize, TabStop.ALIGN_LEFT, TabStop.LEAD_NONE);
TabSet tabset = new TabSet(tabs);
StyleContext cont = StyleContext.getDefaultStyleContext();
AttributeSet a = cont.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.TabSet, tabset);
txt.setParagraphAttributes(a, true);
}
}
txt.setParagraphAttributes(a,true);
当我从 caretListener 调用更新函数时,我在这一行收到 IllegalStateException