Received: from SOUTH-STATION-ANNEX.MIT.EDU by po10.MIT.EDU (5.61/4.7) id AA12328; Tue, 5 Oct 99 22:53:07 EDT Received: from hermes.javasoft.com by MIT.EDU with SMTP id AA23552; Tue, 5 Oct 99 22:52:45 EDT Received: (from nobody@localhost) by hermes.java.sun.com (8.9.3+Sun/8.9.1) id CAA17929; Wed, 6 Oct 1999 02:52:53 GMT Date: Wed, 6 Oct 1999 02:52:53 GMT Message-Id: <199910060252.CAA17929@hermes.java.sun.com> X-Authentication-Warning: hermes.java.sun.com: Processed from queue /bulkmail/data/ed_72/mqueue2 X-Mailing: 191 From: JDCTechTips@sun.com Subject: JDC Tech Tips October 5, 1999 To: JDCMember@sun.com Reply-To: JDCTechTips@sun.com Errors-To: JDCMailErrors@sun.com Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Mailer: Beyond Email 2.2 J D C T E C H T I P S TIPS, TECHNIQUES, AND SAMPLE CODE WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, October 5, 1999. This issue covers: * Swing Document Locations * Keymaps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SWING DOCUMENT LOCATIONS In Java(tm) 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(); lastpos = 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 JDC mailing list are used for internal Sun Microsystems(tm) 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/ - ARCHIVES You'll find the JDC Tech Tips archives at: http://developer.java.sun.com/developer/TechTips/index.html - COPYRIGHT Copyright 1999 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA. This document is protected by copyright. For more information, see: http://developer.java.sun.com/developer/copyright.html This issue of the JDC Tech Tips is written by Glen McCluskey. JDC Tech Tips October 5, 1999