Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 

Chapter 2. (Introduction) Swing Mechanics. Easy for reading, Click here!

Custom Search
Chapter 2. (Introduction) Swing Mechanics. Easy for reading, Click here!

[ Return to Swing (Book) ]

Page: 8/14 



Previous Page Previous Page (7/14) - Next Page (9/14) Next Page
Subpages: 1. JComponent properties, size, and positioning 
2.  Event handling and dispatching 
3. Multithreading
4. Timers
5. AppContext service
6. Inside Timers & the TimerQueue
7. JavaBeans architecture
8. Fonts, Colors, Graphics and text
9. Using the Graphics clipping area
10. Graphics debugging
11. Painting and validation
12. Focus Management
13. Keyboard input, KeyStrokes, and Actions
14. SwingUtilities

2.8    Fonts, Colors, Graphics and text

2.8.1    Fonts

class java.awt.Font, abstract class java.awt.GraphicsEnvironment

As we saw in BakedBean above, fonts are quite easy to create:

    m_beanFont = new Font("SanSerif", Font.BOLD | Font.ITALIC, 12);

In this code "SanSerif" is the font name, Font.Bold | Font.PLAIN is the style (which in this case is both bold and italic), and 12 is the size. The Font class defines three static int constants to denote font style: Font.BOLD, Font.ITALIC, FONT.PLAIN. We can specify font size as any int in the Font constructor (as shown above). Using Java 2, in order to get a list of available font names at run-time we ask the local GraphicsEnvironment:

    GraphicsEnvironment ge = GraphicsEnvironment.

      getLocalGraphicsEnvironment();

    String[] fontNames = ge.getAvailableFontFamilyNames();

Note: Java 2 introduces a whole new powerful mechanism for communicating with devices that can render graphics, such as screens, printers or image bufferes. These devices are represented as instances of the GraphicsDevice class. Interstingly, a GraphicsDevice might reside on the local machine, or it might reside on a remote machine. Each GraphicsDevice has a set of GraphicsConfiguration objects associated with it. A GraphicsConfiguration describes specific characteristics of the associated device. Usually each GraphicsConfiguration of a GraphicsDevice represents a different mode of operation (for instance resolution and number of colors).

Note: In JDK1.1 code, getting a list of font names often looked like this:

String[] fontnames = Toolkit.getDefaultToolkit().getFontList();

The Toolkit.getFontList() method has been deprecated in Java 2 and this code should be updated.

GraphicsEnvironment is an abstract class that describes a collection of GraphicsDevices. Subclasses of GraphicsEnvironment must provide three methods for retreiving arrays of Fonts and Font information:

    Font[] getAllFonts(): retreives all available Fonts in one-point size.

    String[] getAvailableFontFamilyNames(): retreives the names of all font families available.

    String[] getAvailableFontFamilyNames(Locale l): retreives the names of all font families available using the specifice Locale (internationalization support).

GraphicsEnvironment also provides static methods for retrieving GraphicsDevices and the local GraphicsEnvironment instance. In order to find out what Fonts are available to the system our program is running on, we must refer to this local GraphicsEnvironment instance, as shown above. It is much more efficient and convenient to retreive the available names and use them to construct Fonts than it is to retreive an actual array of Font objects (no less, in one-point size).

We might think that, given a Font object, we can use typical getXX()/setXX() accessors to alter its name, style, and size. Well, we would be half right. We can use getXX() methods to retrieve this information from a Font:

    String getName()

    int getSize()

    float getSize2D()

    int getStyle

However, we cannot use typical setXX() methods. Instead we must use one of the following Font instance methods to derive a new Font:

    deriveFont(float size)

    deriveFont(int style)

    deriveFont(int style, float size)

    deriveFont(Map attributes)

    deriveFont(AffineTransform trans)

    deriveFont(int style, AffineTransform trans)

Normally we will only be interested in the first three methods.

Note: AffineTransforms are used in the world of Java 2D to perform things such as translations, scales, flips, rotations, and shears. A Map is an object that maps keys to values (it does not contain the objects involved) and the attributes referred to here are key/value pairs as described in the API docs for java.text.TextAttribute (this class is defined in the java.awt.font package that is new to Java 2, and considered part of Java 2D -- see chapter 23).

2.8.2    Colors

