分类: Java
2008-04-17 15:49:09
第21章 文本基础
Swing文本组件是相对比较简单的组件。它建立在由javax.swing.text包的类和接口提供的一个复杂的下层构件之上。本书将分三章来介绍Swing文本。本章主要讨论所有文本组件从JTextComponent类继承的基本功能。在第22章的“文本组件”中将讨论这些文本组件。在第23章的“定制文本组件”中将讨论Swing文本的更高级的主题,如视图、元素、属性集和风格。
21.1 Swing文本组件
21.2 动作
21.2.1 文本动作
例21-1 使用文本组件动作
public class Test extends JFrame {
private JTextArea textArea = createTextArea();
private Action[] actions = textArea.getActions();
private JList actionList = createActionList(actions);
private JSplitPane splitPane = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
new JScrollPane(textArea),
new JScrollPane(actionList));
public Test() {
Container contentPane = getContentPane();
splitPane.setDividerLocation(150);
contentPane.add(splitPane, BorderLayout.CENTER);
contentPane.add(GJApp.getStatusArea(),
BorderLayout.SOUTH);
}
private JList createActionList(Action[] actions) {
DefaultListModel model = new DefaultListModel();
final JList list = new JList(model);
list.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
for(int i=0; i < actions.length; ++i) {
model.addElement(actions[i]);
}
list.setCellRenderer(new DefaultListCellRenderer() {
public Component getListCellRendererComponent(
JList list, Object value,
int index, boolean isSelected,
boolean cellHasFocus) {
super.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
Action action = (Action)value;
setText((String)action.getValue(Action.NAME));
return this;
}
});
list.addListSelectionListener(new ListSelectionListener(){
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()) {
Action source =
(Action)actionList.getSelectedValue();
textArea.requestFocus();
source.actionPerformed(null);
GJApp.showStatus("Action: " +
(String)source.getValue(Action.NAME));
}
}
});
return list;
}
private JTextArea createTextArea() {
JTextArea textArea = new JTextArea(
"line one\nline two\nline three\nline four");
textArea.setFont(new Font("Dialog", Font.ITALIC, 24));
textArea.getCaret().setBlinkRate(0);
return textArea;
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Text Component Actions",300,300,450,300);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
21.2.2 动作和编辑工作包
例21-2 用缺省编辑工具包访问动作
public class Test extends JApplet {
private JTextArea textArea = new JTextArea("some content");
private Hashtable actionTable = new Hashtable();
public Test() {
Container contentPane = getContentPane();
textArea.setFont(new Font("Dialog", Font.PLAIN, 24));
loadActionTable();
setJMenuBar(createMenu());
contentPane.add(textArea, BorderLayout.CENTER);
}
private void loadActionTable() {
Action[] actions = textArea.getActions();
for(int i=0; i < actions.length; ++i) {
actionTable.put(actions[i].getValue(Action.NAME),
actions[i]);
}
}
private Action getAction(String name) {
return (Action)actionTable.get(name);
}
private JMenuBar createMenu() {
JMenuBar menuBar = new JMenuBar();
JMenu editMenu = new JMenu("Edit");
editMenu.add(getAction(DefaultEditorKit.cutAction));
editMenu.add(getAction(DefaultEditorKit.copyAction));
editMenu.add(getAction(DefaultEditorKit.pasteAction));
menuBar.add(editMenu);
return menuBar;
}
}
21.3 键映射
例21-3 设置键映射
public class Test extends JApplet {
private JTextArea textArea = new JTextArea("initial content");
private JCheckBox cbox = new JCheckBox("keymap added");
private Hashtable actionTable = new Hashtable();
private Keymap originalKeymap, newKeymap;
public void init() {
Container contentPane = getContentPane();
loadActionTable();
originalKeymap = textArea.getKeymap();
newKeymap = createKeymap();
textArea.setFont(new Font("Dialog", Font.PLAIN, 24));
contentPane.add(new ControlPanel(), BorderLayout.NORTH);
contentPane.add(textArea, BorderLayout.CENTER);
}
private Keymap createKeymap() {
Keymap map = JTextComponent.addKeymap("applet keymap",
textArea.getKeymap());
KeyStroke forwardKeyStroke =
KeyStroke.getKeyStroke(KeyEvent.VK_F,
InputEvent.ALT_MASK),
backwardKeyStroke =
KeyStroke.getKeyStroke(KeyEvent.VK_B,
InputEvent.ALT_MASK);
Action forwardAction =
getAction(DefaultEditorKit.forwardAction),
backwardAction =
getAction(DefaultEditorKit.backwardAction);
map.addActionForKeyStroke(forwardKeyStroke,
forwardAction);
map.addActionForKeyStroke(backwardKeyStroke,
backwardAction);
return map;
}
private void loadActionTable() {
Action[] actions = textArea.getActions();
for(int i=0; i < actions.length; ++i) {
actionTable.put(actions[i].getValue(Action.NAME),
actions[i]);
}
}
private Action getAction(String name) {
return (Action)actionTable.get(name);
}
class ControlPanel extends JPanel {
public ControlPanel() {
add(cbox);
cbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.setKeymap(cbox.isSelected() ?
newKeymap :
originalKeymap);
textArea.requestFocus();
}
});
}
}
}
21.4 文档
21.4.1 定制文档
例21-4 只可以输入整数的文档
public class Test extends JApplet {
JTextField tf = new JTextField(3);
public Test() {
Container contentPane = getContentPane();
JLabel label = new JLabel("Enter an Integer:");
tf.setDocument(new IntegerDocument());
contentPane.setLayout(new FlowLayout());
contentPane.add(label);
contentPane.add(tf);
}
}
class IntegerDocument extends PlainDocument {
public void insertString(int offset, String s,
AttributeSet attributeSet)
throws BadLocationException {
try {
Integer.parseInt(s);
}
catch(Exception ex) { // only allow integer values
Toolkit.getDefaultToolkit().beep();
return;
}
super.insertString(offset, s, attributeSet);
}
}
21.4.2 文档监听器
例21-5 使用文档监听器
public class Test extends JFrame {
private JTextArea textArea = new JTextArea();
private Document document = textArea.getDocument();
private DefaultEditorKit kit = new DefaultEditorKit();
private Action saveAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
String s = JOptionPane.showInputDialog(
Test.this,
"Enter Filename:");
if(s != null) {
try {
kit.write(new FileWriter(s),
document, 0,
document.getLength());
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}
};
public Test() {
Container contentPane = getContentPane();
try {
kit.read(new FileReader("Test.java"), document, 0);
}
catch(Exception ex) {
ex.printStackTrace();
}
final JTextArea status = new JTextArea();
JPanel p = new JPanel();
JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
p, status);
sp.setDividerLocation(200);
saveAction.putValue(Action.NAME, "Save ...");
saveAction.setEnabled(false);
p.setLayout(new BorderLayout());
p.add(new JScrollPane(textArea), BorderLayout.CENTER);
contentPane.add(sp, BorderLayout.CENTER);
textArea.getDocument().addDocumentListener(
new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
saveAction.setEnabled(true);
updateStatus(e);
}
public void removeUpdate(DocumentEvent e) {
saveAction.setEnabled(true);
updateStatus(e);
}
public void changedUpdate(DocumentEvent e) {
saveAction.setEnabled(true);
updateStatus(e);
}
private void updateStatus(DocumentEvent e) {
status.append(e.getType().toString());
status.append(" Offset: " + e.getOffset());
status.append(" Length: " + e.getLength() + "\n");
}
});
setJMenuBar(createMenuBar());
}
private JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu editMenu = new JMenu("Edit");
editMenu.add(new DefaultEditorKit.CutAction());
editMenu.add(new DefaultEditorKit.CopyAction());
editMenu.add(new DefaultEditorKit.PasteAction());
editMenu.addSeparator();
editMenu.add(saveAction);
menuBar.add(editMenu);
return menuBar;
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Using Document Listeners",
300,300,650,500);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
21.5 加字符与加重器
21.5.1 加字符
21.5.2 加字符监听器
例21-6 实现一个加字符监听器
public class Test extends JApplet {
public Test() {
Container contentPane = getContentPane();
JTextArea textArea = new JTextArea();
contentPane.add(textArea, BorderLayout.CENTER);
textArea.setFont(new Font("Dialog", Font.PLAIN, 24));
textArea.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
showStatus("Mark: " + e.getMark() +
" / Dot: " + e.getDot());
}
});
}
}
21.5.3 定制加字符
例21-7 实现一个定制加字符
public class Test extends JApplet {
public Test() {
Container contentPane = getContentPane();
JTextArea textArea = new JTextArea();
textArea.setCaret(new TriangleCaret(8));
textArea.setFont(new Font("Dialog", Font.ITALIC, 24));
contentPane.add(textArea, BorderLayout.CENTER);
}
}
class TriangleCaret extends DefaultCaret {
private int triangleWidth, left, right, top, bottom, middle;
public TriangleCaret(int triangleWidth) {
this.triangleWidth = triangleWidth;
}
public void paint(Graphics g) {
if(isVisible()) {
try {
JTextComponent comp = getComponent();
Rectangle r = comp.modelToView(getDot());
setLocations(r);
g.setColor(comp.getCaretColor());
g.drawLine(left, bottom, middle, top);
g.drawLine(middle, top, right, bottom);
g.drawLine(right, bottom, left, bottom);
}
catch(BadLocationException ex) {
ex.printStackTrace();
}
}
}
protected synchronized void damage(Rectangle r) {
if(r != null) {
setLocations(r);
x = left;
y = top;
width = right - left + 1;
height = bottom - top + 1;
}
}
private void setLocations(Rectangle r) {
left = r.x - triangleWidth/2;
right = r.x + triangleWidth/2;
bottom = r.y + r.height - 1;
top = bottom - triangleWidth;
middle = r.x;
repaint();
}
}
21.5.4 加重器
例21-8 一个定制的加重器
public class Test extends JApplet {
public Test() {
Container contentPane = getContentPane();
JTextArea textArea = new JTextArea(
"File choosers, like option panes, are lightweight\n" +
"components that\n" +
"are meant to be placed ...");
textArea.setCaret(new BoxHighlightingCaret());
textArea.setFont(new Font("Dialog", Font.ITALIC, 24));
contentPane.add(new JScrollPane(textArea),
BorderLayout.CENTER);
}
}
class BoxHighlightingCaret extends DefaultCaret {
private static BoxHighlighterPainter painter =
new BoxHighlighterPainter(null);
public Highlighter.HighlightPainter getSelectionPainter(){
return painter;
}
static class BoxHighlighterPainter
extends DefaultHighlighter.DefaultHighlightPainter {
private Color color;
public BoxHighlighterPainter(Color color) {
super(color);
this.color = color;
}
public Shape paintLayer(Graphics g, int p0, int p1,
Shape shape, JTextComponent comp,
View view) {
Rectangle b = shape.getBounds();
try {
g.setColor(getColor(comp));
Rectangle r1 = comp.modelToView(p0);
Rectangle r2 = comp.modelToView(p1);
g.drawRect(r1.x, r1.y, // x,y
r2.x - r1.x - 1, // width
r1.height - 1); // height
}
catch(BadLocationException ex) {
ex.printStackTrace();
}
return b;
}
private Color getColor(JTextComponent comp) {
return color != null ? color :
comp.getSelectionColor();
}
}
}
21.6 撤销/恢复
例21-9 一个撤消和恢复的实现
public class Test extends JApplet {
private JTextArea textArea = new JTextArea("some content");
private Document document = textArea.getDocument();
private UndoManager undoManager = new UndoManager();
private UndoLastAction undoAction = new UndoLastAction();
private RedoAction redoAction = new RedoAction();
public Test() {
Container contentPane = getContentPane();
createMenu();
contentPane.add(textArea, BorderLayout.CENTER);
textArea.setFont(new Font("Dialog", Font.PLAIN, 24));
document.addUndoableEditListener(
new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent e){
undoManager.addEdit(e.getEdit());
undoAction.update();
redoAction.update();
}
});
}
private void createMenu() {
JMenuBar menuBar = new JMenuBar();
JMenu editMenu = new JMenu("Edit");
editMenu.add(new DefaultEditorKit.CutAction());
editMenu.add(new DefaultEditorKit.CopyAction());
editMenu.add(new DefaultEditorKit.PasteAction());
editMenu.addSeparator();
editMenu.add(undoAction);
editMenu.add(redoAction);
menuBar.add(editMenu);
setJMenuBar(menuBar);
}
class RedoAction extends AbstractAction {
public RedoAction() {
super("Redo");
update();
}
public void actionPerformed(ActionEvent e) {
undoManager.redo();
undoAction.update();
update();
}
public void update() {
boolean canRedo = undoManager.canRedo();
if(canRedo) {
setEnabled(true);
putValue(Action.NAME,
undoManager.getRedoPresentationName());
}
else {
setEnabled(false);
putValue(Action.NAME, "Redo");
}
}
}
class UndoLastAction extends AbstractAction {
public UndoLastAction() {
super("Undo");
update();
}
public void actionPerformed(ActionEvent e) {
undoManager.undo();
redoAction.update();
update();
}
public void update() {
boolean canUndo = undoManager.canUndo();
if(canUndo) {
setEnabled(true);
putValue(Action.NAME,
undoManager.getUndoPresentationName());
}
else {
setEnabled(false);
putValue(Action.NAME, "Undo");
}
}
}
}