|
You are receiving this e-mail {e-mail address} because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy
prominently on our Web site http://sun.com/privacy/ Please do not reply to the mailed version of the newsletter, this alias is not monitored. Feedback options are listed in the footer for both content and delivery issues. |
![]() |
||||||
|
||||||
|
This monthly newsletter provides a way for you to learn the basics of the Java programming language, discover new resources, and keep up-to-date on the latest additions to Sun Developer Network's New to Java Center. You can receive future issues of this newsletter in HTML or text: http://developer.java.sun.com/subscription/ Note: For the code to compile in this issue of Fundamentals, you need to use the JDK 5.0 software. http://java.sun.com/j2se/1.5.0/download.jsp |
||
| Contents | ||
| Java Programming Language Basics | ||
|
Drawing Boxes Around Characters and Strings This month's tip comes from reader Bengi, who asked, "Could you show how to calculate a bounding box of a String?" The response is provided by writer John Zukowski. There are at least two ways to answer this question, and we'll look at both. The Font class offers a getStringBounds() method that returns the bounding rectangle of a String. The Graphics class offers a getFontMetrics() method that allows you to get the string width and character dimensions for a finer level of detail. Of course, there is also the option of just setting the border of a JLabel to draw the box for you. We'll look at all these here.
All three programs take a string from the command line to draw with a bounded box. If no string is provided, the word " Money" is drawn, a word that offers a combination of uppercase and lowercase letters as well as a descender (the character "y," which extends below the baseline).
Using Font.getStringBounds()
The first way to draw a bounding box is sufficient for most cases in which you are explicitly drawing the characters. Given the graphics context passed into your paintComponent() method, get its font rendering context, which contains internal details about the font, and then ask that what the bounding rectangle is for your message. Then, draw the rectangle.
String message = ...;
Graphics2D g2d = (Graphics2D)g;
FontRenderContext frc = g2d.getFontRenderContext();
Shape shape = theFont.getStringBounds(message, frc);
g2d.draw(shape);
Just be sure to coordinate the location of the drawn string with the rectangle, as demonstrated by the following program:
import javax.swing.*;
import java.awt.*;
import java.awt.font.*;
public class Bounds {
static class BoxedLabel extends JComponent {
Font theFont = new Font("Serif", Font.PLAIN, 100);
String message;
BoxedLabel(String message) {
this.message = message;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Insets insets = getInsets();
g.translate(insets.left, insets.top);
int baseline = 150;
g.setFont(theFont);
FontMetrics fm = g.getFontMetrics();
// Center line
int width = getWidth() - insets.right;
int stringWidth = fm.stringWidth(message);
int x = (width - stringWidth)/2;
g.drawString(message, x, baseline);
Graphics2D g2d = (Graphics2D)g;
FontRenderContext frc = g2d.getFontRenderContext();
Shape shape = theFont.getStringBounds(message, frc);
g.translate(x, baseline);
g2d.draw(shape);
g.translate(-x, -baseline);
g.translate(-insets.left, -insets.top);
}
}
public static void main(String args[]) {
final String message;
if (args.length == 0) {
message = "Money";
} else {
message = args[0];
}
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Bounds");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent comp = new BoxedLabel(message);
frame.add(comp, BorderLayout.CENTER);
frame.setSize(400, 250);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
Using Graphics.getFontMetrics()
The second mechanism demonstrates a finer level of detail that may or may not be necessary. What if you want to draw a box around each character of a string? With a proportional font, each character is a different width, so you can't just calculate font size multiplied by number of characters to get the width of the whole string. Instead, you work with the FontMetrics class to get the metrics of each
character involved.
g.setFont(theFont);
FontMetrics fm = g.getFontMetrics();
Some information you get is specific to the font, and not at the character level. When you draw a string, you specify the baseline -- the line where the bottom of the character is to be drawn. The space above the line for the tallest character, including diacritical marks like umlauts, is called the ascent. Below the line for descenders (such as the letter "y") is called descent. Space reserved for between lines of characters is called leading, pronounced like the metal, not like taking charge of a group. The height is the sum of these three.
int ascent = fm.getAscent();
int descent = fm.getDescent();
int leading = fm.getLeading();
int height = fm.getHeight();
There are also values for the maximum of the three sizes, though
this may be the same as the non-max value.
int maxAdv = fm.getMaxAdvance();
int maxAsc = fm.getMaxAscent();
int maxDes = fm.getMaxDescent();
As far as width goes, you can ask for the width of the whole string:
int stringWidth = fm.stringWidth(message);
So, in the case of the bounding box of a string, you'd take its
width and height to create the rectangle.
int stringWidth = fm.stringWidth(message);
int height = fm.getHeight();
To work at the character level, the FontMetrics class has a charWidth() method. By looping through your string, you can increase the x coordinate of your box drawing to draw the next box.
charX += fm.charWidth(message.charAt(i));
The following program demonstrates the use of both sets of methods to box off the whole string and each character.
import javax.swing.*;
import java.awt.*;
public class Metrics {
static class BoxedLabel extends JComponent {
Font theFont = new Font("Serif", Font.PLAIN, 100);
String message;
BoxedLabel(String message) {
this.message = message;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Insets insets = getInsets();
g.translate(insets.left, insets.top);
int baseline = 150;
g.setFont(theFont);
FontMetrics fm = g.getFontMetrics();
int ascent = fm.getAscent();
int descent = fm.getDescent();
int height = fm.getHeight();
int leading = fm.getLeading();
int maxAdv = fm.getMaxAdvance();
int maxAsc = fm.getMaxAscent();
int maxDes = fm.getMaxDescent();
// Center line
int width = getWidth() - insets.right;
int stringWidth = fm.stringWidth(message);
int x = (width - stringWidth)/2;
g.drawString(message, x, baseline);
drawHLine(g, x, stringWidth, baseline);
drawHLine(g, x, stringWidth, baseline-ascent);
drawHLine(g, x, stringWidth, baseline-maxAsc);
drawHLine(g, x, stringWidth, baseline+descent);
drawHLine(g, x, stringWidth, baseline+maxDes);
drawHLine(g, x, stringWidth, baseline+maxDes+leading);
int charX = x;
for (int i=0; i <= message.length(); i++) {
drawVLine(g, charX, baseline-ascent, baseline+maxDes+leading);
if (i != message.length()) {
charX += fm.charWidth(message.charAt(i));
}
}
}
void drawHLine(Graphics g, int x, int width, int y) {
g.drawLine(x, y, x+width, y);
}
void drawVLine(Graphics g, int x, int y, int height) {
g.drawLine(x, y, x, height);
}
}
public static void main(String args[]) {
final String message;
if (args.length == 0) {
message = "Money";
} else {
message = args[0];
}
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Metrics");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent comp = new BoxedLabel(message);
frame.add(comp, BorderLayout.CENTER);
frame.setSize(400, 250);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
One thing to mention about this program is that had the font been italic, the character might not have been bound to within the drawn box. If you need absolute control over the bounds of a string, consider looking at the TextLayout class, which allows you to get the outline shape of a string for further manipulation.
Setting Border of JLabel
The JLabel class has a setBorder() method. This allows you to directly "add" the bounding box without having to subclass to draw it yourself. The system classes will calculate the appropriate location for you, as the following example shows.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
public class Bordered {
public static void main(String args[]) {
final String message;
if (args.length == 0) {
message = "Money";
} else {
message = args[0];
}
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Border");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent comp = new JLabel(message, JLabel.CENTER);
comp.setFont(new Font("Serif", Font.PLAIN, 100));
comp.setBorder(LineBorder.createBlackLineBorder());
frame.getContentPane().setLayout(new GridBagLayout());
frame.add(comp);
frame.setSize(400, 250);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
There is one difference between this program and the prior two: The layout manager is different. Had the layout manager stayed as BorderLayout, the border would have been drawn on the border of the frame. Without using any GridBagConstraints, using GridBagLayout forced the component to be its preferred size, thus centering itself and drawing the borders in roughly the same location as the other two classes.
Conclusion As with much else in the Java platform, there is more than one way to do something. Use the way most appropriate for the situation at hand. You'll find that sometimes one way is much better based upon current circumstances. |
||
| Making Sense of the Java Classes & Tools | ||
|
Listener API Table In the three-column table that follows, the first column gives the name of the listener interface, with either a link to the tutorial page that discusses the listener or, if the tutorial doesn't discuss the listener, a link to the API docs. The second column names the corresponding adapter class, if any. The third column lists the methods that the listener interface contains and shows the type of the event object passed into the method. Typically, the listener, the adapter, and the event type have the same name prefix, but this is not always the case. Read more |
||
| Java Bits | ||
|
How to Use Borders -- Java Tutorial Every JComponent can have one or more borders. Borders are incredibly useful objects that, although not themselves components, know how to draw the edges of Java Foundation Classes/Swing (JFC/Swing) components. Borders are useful not only for drawing lines and fancy edges but also for providing titles and empty space around components.
Note: Our examples set borders on JPanels, JLabels, and custom subclasses of JComponent. Although technically you can set the border on any object that inherits from JComponent, the look-and-feel implementation of many standard JFC/Swing components doesn't work well with user-set borders. In general, when you want to set a border on a standard Swing component other than JPanel or JLabel, we recommend that you put the component in a JPanel and set the border on the JPanel.
The GTK+ look and feel handles borders differently than do other look and feels. Please refer to the 1.4.2 release notes (outside of the tutorial) for details.
To put a border around a JComponent, you use its setBorder method. You can use the BorderFactory class (in the API reference documentation) to create most of the borders that Swing provides. If you need a reference to a border, say, because you want to use it in multiple components, you can save it in a variable of type Border (in the API reference documentation). Here is an example of code that creates a bordered container:
JPanel pane = new JPanel(); pane.setBorder(BorderFactory.createLineBorder(Color.black));Here's a picture of the container, which contains a label component. The black line drawn by the border marks the edge of the container.
The rest of this article discusses the following topics:
|
||
| What's New on java.net | ||
|
The New RMI API by Krishnan Viswanath Java Remote Method Invocation (RMI) introduced a powerful mechanism for distributing application logic across different machines. Instead of having to perform tasks in one monolithic central system, RMI made it possible to build modular and manageable applications in which the computing logic could be distributed. RMI has been the primary communication mechanism for various server-side component architectures, including Enterprise JavaBeans (EJB). Introduced with Java platform 1.1, RMI has been steadily evolving with every major release and has seen the introduction of three new important features with the release of J2SE 5.0. The new features include support for dynamic stub generation, RMI over Secure Sockets Layer (SSL), and the ability to launch a Java RMI server as an extended Internet service (xinetd) daemon in Unix systems. In this article, we will cover these additions. RMI Security The default RMI communication mechanism, the Java Remote Method Protocol (JRMP), is not secure. It is possible to secure the communication by writing custom socket factories using Java Secure Socket Extension (JSSE). But this approach puts the burden of writing additional code on the developers, who must take care of securing data exchange using cryptography. J2SE 5.0 alleviates this issue by introducing two new classes, javax.rmi.ssl.SslRMIClientSocketFactory and javax.rmi.ssl.SslRMIServerSocketFactory, that provide the ability to secure the communication channel between the client and the server using the Secure Sockets Layer (SSL)/Transport Layer Security (TLS) protocols.
These socket factory classes provide a simple and elegant way to use JSSE for secure Java RMI communication, which enables enforcement of data integrity, data confidentiality (through encryption), server authentication, and (optionally) client authentication for remote method invocations. This means developers can focus on the business logic of the distributed application instead of dealing with security-related plumbing. In this section, we will go over the details of using the new SSL socket factories for RMI communication. But before we delve into details, we will provide a brief introduction to TLS. SSL is the most widely used protocol for implementing cryptography over a distributed communication protocol such as HTTP. The primary purpose of SSL is to provide privacy, data integrity, authenticity, and nonrepudiation. This is achieved by using symmetric key for data encryption between the client and server, and asymmetric key cryptography (or public/private key cryptography) to authenticate the identities of communicating parties as well as to encrypt the shared encryption key that is used when establishing an SSL session. Read the rest of this article |
||
| Learning Java 2D, Part 2 | ||
|
by Robert Eckstein Part 1 in this series on learning to use the Java 2D API discussed how the Java 2D graphics engine -- represented by the java.awt.Graphics2D class -- takes graphics primitive classes such as shapes, text, and images and renders them to an output device, such as a screen or a printer. This article discusses how to use the Java 2D API libraries to manipulate and display images.
Working With Images With the Abstract Window Toolkit (AWT) alone, the only way to display an image is to use the java.awt.Image class. However, this class does not allow you to access the image data directly. In fact, the only methods that directly returned information about the image in java.awt.Image were getHeight() and getWidth(), but even then, there were limitations: If the system had not yet loaded the image data, the values would be erroneous, and you would have to use an instance of java.awt.ImageObserver to be notified when the data became available. If you wanted to manipulate the image data in other ways, you were forced to use the inconvenient producer-consumer model to inspect or manipulate the data as it was decoded from its source.
Buffered Images The java.awt.image.BufferedImage class, introduced as part of the Java 2D API with the Java Development Kit (JDK) 1.2, affords the programmer much more freedom to directly manipulate the pixels inside an image. Compared to the producer-consumer model, this class uses an immediate-mode imaging model from which you can inspect and modify pixel data stored directly in memory. You can also access image data in a variety of formats and use several types of filtering operations to manipulate the data.
Read the rest of this article |
||
| Sun's Java Technology CD-ROM Courses | ||
|
Java Programming Language (CDJ-275) The Java Programming Language course provides students with a self-paced CD-ROM course that can help experienced programmers learn how to write, compile, and run Java technology applications. This course provides fundamental knowledge about the Java programming language and its runtime environment, object-oriented programming with the Java programming language, creating programs with graphical user interface (GUI) components, handling exceptions, using threads, creating applets, and how input/output and networking work in the Java programming language. Learn more about this course |
||
| Sun's Java Technology Web Courses | ||
|
J2SE Internals and Troubleshooting (WJO-3250) The J2SE Internals and Troubleshooting course provides technical information on the internal functioning and operation of Java 2 Platform, Standard Edition (J2SE). The course addresses debugging, gathering of crash-related data, the nature of the Just In Time compiler, garbage collection, JNI, threads, and handling signals in native code. Learn more about this course |
||
| Free Developers Tools | ||
|
Sun is offering the award-winning Sun Java Studio Enterprise and Sun Java Studio Creator IDEs at no cost to all developers worldwide who join Sun Developer Network (SDN). Learn more |
||
| For More Information | ||
|
The terms "Java Virtual Machine" and "JVM" mean a virtual machine for the Java platform. |
||
| Downloading the Java Platform, Standard Edition (Java SE, formerly known as J2SE) | ||
|
For most Java technology development, you need the class libraries, compiler, tools, and runtime environment provided with the Java SE development kit. Download Java SE Platform Bookmark the Specifications New to Java Center |
||
|
Comments? Send your feedback on the Java Technology Fundamentals Newsletter to: fundamentals_newsletter@sun.com
Find archived issues of the following Java technology developer newsletters or manage your current newsletter subscriptions: https://softwarereg.sun.com/registration/developer/en_US/subscriptions Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
PRIVACY STATEMENT Sun respects your online time and privacy. You have received this based on your email preferences. If you would prefer not to receive this information, please follow the steps at the bottom of this message to unsubscribe. IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies: http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/ http://developer.java.sun.com/berkeley_license.html © 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://sun.com/suntrademarks Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. To update your Sun subscription preferences or unsubscribe to Sun news services, click here or use this link https://softwarereg.sun.com/registration/developer/en_US/subscriptions FEEDBACK Comments? Send your feedback on the Java Technology Fundamentals Newsletter to dana.nourie@sun.com Sun Microsystems, Inc. 10 Network Circle, MPK10-209 Menlo Park, CA 94025 US |