The Color class provides several static Color instances to be used for convenience (e.g. Color.blue, Color.yellow, etc.). We can also construct a Color using, among others, the following constructors:

    Color(float r, float g, float b)

    Color(int r, int g, int b)

    Color(float r, float g, float b, float a)

    Color(int r, int g, int b, int a)

Normally we use the first two methods, and those familiar with JDK1.1 will most likely recognize them. The first allows red, green, and blue values to be specified as floats from 0.0 to 1.0. The second takes these values as ints from 0 to 255.

The second two methods are new to Java 2. They each contain a fourth parameter which represents the Color's alpha value. The alpha value directly controls transparency. It defaults to 1.0 or 255 which means completely opaque. 0.0 or 0 means completely transparent.

Note that, as with Fonts, there are plenty of getXX() accessors but no setXX() accessors. Instead of modifying a Color object we are normally expected to create a new one.

Note: The Color class does have static brighter() and darker() methods that return a Color brighter or darker than the Color specified, but their behavior is unpredicatble due to internal rounding errors and we suggest staying away from them for most practical purposes.

By specifying an alpha value we can use the resulting Color as a component's background to make it  transparent! This will work for any lightweight component provided by Swing such as labels, text components, internal frames, etc. Of course there will be component-specific issues involved (such as making the borders and title bar of an internal frame transparent). The next section demonstrates a simple Swing canvas example showing how to use the alpha value to paint some transparent shapes.

Note: A Swing component's opaque property, controlled using setOpaque(), is not directly related to Color transparency. For instance, if we have an opaque JLabel whose background has been set to a transparent green (e.g. Color(0,255,0,150)) the label's bounds will be completely filled with this color only because it is opaque. We will be able to see through it only because the color is transparent. If we then turn off opacity the background of the label would not be rendered. Both need to be used together to create transparent components, but they are not directly related.

2.8.3    Graphics and text

abstract class java.awt.Graphics, abstract class java.awt.FontMetrics

Painting is much different in Swing than it is in AWT. In AWT we typically override Component's paint() method to do rendering and the update() method for things like implementing our own double-buffering or filling the background before paint() is called.

With Swing, component rendering is much more complex. Though JComponent is a subclass of Component, it uses the update() and paint() methods for different reasons. In fact, the update() method is never invoked at all. There are also five additional stages of painting that normally occur from within the paint() method. We will discuss this process in section 2.11, but it suffices to say here that any JComponent subclass that wants to take control of its own rendering should override the paintComponent() method and not the paint() method. Additionally, it should always begin its paintComponent() method with a call to super.paintComponent().

Knowing this, it is quite easy to build a JComponent that acts as our own lightweight canvas. All we have to do is subclass it and override the paintComponent() method. Inside this method we can do all of our painting. This is how to take control of the rendering of simple custom components. However, this should not be attempted with normal Swing components because UI delegates are in charge of their rendering (we will see how to take customize UI delegate rendering at the end of chapter 6, and throughout chapter 21).

Note: The awt Canvas class can be replaced by a simplified version of the JCanvas class we define in the following example.

Inside the paintComponent() method we have access to that component's Graphics object (often referred to as a component's graphics context) which we can use to paint shapes and draw lines and text. The Graphics class defines many methods used for these purposes and we refer you to the API docs for these. The following code shows how to construct a JComponent subclass that paints an ImageIcon and some shapes and text using various Fonts and Colors, some completely opaque and some partially transparent (we saw similar, but less interesting, functionality in BakedBean). Figure 2.3 illustrates.

Figure 2.3 Graphics demo in a lightweight canvas.

<<file figure2-3.gif>>

The Code: TestFrame.java

see \Chapter1\2

import java.awt.*;

import javax.swing.*;

class TestFrame extends JFrame

{

  public TestFrame() {

    super( "Graphics demo" );

    getContentPane().add(new JCanvas());

  }

  public static void main( String args[] ) {

    TestFrame mainFrame = new TestFrame();

    mainFrame.pack();

    mainFrame.setVisible( true );

  }

}

class JCanvas extends JComponent {

  private static Color m_tRed = new Color(255,0,0,150);

  private static Color m_tGreen = new Color(0,255,0,150);

  private static Color m_tBlue = new Color(0,0,255,150);

