Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Technical Tips

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
Print Button
 
Tech Tips archive

Tech Tips
October 5, 1999

This issue presents tips, techniques, and sample code for the following topics:

This issue of the JDC Tech Tips is written by Glen McCluskey.


SWING DOCUMENT LOCATIONS

In JavaTM Foundation Classes (JFC) Project Swing, a text pane that you use to edit text is backed by a "document". For example, a JTextPane has, by default, a DefaultStyledDocument underlying it. The document is what actually stores text and other content that is displayed in the pane.

Suppose that you are using a Swing document in your application, and you'd like to keep track of specific locations in the document. So you decide to use character offsets for this purpose, for example, a location that is 47 characters into the document.

This approach does work until you edit the document. For example, suppose you delete the first 10 characters. You'll then need to update offset 47 to 37 to keep the location correct.

A better approach to track document locations is Swing's Position interface. If a class implements the Position interface, it defines a location in a document. If the document changes, for instance, after editing, the location is updated as necessary. To see how this works, consider the following example:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class PosDemo {
  static Position lastpos;

  public static void main(String args[]) {
    JFrame frame = new JFrame("Position demo");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });

    final JTextPane pane = new JTextPane();
    pane.setPreferredSize(new Dimension(600, 400));

    JButton setbutton = new JButton("Set Position");
    JButton gobutton = new JButton("Go To Position");

    setbutton.addActionListener(
      new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        try {
          int dot = pane.getCaret().getDot();
          Document doc = pane.getDocument();
          lastpos = doc.createPosition(dot);
          pane.requestFocus();
        }
        catch (BadLocationException exc) {
          System.err.println(exc);
        }
      }
    });

    gobutton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        if (lastpos == null) {
          Toolkit.getDefaultToolkit().beep();
        }
        else {
                        
          int pos = Lastpos.getOffset();
          pane.getCaret().setDot(pos);
          pane.requestFocus();
        }
      }
    });

    JPanel buttonpanel = new JPanel();
    buttonpanel.add(setbutton);
    buttonpanel.add(gobutton);

    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());
    panel.add("North", buttonpanel);
    panel.add("Center", pane);

    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }
}
The demo sets up a text window, along with Set Position and Go To Position buttons. Suppose you type some text, move the text caret somewhere in that text, and then select Set Position. At this point you've recorded a location in the text. Then suppose that you edit the text, adding and deleting characters before and after the position you selected. If you then select the Go To Position button, the caret will move back to the original location. In other words, the action of the Go To Position button takes into account the changed offset of the location based on edits you've done.

To see what's going on here, enter a distinct pattern like "XYZ" into the middle of some random text. Move the caret to that pattern and then select Set Position. Doing it this way makes it clear that the pattern itself is being tracked as a location, rather than simply a specific character offset in the document.

These three lines in the example program do the actual location saving:

 int dot = pane.getCaret().getDot();
 Document doc = pane.getDocument();
 astpos = doc.createPosition(dot);
The first line retrieves the current caret offset (dot). The second line gets the document. And the third line creates a Position instance in the document from the caret offset. The process is reversed later in the program with the lines:
  int pos = lastpos.getOffset();
  pane.getCaret().setDot(pos);
where getOffset retrieves the updated offset.


KEYMAPS

You may have never considered the details of what happens when you type characters into a text area. But this process is important to understand, especially if you're trying to customize how an application handles input from the keyboard.

Swing text components use what are called "keymaps". A keymap maps keyboard keys to resulting actions. For example, the Backspace key deletes the character preceding the text caret. Or the Delete key removes the character after the caret. By contrast, simply typing a character such as "z" inserts that character as text content.

It's possible to override the default keymap with your own, as this example illustrates:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class KeyMap {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Keymap demo");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });

    final JTextPane pane = new JTextPane();
    pane.setPreferredSize(new Dimension(600, 400));

    Keymap km = pane.getKeymap();
    KeyStroke ks = KeyStroke.getKeyStroke(
      KeyEvent.VK_Z, Event.CTRL_MASK);
    Action act = new TextAction("Ctrl-Z") {
      public void actionPerformed(ActionEvent e) {
        pane.replaceSelection("ZZZ");
      }
    };
    km.addActionForKeyStroke(ks, act);

    JPanel panel = new JPanel();
    panel.add("Center", pane);

    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }
}
This demo overrides the default action for Ctrl-Z (which is to do nothing). With this override in place, Ctrl-Z inserts "ZZZ" into the text pane. In other words, a keystroke (a combination of a key and possibly a modifier like Ctrl) has been added to the keymap. And an action has been specified for the keystroke such that replaceSelection is called to insert text or replace selected text with new text.

This feature can be used in an application such as a word processor,where the user binds arbitrary text strings to keys.

There are several interesting points to note about keymaps. One is that a default keymap is set up for you when you use JTextPane. It contains bindings for keystrokes such as Ctrl-X (cut selected text). The example above changes this keymap by adding a keystroke/action pair to it. This modification will be reflected in all text panes in the application. So if you don't want to disturb the default keymap, you can create your own.

If you set a keymap to null, as in:

pane.setKeymap(null);

then keyboard input to the text pane is disabled.

There is also the concept of parent and child keymaps. If a keystroke is not resolved in a child keymap, then it is searched for in the parent. An application might, for example, create its own keymap, and use the default keymap as a parent. The parent keymap is used to resolve keystrokes not found in the application-specific keymap. In the example above, Ctrl-Z might be resolved in a keymap that has been created in the application, with Ctrl-X resolved in the default parent keymap.

— Note —

The names on the JDCSM mailing list are used for internal Sun MicrosystemsTM purposes only. To remove your name from the list, see Subscribe/Unsubscribe below.

— Feedback —

Comments? Send your feedback on the JDC Tech Tips to: jdc-webmaster

— Subscribe/Unsubscribe —

The JDC Tech Tips are sent to you because you elected to subscribe when you registered as a JDC member. To unsubscribe from JDC email, go to the following address and enter the email address you wish to remove from the mailing list:

http://developer.java.sun.com/unsubscribe.html

To become a JDC member and subscribe to this newsletter go to:

http://java.sun.com/jdc/


Print Button
[ This page was updated: 21-Sep-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary | Feedback | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.