由于JTextArea是一个二维的输入组件,因此[Enter]键在JTextArea中代表的意义只是单纯的换行字符而不再是一个事件驱动的 切入点。那么我们该 如何来处理JTextArea的事件呢?还记得我们在前面介绍过Listener的机制吗?相同的,我们一样需要使用 Listener的机制来处理发生在JTextArea中的事件,只是不再是以前提到的ActionListener了。在JTextArea中使用的Listener有两 种,一个是UndoableEditListener,另一个是DocumentListener.UndoableEditListener interface是负责纪录JTextArea中所有操作 发生的顺序并且可以运行还原上一步的功能。这个功能在目前的软件中应用相当广泛,如文书编辑软件Word中的复原功能、小画家 中的复原功能,相信大家都有使用过。DocumentListener interface则是纪录发生在JTextArea中所有的事件(如键入字符、删除 字符、剪下、贴上)并将所有的事件以树状的层次式结构组织起来;也就是说当JTextArea中的内容有任何变动时,会DocumentEvent ,此时必须使用DocumentListener接口中的方法来处理此事件。我们来看下面这个范例,使JTextArea具有复原的功能:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*由于会使用到复原和事件驱动功能,因此需要将javax.swing.undo和javax.swing.event两个package包含进来
*/
import javax.swing.undo.*;
import javax.swing.event.*;
/*JTextArea4类继承JFrame类并实作UndoableEditListener interface.实作UndoableEditListener interface就必须要编写其中的
*undoableEditHappened().
*/
public class JTextArea4 extends JFrame implements UndoableEditListener{
private UndoableEdit edit;
private JTextArea jta;
private JTextArea message;
private JMenuItem undoitem;
private JMenuItem redoitem;
public JTextArea4(){
super("JTextArea4");
jta = new JTextArea();
jta.getDocument().addUndoableEditListener(this);//将JTextArea加入UndoableEditListener.
message = new JTextArea();
message.setEditable(false);//利用setEditable()方法将另一个JTextArea设置为不可编辑.
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1,1));
p1.setBorder(BorderFactory.createTitledBorder("Edit Area"));
p1.add(new JScrollPane(jta));
//--begin:分别将两个JTextArea通过JPanel放到JFrame中。
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(1,1));
p2.setBorder(BorderFactory.createTitledBorder("Message"));
p2.add(new JScrollPane(message));
getContentPane().setLayout(new GridLayout(2,1));
getContentPane().add(p1);
getContentPane().add(p2);
//--end
//建立目录菜单并放置到JFrame中.
JMenuBar bar = new JMenuBar();
JMenu theMenu = new JMenu("Edit");
undoitem = new JMenuItem("Undo");
redoitem = new JMenuItem("Redo");
theMenu.add(undoitem);
theMenu.add(redoitem);
bar.add(theMenu);
updateMenuItem();//构造目录菜单
setJMenuBar(bar);
setSize(300,300);
//采用inner class方式,分别构造菜单选项被点选后的运行操作。分别调用undo(),redo()方法来完成.
undoitem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
edit.undo();
updateMenuItem();//运行undo功能
message.append("- Undo -\n");
}
});
redoitem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
edit.redo();
updateMenuItem();//运行redo功能
message.append("- Redo -\n");
}
});
}//end of JTextArea4()
public void undoableEditHappened(UndoableEditEvent ev){
StringBuffer buf = new StringBuffer(200);
/*当用户在Text Area中有所操作时,就可以用getEdit()方法取得UndoableEdit对象,此对象纪录着刚刚用户的操作,因
*此可由些对象的undo()或redo()达到取消或复原的功能.
*/
edit = ev.getEdit();
buf.append("undoableEdit:");
buf.append(edit.getPresentationName());
buf.append("\n");
message.append(buf.toString());
updateMenuItem();
}//end of undoableEditHappened()
//判断是否此时是否可以运行undo或redo的功能,并且改变目录菜单的状态值.
public void updateMenuItem(){
if (edit != null){
undoitem.setEnabled(edit.canUndo());
redoitem.setEnabled(edit.canRedo());
undoitem.setText(edit.getUndoPresentationName());
redoitem.setText(edit.getRedoPresentationName());
}else{
undoitem.setEnabled(false);
redoitem.setEnabled(false);
undoitem.setText("Undo");
redoitem.setText("Redo");
}
}//end of updateMenu()
public static void main(String args[]) {
JFrame f = new JTextArea4();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.show();
}//end of main()
}//end of class JTextArea4
我们在前面提到Enter键在JTextArea中不再是事件驱动的切入点,因此我们要利用Listener的机制来控制JTextArea的事件驱动 。但是,我们要怎么样知道在JTextArea中的数据内容呢?这就要了解JTextArea的存储模式了,JTextArea把输入区内的每一行当成 一个独立的单无(Element),并依照Document内规划的树状结构来存储,也就是说在JTextArea的第一行属于Element 0、第二行属于 Element 1、第三行属于Element 2等等。不论我们在费心的去处理。接下来我们来看看,Element和DocumentListener interface的 用法。我们改写JTextArea4.java加入DocumentListener,将程序存储为JTextArea5.java.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.undo.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class JTextArea5 extends JFrame implements UndoableEditListener,
DocumentListener {
private UndoableEdit edit;
private JTextArea jta;
private JTextArea message;
private JMenuItem undoitem;
private JMenuItem redoitem;
public JTextArea5() {
super("JTextArea");
jta = new JTextArea();
jta.getDocument().addUndoableEditListener(this);
jta.getDocument().addDocumentListener(this);
message = new JTextArea();
message.setEditable(false);
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1, 1));
p1.setBorder(BorderFactory.createTitledBorder("Edit Area"));
p1.add(new JScrollPane(jta));
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(1, 1));
p2.setBorder(BorderFactory.createTitledBorder("Message"));
p2.add(new JScrollPane(message));
getContentPane().setLayout(new GridLayout(2, 1));
getContentPane().add(p1);
getContentPane().add(p2);
JMenuBar bar = new JMenuBar();
JMenu theMenu = new JMenu("Edit");
undoitem = new JMenuItem("Undo");
redoitem = new JMenuItem("Redo");
theMenu.add(undoitem);
theMenu.add(redoitem);
bar.add(theMenu);
updateMenuItem();
setJMenuBar(bar);
setSize(300, 300);
undoitem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
edit.undo();
updateMenuItem();
message.append("- Undo -\n");
}
});
redoitem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
edit.redo();
updateMenuItem();
message.append("- Redo -\n");
}
});
} // end of JTextArea5
public void undoableEditHappened(UndoableEditEvent ev) {
StringBuffer buf = new StringBuffer(200);
edit = ev.getEdit();
buf.append("undoableEdit:");
buf.append(edit.getPresentationName());
buf.append("\n");
message.append(buf.toString());
updateMenuItem();
}// end of undoableEditHappened()
public void updateMenuItem() {
if (edit != null) {
undoitem.setEnabled(edit.canUndo());
redoitem.setEnabled(edit.canRedo());
undoitem.setText(edit.getUndoPresentationName());
redoitem.setText(edit.getRedoPresentationName());
} else {
undoitem.setEnabled(false);
redoitem.setEnabled(false);
undoitem.setText("Undo");
redoitem.setText("Redo");
}
}// end of updateMenu()
public void showDE(DocumentEvent de) {
StringBuffer debuf = new StringBuffer(100);
debuf.append(de.getType());
debuf.append("Offset:");
debuf.append(de.getOffset());
debuf.append("Length:");
debuf.append(de.getLength());
Element Eroot = jta.getDocument().getDefaultRootElement();
DocumentEvent.ElementChange Echange = de.getChange(Eroot);
if (Echange == null) {
debuf.append("(No Element Change)");
} else {
debuf.append("Element Change:index");
debuf.append("Echange.getIndex()");
}
debuf.append("\n");
message.append(debuf.toString());
}
public void changedUpdate(DocumentEvent de) {
showDE(de);
}
public void insertUpdate(DocumentEvent de) {
showDE(de);
}
public void removeUpdate(DocumentEvent de) {
showDE(de);
}
public static void main(String[] args) {
JFrame f = new JTextArea5();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.show();
}
}