  private static Font m_biFont =

    new Font("Monospaced", Font.BOLD | Font.ITALIC, 36);

  private static Font m_pFont =

    new Font("SanSerif", Font.PLAIN, 12);

  private static Font m_bFont = new Font("Serif", Font.BOLD, 24);

  private static ImageIcon m_flight = new ImageIcon("flight.gif");

  public JCanvas() {

    setDoubleBuffered(true);

    setOpaque(true);

  }

  public void paintComponent(Graphics g) {

    super.paintComponent(g);

    // fill entire component white

    g.setColor(Color.white);

    g.fillRect(0,0,getWidth(),getHeight());

    // filled yellow circle

    g.setColor(Color.yellow);

    g.fillOval(0,0,240,240);

    // filled magenta circle

    g.setColor(Color.magenta);

    g.fillOval(160,160,240,240);

    // paint the icon below blue sqaure

    int w = m_flight.getIconWidth();

    int h = m_flight.getIconHeight();

    m_flight.paintIcon(this,g,280-(w/2),120-(h/2));

    // paint the icon below red sqaure

    m_flight.paintIcon(this,g,120-(w/2),280-(h/2));

    // filled transparent red square

    g.setColor(m_tRed);

    g.fillRect(60,220,120,120);

    // filled transparent green circle

    g.setColor(m_tGreen);

    g.fillOval(140,140,120,120);

    // filled transparent blue square

    g.setColor(m_tBlue);

    g.fillRect(220,60,120,120);

    g.setColor(Color.black);

    // Bold, Italic, 36-point "Swing"

    g.setFont(m_biFont);

    FontMetrics fm = g.getFontMetrics();

    w = fm.stringWidth("Swing");

    h = fm.getAscent();

    g.drawString("Swing",120-(w/2),120+(h/4));

    // Plain, 12-point "is"

    g.setFont(m_pFont);

    fm = g.getFontMetrics();

    w = fm.stringWidth("is");

    h = fm.getAscent();

    g.drawString("is",200-(w/2),200+(h/4));

    // Bold 24-point "powerful!!"

    g.setFont(m_bFont);

    fm = g.getFontMetrics();

    w = fm.stringWidth("powerful!!");

    h = fm.getAscent();

    g.drawString("powerful!!",280-(w/2),280+(h/4));

  }

  // Most layout managers need this information

  public Dimension getPreferredSize() {

    return new Dimension(400,400);

  }

  public Dimension getMinimumSize() {

    return getPreferredSize();

  }

  public Dimension getMaximumSize() {

    return getPreferredSize();

  }

}

Note that we override JComponent's getPreferredSize(), getMinimumSize(), and getMaximumSize(), methods so most layout managers can intelligably size this component (otherwise some layout managers will set its size to 0x0). It is always good practice to override these methods when implementing custom components.

The Graphics class uses what is called the clipping area. Inside a component's paint() method, this is the region of that component's view that is being repainted (we often say that the clipping area represents the damaged or dirtied region of the component's view). Only painting done within the clipping area's bounds will actually be rendered. We can get the size and position of these bounds by calling getClipBounds() which will give us back a Rectangle instance describing it. The reason a clipping area is used is for efficiency purposes: there is no reason to paint undamaged or invisible regions when we don't have to. (We will show how to extend this example to work with the clipping area for maximum efficiency in the next section).

Note: All Swing components are double buffered by default. If we are building our own lightweight canvas we do not have to worry about double-buffering. This is not the case with an awt Canvas.

As we mentioned earlier, Fonts and Font manipulation is very complex under the hood. We are certainly glossing over their structure, but one thing we should discuss is how to obtain useful information about fonts and the text rendered using them. This involves use of the FontMetrics class. In the example above, FontMetrics allowed us to determine the width and hieght of three Strings, rendered in the current Font associated with the Graphics object, so that we could draw them centered in the circles.

Figure 2.4 illustrates some of the most common information that can be retreived from a FontMetrics object. The meaning of baseline, ascent, descent, and height should be clear from the diagram. The ascent is supposed to be the distance from the baseline to the top of most characters in that font. Note that when we use g.drawString() to render text, the coordinates specified represent the position to place the baseline of the first character.

FontMetrics provides several methods for retrieving this and more detailed information, such as the width of a String rendered in the associated Font.

Figure 2.4 Using FontMetrics

<<file figure2-4.gif>>

In order to get a FontMetrics instance we first tell our Graphics object to use the Font we are intersted in examining using the setFont() method. Then we create the FontMetrics instance by calling getFontMetrics() on our Graphics object:

    g.setFont(m_biFont);

    FontMetrics fm = g.getFontMetrics();

A typical operation when rendering text is to center it on a given point. Suppose we want to center the text "Swing" on 200,200. Here is the code we would use (assuming we have retrieved the FontMetrics object, fm, as shown above):

     int w = fm.stringWidth("Swing");

     int h = fm.getAscent();

     g.drawString("Swing",200-(w/2),200+(h/4));

We get the width of "Swing" in the current font, divide it by two, and subtract it from 200 to center the text horizontally. To center it vertically we get the ascent of the current font, divide it by four, and add 200. The reason we divide the ascent by four is probably NOT so clear.

It is now time to address a common mistake that has arisen with Java 2. Figure 2.4 is not an accurate way to document FontMetrics. This is the way we have seen things documented in the Java tutorial and just about everywhere else that we have referenced. However, there appears to be a few problems with FontMetrics as of Java 2 FCS. Here we'll write a simple program that demonstrates these problems. Our program will draw the text "Swing" in a 36-point bold, monospaced font. We draw lines where its ascent, ascent/2, ascent/4, baseline, and descent lie. Figure 2.5 illustrates.

Figure 2.5 The real deal with FontMetrics in Java 2

<<file figure2-5.gif>>

The Code: TestFrame.java

See \Chapter1\2\fontmetrics

import java.awt.*;

import javax.swing.*;

class TestFrame extends JFrame

{

  public TestFrame() {

    super( "Lets get it straight!" );

    getContentPane().add(new JCanvas());

  }

  public static void main( String args[] ) {

    TestFrame mainFrame = new TestFrame();

    mainFrame.pack();

    mainFrame.setVisible( true );

  }

}

class JCanvas extends JComponent

{

  private static Font m_biFont = new Font("Monospaced", Font.BOLD, 36);

  public void paintComponent(Graphics g) {

    g.setColor(Color.black);

    // Bold 36-point "Swing"

    g.setFont(m_biFont);

    FontMetrics fm = g.getFontMetrics();

    int h = fm.getAscent();

    g.drawString("Swing",50,50); // Try these as well: Ñ Ö Ü ^

    // draw Ascent line

    g.drawLine(10,50-h,190,50-h);

    // draw Ascent/2 line

    g.drawLine(10,50-(h/2),190,50-(h/2));

    // draw Ascent/4 line

    g.drawLine(10,50-(h/4),190,50-(h/4));

    // draw baseline line

    g.drawLine(10,50,190,50);

    // draw Descent line

    g.drawLine(10,50+fm.getDescent(),190,50+fm.getDescent());

  }

  public Dimension getPreferredSize() {

    return new Dimension(200,100);

  }

}

We encourage you to try this demo program with various different fonts, font sizes, and even characters with diacritical marks such as Ñ, Ö, or Ü. You will find that the ascent is always much higher than it is typically documented to be, and the descent is always lower. The most reliable means of vertically centering text we found turned out to be baseline + ascent/4. However, baseline + descent might also be used and, depending on the font in use, may provide more accurate centering.

The point is that there is no correct way to perform this task due to the current state of FontMetrics in Java 2.You may experience very different results if not using the first release of Java 2. It is a good idea to run this program and verify whether or not results similar to those shown in figure 2.5 are produced on your system. If not you will want to use a different centering mechanism for your text which should be fairly simple to determine through experimentation with this application.

Note: In JDK1.1 code, getting a FontMetrics instance often looked like this:

FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(myfont);

The Toolkit.getFontMetrics method has been deprecated in Java 2 and this code should be updated.



[ Return to Swing (Book) ]


Top 10 read Java Articles
 Get free "1000 Java Tips eBook"

 Java Calendar and Date: good to know facts and code examples

 Array vs ArrayList vs LinkedList vs Vector: an excellent overview and examples

 How can I convert any Java Object into byte array? And byte array to file object

 The Java Lesson 1: What is Java?

 How do I compare two dates and times, date between dates, time between times and

 Maven vs Ant or Ant vs Maven?

 How to open, read, write, close file(s) in Java? Examples on move, rename and de

 Java Array

 Java: JLabel font and color


[ More in News Section ]
Java Lessons

The Java Lesson 1:
What is Java?
The Java Lesson 2:
Anatomy of a simple Java program
The Java Lesson 3:
Identifiers and primitive data types
The Java Lesson 4:
Variables, constants, and literals
The Java Lesson 5:
Arithmetic operations, conversions, and casts
The Java Lesson 6:
Boolean expressions and operations
The Java Lesson 7:
Bitwise operations
The Java Lesson 8:
Flow control with if and else
The Java Lesson 9:
switch statements
The Java Lesson 10:
for, while, and do-while statements
The Java Lesson 11:
Using break and continue
The Java Lesson 12:
Class methods and how they are called
The Java Lesson 13:
Using the Math class
The Java Lesson 14:
Creating and calling custom class methods
The Java Lesson 15:
Overloading class methods
The Java Lesson 16:
An introduction to objects and object references
The Java Lesson 17:
The String class
The Java Lesson 18:
The StringBuffer class
The Java Lesson 19:
Initializing and processing arrays of primitives
The Java Lesson 20:
Initializing and processing arrays of objects
The Java Lesson 23:
Inheritance and overriding inherited methods
The Java Lesson 24:
abstract classes and polymorphism
The Java Lesson 25:
Interfaces, instanceof, and object conversion and casting
The Java Lesson 26:
Introduction to graphical programming and the java.awt packa
The Java Lesson 27:
The Component class
The Java Lesson 28:
Containers and simple layout managers
The Java Lesson 29:
The Color and Font classes
The Java Lesson 30:
Drawing geometric shapes
The Java Lesson 31:
Choice, List, and Checkbox controls
The Java Lesson 32:
Using the Scrollbar graphical control
The Java Lesson 33:
Menus and submenus
The Java Lesson 34:
An introduction to applets and the Applet class
The Java Lesson 35:
Essential HTML to launch an applet and pass it parameters
The Java Lesson 36:
Mouse event processing
Java Lesson 37:
Menus and submenus
Java Lesson 38:
The WindowListener interface and the WindowAdapter class
Java Lesson 39:
An introduction to GridBagLayout
Java Lesson 40:
An introduction to the Java Collections API
Java Lesson 41:
Exception handling with try, catch, and finally blocks
Java Lesson 42:
Claiming and throwing exceptions
Java Lesson 43:
Multithreading, the Thread class, and the Runnable interface
Java Lesson 44:
An introduction to I/O and the File and FileDialog classes
Java Lesson 45:
Low-level and high-level stream classes
Java Lesson 46:
Using the RandomAccessFile class
Java Lessons by
Joh Huhtala: Update

Latest articles
 Java Profiler JProbe to Resolve Performance Problems Faster

 SSL with GlassFish v2, page 5

 SSL with GlassFish v2, page 4

 SSL with GlassFish v2, page 3

 SSL with GlassFish v2, page 2

 The Java Lesson 2: Anatomy of a simple Java program, page 2

 New site about Java for robots and robotics: both software and hardware.

 Exceptions -III: What's an exception and why do I care?

 Exceptions -II: What's an exception and why do I care?

 Exceptions: What's an exception and why do I care?

 Double your Java code quality in 10 minutes, here is receipt

 Murach's Java Servlets and JSP

 How to get ascii code from a char in Java?

 Can we just try without catch? Yes!

 Make Tomcat page load faster

 Make your Tomcat More secure - limit network address for certain IP addresses

 New Java book online starts now here...

 Implementing RESTful Web Services in Java

 Firefox trimming from 1 GB to 40 Mb with many tabs opened

 SSL with GlassFish v2

 My request to replublish Tech Tips

 Search JavaFAQ.nu site here

 New Advanced Installer for Java 6.0 brings XML updates and imports 3rd party MSI

 EJB programming restrictions

 Maven vs Ant or Ant vs Maven?

 Why Java does not use default value which it should?

 How to unsign signed bytes in Java - your guide is here

 The Java Lesson 3: Identifiers and primitive data types. Page 2

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 4

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 3


[ More in News Section ]


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy