The Java Programming Language

Table of Contents

last revision
16 September 2012, 3:20pm
book quality
not too bad
:

quote: "A world in itself" (anon) Stroustrup: "bloated and inefficient"

This booklet attempts to provide 'recipes' for how to carry out common tasks with the java language. The idea of this and other booklets at bumble.sf.net is to provide the most succint but complete code snippets which will get the job done. But the java language doesnt really lend itself to this type of succintness. Complete examples are given where possible.

Learning Java ‹↑›

Books ‹↑›

"effective java programming" josh bloch Supposedly a good book "filthy rich clients" chet haase, romain guy ... How to create nice looking interfaces in java using animation and other graphical effects "Java 6 New Features: A Tutorial" Budi Kurniawan (ISBN-10: 0975212885, ISBN-13: 978-0975212882) Some good stuff about drag and drop "swing hacks"

Web Resources ‹↑›

www: www.stackoverflow.com
Possibly the best forum to get answers to tricky java programming problems.
www: http://www.javarichclient.com
Very good examples of how to improve a java swing interface.
www: http://docstore.mik.ua/orelly/java-ent/
text from the oreilly in a nutshell series on various java topics
www: tips4java.workpress.com/
Very good advanced java tips by Rob Camick and Darryl Burke
www: http://elliotth.blogspot.com/
a blog with some good code snippets, by an android developer elliott hughes with good android links- eg vogar.
www: http://www.java2s.com/
a lot of examples but without any comments or explanation. Good drag and drop examples.
www: http://leepoint.net/notes-java/
good introductory notes
www: rgagnon
- real java howto Some good examples.
www: http://rcforte.wordpress.com/author/rcforte/
A good blog about java swing etc.
www: http://www.jguru.com/faq/
some good, advanced faqs about java topics, including javamail
www: http://www.exampledepot.com/egs/
short and clear examples but sometimes not very 'correct'
www: http://devdaily
short but good examples
www: http://javagraphics.blogspot.com/
nice advanced java graphics, interface examples
www: www.java-tips.org
tips
www: http://www.kodejava.org/examples/28.html

Documentation For Java ‹↑›

Installing Java Documentation ‹↑›

The java api documentation contained in a file called something like jdk-6-doc.zip is a set of html files generated from the javadoc comments contained in the api source code.

download the java documentation package

 ...

unzip the documentation file

 jar xvf jdk-6-doc.zip
 unzip jdk-6-doc.zip   the same

copy or move the doc file to any folder, or the jdk folder

 mv docs /usr/lib/jvm/java-6-sun/

open the index page in a browser

 docs/index.html

on a linux debian computer, install the java documentation

 sudo apt-get install sun-java6-doc

Viewing Java Api Documentation ‹↑›

Source Code For The Java Api ‹↑›

The src code for the java apis can be a valuable learning tool. Sun seems to be releasing its source code through the openjdk project, which is an open source implementation of the java platform.

on a debian linux system install java 6 source code

 sudo apt-get install sun-java6-source

http://download.java.net/openjdk/jdk6/ url to download source for the openjdk implementation of the java apis.

Javadoc ‹↑›

javadoc is a tool for generating documentation for java classes in (usually) html format from the java source files. Java documentation cannot be accessed via reflection because the information is not contained in the '.class' files.

Basic Java ‹↑›

www: www.java2s.com/Code/Java/Language-Basics/CatalogLanguage-Basics.htm
examples of language basics
possibly the simplest java program
   public class Simple {
     public static void main(String[] args) {
       System.out.println("hello");
     }
   }

The parameter to the main method is necessary.

Variables Member Fields And Parameters ‹↑›

Varargs ‹↑›

Some methods can take a variable number of parameters or arguments. This is sometimes referred to as 'varargs'. An example of this is the System.out.format() method and the String.format() method. If the wrong number of arguments is given for a particular invocation, then a Runtime exception is thrown, not a compile-time error.

Member Fields ‹↑›

The class java.lang.reflect.Field can be used to obtain complete information about member fields in classes. See the Reflection section for more information.

Access Modifiers ‹↑›

Access modifiers are a method to restrict access (by other classes or objects) to the member fields and methods of a class.

The class java.lang.reflect.Modifier and the method java.lang.reflect.Field.getModifiers() can be used to obtain lots of information about the access and other modifiers applied to particular member fields in a class. See the Reflection,Fields section for more detailed information

In general member fields should be declared private to ensure data hiding.

declare a JTable as a private member field

 private JTable table;

Final ‹↑›

 final String WORD = new String("tree");
 private final String WORD = new String("tree");

Variable Scope ‹↑›

within a method the parameter name takes precedence over member

    String s;
    public void doTask(s) {
      this.s = s;
    }

Declaring Variables ‹↑›

declare 2 variables as type integer

 int x, y;

Initialising Variables ‹↑›

It is reasonably common to see Objects initialised to 'null'. Often the point of this is to avoid compiler errors of the type 'variable o may not have been initialised'. These errors arise usually because of try/catch blocks containing another (real) initialisation of the object variable.

initialise a variable to null to avoid compiler errors with try/catch

 java.util.Properties p = null;

Gotchas For Declarations ‹↑›

compile errors !!! variable uninitialised

 int x; System.out.print("x=" + x);
 int x; x=x+1

but NO error if var is an instance variable

 private int x;    !! initialised to zero

declare a constant array of strings as a private member variable

  private static final String[] COLUMN_NAMES = 
   {"Action", "When Focused", "When In Focused Window", "When Ancestor"};

Enum Type ‹↑›

The enum enumerated data type was introduced into java 1.5 (2004) These are often called enumerations, but are not to be confused with the (oldish) java iterator Enumeration.

an example of using an enumerated type

   enum ElectricalUnits {
     AMPS("Amps"), OHMS("Ohms"), WATTS("Watts"), VOLTS("Volts");
     private String text;
     private ElectricalUnits(String text) {
       this.text = text;
     }
     public String getText() {
       return text;
     }
     @Override
     public String toString() {
       return text;
     }
   }

Primitive Types ‹↑›

In java certain data types are not (considered) proper classes and are referred to as 'Primitive Types'. Since these data types are not classes they do not need nor can be instantiated with the 'new' keyword. Each of the primitives types also has a wrapper class which can be used to perform common tasks.

Strangely these types do have a class which can be got with eg int.class double.class etc.

Access modifiers
static - initialised at compile time no object instance required
final - cannot be changed (similar to 'const' in c?)
public - can be used by another class
private - can only be used by the declaring class
protected - dont know about this one.

check if the field of a class is an 'int' primitive type

 if (field.getType().equals(int.class)) { ... }

Classes ‹↑›

Possibly the simplest compilable class

    public class Minimal {} 

a simple class with a constructor

    public class Name {
      public String first;
      public String last;

      public Name(String f, String l) {
        this.first = f; this.last = l;
      }
   }

another simple class with a constructor

    public class Name {
      private String first;
      private String last;

      public Name(String f, String l)
        { this.first = f; this.last = l; }

      public void print()
        { System.out.println(this.first + " " + this.last); }

      public static void main(String[] args) {
        Name t = new Name("Bill", "King");
        t.print();
      }
    }

Constructors ‹↑›

Constructors are the special method or function which creates a new object instance of a particular class.

When we extend a class we have to reimplement any constructors we want to use, but it is not necessary to reimplement methods.

an empty constructor doesnt seem necessary

 public DashStroke() {}

a private constructor is a way of preventing direct use (Factories etc)

 private DashStroke() {}

make 2 object contructors, one using this() and a default value

    public FileSystemModel() { 
      this(System.getProperty("user.home")); }

    public FileSystemModel( String startPath ) {
        root = startPath;
    }

Methods ‹↑›

a simple method declaration and body

    public string getAge(String name)
    {
      return this.age;
    }

!!! method names cant be reserved words ('do', 'while' etc)

 public void print() {}
 public boolean print() {}
 public String print(int i, double d) {}
 private static int[] doo() {}
 public static int doo(int i) {}
 public static void doo(char c) {}

Static Methods ‹↑›

A static method is the equivalent of a function in a procedural programming language. A static method can be invoked without any object being instantiated

use a static method of the 'Search' class to search for "tree"

 Search.start("tree");

Recursive Methods ‹↑›

Recursion is a potentially powerful technique. It involves a method which calls itself after or before performing some task. Recursion is often useful when dealing with heirarchical or 'tree' data structures (such as the file-system).

Infinite recursion compiles but produces a stack overflow error.

Subclasses And Inheritance ‹↑›

One of the cornerstones of Object Oriented programming is the idea of inheritance, or creating a subclass from an existing class. The purpose of subclassing is to take advantage of all the functionality and data modeling of the parent or ancestor class, and add to or modify a small amount of that functionality. The majority or all of the code of the parent class is in this way reused.

The process of inheriting from a class is also known as 'extending' a class.

create a class 'Circle' which inherits from the 'Shape' class

 public class Circle extends Shape {}

Interestingly, when we create a subclass we are not obliged to add or modify any functionality of the ancestor class. The following example compiles and produces a class 'TextPanel' which is identical to the JPanel class, but has no constructors so that you cant actually use it for anything.

create a subclass of a swing JPanel, but dont modify anything -------- import javax.swing.*; public class TextPanel extends JPanel {} ,,,

Inner Classes ‹↑›

Inner classes are full class definitions which ocurr inside the body of another class.

refer to method load() of outer class (ImageProcess) in inner class

 ImageProcess.this.load()

refer to member field 'text' of outer class (Glue) in inner class

 Glue.this.text
 text   the same, no qualifiers are necessary

Abstract Classes ‹↑›

Abstract classes are classes which need to be subclassed before they can be used. Unlike interfaces, abstract classes may contain implementations of various methods and member variables, but this code is necessarily incomplete, and it is the job of the subclass to provide the missing code.

It is generally considered less 'work' for the programmer to subclass an abstract class than implement an interface.

Anonymous Classes ‹↑›

Anonymous classes have no class name, and sometimes they dont even have an object name. But how do you define constructors for a class that has no name? The answer is to create a method with no name. In other words, just "{ /* constructor */ }". How odd.

Anonymous classes may be a terse way to implement functionality, and can be an alternative to an inner class but are somewhat less readable than inner classes.

write a constructor in an anonymous AbstractAction class

   Action colourAction = new AbstractAction() {
     { putValue(Action.NAME, "Green On Black"); }
     public void actionPerformed(ActionEvent e)
     { /* do something */ }
   };

an anonymous KeyAdapter (sub) class with no object name

  jpanel.addKeyListener(new KeyAdapter() {
    public void keyTyped(KeyEvent e) { /* do something */ }
  });

Interfaces ‹↑›

An interface is a powerful concept. An interface may be described as a 'contract' which a class must fulfill, or else a 'role' which it must play, or else a 'protocol' which is must obey. Whatever the language used, it is easiest to understand them by using them.

When implementing an interface, the parameter names are not important, only the parameter type. Empty implementations of methods are also ok if the return type is void.

an empty implementation of an interface method

 public void sequenceComplete(ImageReader r) {}

Objects ‹↑›

An object is an instance of a class which has been created (that is: allocated memory, and initialized). Objects in java are created with the 'new' keyword and one of the classes constructors.

check if an object is an instance of a class

BufferedImage bufImg = null; if (origImage instanceof BufferedImage) { bufImg = (BufferedImage) origImage; } else { bugImg = new BufferedImage(...); } ,,,

create a new JTextArea and cast to a JComponent

  Object o = Class.forName("javax.swing.JTextArea").newInstance();
  component = (JComponent)o;

Casting Objects ‹↑›

cast an object to a subclass and call a method on the new type

 ((Graphic2D) g).setRenderingHints(...);

Beans Or Javabeans ‹↑›

java.beans.* package.

Java beans are a type of java class conforming to certain restrictions which allow them to be used in contexts like graphical interface builder tools. The most well know requirement is that javabeans must have 'getter' and 'setter' methods for all public member fields.

Java beans may have gone the same way as applets.

Reflection ‹↑›

Reflection allows a program to find out information about java classes. This is also known as 'introspection' and allows a program at run-time to find out what methods a particular class or object has.

www: http://java.sun.com/developer/technicalArticles/ALT/Reflection/
a good article about using reflection with java

Class Objects ‹↑›

The first step when using java reflection is to obtain a reference to the Class object for the class which you wish to inspect, invoke or modify. There are several ways to obtain this Class object.

The 8 Java primitive types
byte
char -
short
int -
long -
double -
float
boolean -

create a new JTextArea and cast to a JComponent

    Object o = Class.forName("javax.swing.JTextArea").newInstance();
    JComponent c = (JComponent) o;

Interestingly in the 2 examples below, the getClass() method does not return 'Object' as the class name, but rather the most specific Class name.

get the specific class name

 Object o = ...; String s = o.getClass().getName();

a complete example of getting the specific class name of an object

   import javax.swing.*;
   public class ObjectClassName {
     public static void main(String[] args) {
       java.util.Enumeration keys = UIManager.getDefaults().keys();
       while (keys.hasMoreElements()) {
         String key = keys.nextElement().toString();
         Object value = UIManager.get(key);
         if (value != null) {
           String className = value.getClass().getName();
           System.out.println(key + ":" + className);
         }
       }
     }
   }

Main Application Class ‹↑›

The main application class is the class containing the static 'main' method which is first executed when the java application is run.

get information about the main application class

    import java.net.URL;
    public class MainName {
      public static void main(String[] args) throws Exception {
        URL main = Main.class.getResource("Main.class");
        System.out.format(
          "Main protocol: %s \nMain path: %s \nMain url: %s", 
          main.getProtocol(),
          main.getPath(),
          main.toString());
      }
    }

determine if the main class is within a jar file

    import java.net.URL;
    public class MainName {
      public static void main(String[] args) throws Exception {
        URL main = Main.class.getResource("Main.class");
        if (main.getProtocol().equals("jar"))
          System.out.println("yes: main in jar");
        else 
          System.out.println("no: main not in jar");
      }
    }

Fields ‹↑›

A java.lang.reflect.Field represents the member field of some class.

get all public and private fields from the Color class

 Field[] fields = Color.class.getDeclaredFields();

get all public fields from the Color class

 Field[] fields = Color.class.getFields();

check if a field is public

 if (Modifier.isPublic(field.getModifiers())) { ... }

check if a field is of type 'int'

 if (field.getType().equals(int.class))
Different ways to obtain a Class object
Class c = new Color().getClass() - get class from an object
Class c = class.forName("java.lang.String") - throws Exception
Class c = JPanel.class - get a class from the class name

The technique below has a practical use: since most java api classes dont use enum types to declare static fields, there is no simple way to loop through the fields.

display the public and private fields for the Color class

   import java.lang.reflect.*;
   public class ColorFields {
     public static void main(String args[]) {
        for (Field f: java.awt.Color.class.getDeclaredFields())
          System.out.println(f);
     }
   }

display the public fields for the Color class

   import java.lang.reflect.*;
   public class ColorFields {
     public static void main(String args[]) {
        for (Field f: java.awt.Color.class.getFields())
          System.out.println(f);
     }
   }

The technique below has applications in many different java api classes.

display the public static fields of type Color within the Color class

   import java.lang.reflect.*;
   import java.awt.Color;
   public class ColorFields {
     public static void main(String args[]) {
       for (Field f: Color.class.getFields()) {
         if (f.getType().equals(Color.class) && 
             Modifier.isStatic(f.getModifiers())) {
            System.out.println(f);
         }
       }
     }
   }

show information about the public fields for the Color class

   import java.lang.reflect.*;
   public class ColorFields {
     public static void main(String args[]) {
        for (Field f: java.awt.Color.class.getFields()) {
          System.out.println(f);
          System.out.format(
            "field.getName(): %s \n" +
            "field.getType(): %s \n", f.getName(), f.getType());
        }
     }
   }

a method to return all static integer fields of a Color class

   public static Integer[] getStaticFields(Class<Color> c) {
     List<Integer> list  = new ArrayList<Integer>();
     Field[] fields = c.getDeclaredFields();
     for (Field field : fields) {
       try {
         if (field.getType().equals(int.class) && 
             Modifier.isStatic(field.getModifiers())) {
           list.add(field.getInt(null));
         }
       }
       catch (IllegalAccessException e) { /* handle */ }
     }
     return list.toArray(new Integer[list.size()]);
   }

Field Values ‹↑›

get the value of a static field (then cast the Object to something)

 Object o = field.get(null);

get the value of a static field which is a Color value

 Color c = (Color)field.get(null);

get the value of the first field from the 'text' object

 Field f = text.getClass().getFields()[0]; Object o = field.get(text);

Display Methods ‹↑›

We can use reflection to find out and display all the methods, whether public or private which belong to a particular class.

display the public methods for the 'String' class including inherited

   import java.lang.reflect.*;
   public class Test 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Class.forName("java.lang.String");
        Method m[] = c.getMethods();
        for (int i = 0; i < m.length; i++)
          System.out.println(m[i]);
     }
   }

display public and private methods declared in the 'String' class

   import java.lang.reflect.*;
   public class Test 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Class.forName("java.lang.String");
        Method m[] = c.getDeclaredMethods();
        for (int i = 0; i < m.length; i++)
          System.out.println(m[i]);
     }
   }

getDeclaredMethods() does not display methods inherited from superclasses. Use getMethods() to display all available methods

display the public methods for the 'String' class in a list box

   import java.lang.reflect.*;
   import javax.swing.*;
   public class PublicMethodsTest 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Class.forName("java.lang.String");
        Method mm[] = c.getMethods();
        Object r = JOptionPane.showInputDialog(
          null, "Choose a method:", "Methods",
          JOptionPane.PLAIN_MESSAGE, null, mm, mm[0]);
        System.out.println( "value selected: " + r );
     }
   }

The application below may become a useful way of inspecting a class.

display constructors, methods for a class named in a JTextField

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.lang.reflect.*;
    public class MethodPanel extends JPanel implements ActionListener {
      JList list;
      DefaultListModel model;
      JTextField box;
      String className;
      public MethodPanel(String className) {
        super(new BorderLayout());
        this.className = className;
        this.box = new JTextField(className);
        this.box.setFont(new Font("Georgia", Font.PLAIN, 24));
        this.box.addActionListener(this);
        this.add(this.box, BorderLayout.NORTH);
        this.model = new DefaultListModel();
        this.setListData();
        this.list = new JList(this.model);
        this.list.setFont(new Font("Georgia", Font.PLAIN, 20));
        this.list.setForeground(Color.darkGray);
        this.list.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
        JScrollPane scroll = new JScrollPane(list);
        scroll.setBorder(null);
        this.add(scroll, BorderLayout.CENTER);
        this.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
      }

      public void setListData() {
        this.model.removeAllElements();
        try {
          Class c = Class.forName(this.className);
          Constructor co[] = c.getConstructors();
          for (int i = 0; i < co.length; i++)
            this.model.addElement(
              co[i].toString()
                .replace("public ", "").replace("java.lang.", "") 
                .replace(this.className + ".", "")
            );
          Method mm[] = c.getMethods();
          for (int i = 0; i < mm.length; i++)
            this.model.addElement(
              mm[i].toString()
                .replace("public ", "").replace("java.lang.", "") 
                .replace(this.className + ".", "")
            );
        }
        catch (ClassNotFoundException e) { 
          this.model.addElement(
            String.format("class '%s' not found", this.className)); 
        }
      }

      public void actionPerformed (ActionEvent e) {
        if (e.getSource() == this.box) {
          this.className = this.box.getText().trim();
          this.setListData();
        }
      }
  
      public static void main(String[] args) throws Exception {
        MethodPanel p = new MethodPanel("javax.swing.DefaultListModel");
        JFrame f = new JFrame("showing methods");
        f.add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); 
        f.setExtendedState(Frame.MAXIMIZED_BOTH);
        f.setVisible(true);
      }
    }

display all the public methods for the current class

   import java.lang.reflect.*;
   import javax.swing.*;
   public class Test 
   {
     public static void main(String args[]) throws Exception
     {
        Test t = new Test();
        Class c = t.getClass();
        Method mm[] = c.getMethods();
        Object r = JOptionPane.showInputDialog(
          null, "Choose method:", "Methods", JOptionPane.PLAIN_MESSAGE, 
          null, mm, mm[0]);
        System.out.println( "Method selected was: " + r );
     }
   }

display all the methods for the 'Integer' class

   import java.lang.reflect.*;
   public class Test 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Integer.TYPE;
        Method m[] = c.getMethods();
        for (int i = 0; i < m.length; i++)
          System.out.println(m[i].toString());
     }
   }

This does not display any results for me.

display the public method names and return type for the 'Method' class

   import java.lang.reflect.*;
   import javax.swing.*;
   import java.awt.GridLayout;
   public class MethodGrid 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Class.forName("java.lang.reflect.Method");
        JPanel p = new JPanel(new GridLayout(0, 2));
        Method m[] = c.getMethods();
        for (int i = 0; i < m.length; i++)
        {
         p.add(new JLabel(m[i].getName()));
         p.add(new JLabel(m[i].getReturnType()+""));
        }
        JFrame f = new JFrame("A panel which can scroll");
        f.add(new JScrollPane(p));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setVisible(true);
     }
   }

display a list of methods with checkboxes for the 'URL' class

  import java.lang.reflect.*;
  import javax.swing.*;
  import java.awt.GridLayout;
  public class Test {
    public static void main(String[] args) throws Exception
    {
       JFrame f = new JFrame("Methods with checkboxes for 'URL'");
       JPanel p = new JPanel(new GridLayout(0,1));
       Class c = Class.forName("java.net.URL");
       Method mm[] = c.getDeclaredMethods();
       for (int ii = 0; ii < mm.length; ii++)
       {
         p.add(new JCheckBox(mm[ii].toString()));
       }
       f.getContentPane().add(new JScrollPane(p));
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
    }
  }

 if (field.getType() == int.class) {}   Another way to do the same

display the constructors for the 'String' class

   import java.lang.reflect.*;
   public class Test 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Class.forName("java.lang.String");
        Constructor co[] = c.getDeclaredConstructors();
        for (int i = 0; i < co.length; i++)
         System.out.println(co[i].toString());
     }
   }

display all the field variables for the 'String' class

   import java.lang.reflect.*;
   public class Test 
   {
     public static void main(String args[]) throws Exception
     {
        Class c = Class.forName("java.lang.String");
        Field f[] = c.getDeclaredFields();
        for (int i = 0; i < f.length; i++)
         System.out.println(f[i].toString());
     }
   }

Method Information ‹↑›

Reflection allows us to get lots of information about each method in a class, such as whether it is public, its return type etc

check if a method is static

 if (Modifier.isStatic(method.getModifiers())) { ... }

check if the return type of a method is void

useful methods of the Method class
m.getParameterTypes() - the types of all the method parameters
m.getDeclaringClass() - the class which declared the method
m.getReturnType() - type of object returned by the method

check if a method is public

 if (Modifier.isPublic(method.getModifiers())) { ... }

check if a method is a valid 'main' method for a class

   int mods = m.getModifiers();
   if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
       !Modifier.isPublic(mods)) {
     throw new NoSuchMethodException("main");
   }

Executing Methods ‹↑›

Java reflection is not only 'introspection' (the ability to find out what methods and constructors exist) but also the capability to invoke or execute those methods with parameters.

execute a method with parameters

   try {
     m.invoke(null, new Object[] { args });
   } catch (IllegalAccessException e) {}

Class Listings ‹↑›

It seems impossible using normal reflection, or introspection to get a list of class names contained in a given package. However we can get a list by inspecting the runtime jar file 'rt.jar' or the java api documentation or by inspecting the source code.

The runtime file rt.jar resides at lib/rt.jar in the "java.home" folder. Listing the rt.jar will show 'internal' sun java classes which should not actually be used by an application since other java platforms (runtime engines & class api) may not have these classes

search the class files in the rt.jar for a class name

   import java.util.jar.*;
   import java.util.zip.*;
   import java.io.*;
   import java.util.Enumeration;
   import javax.swing.*;
   import java.awt.*;
   public class ListRuntimeJar extends JPanel {
     private JList list;
     private String className;
     public ListRuntimeJar(String className) {
       super();
       this.className = className;
       this.list = new JList(new DefaultListModel());
       this.list.setFont(new Font(Font.SERIF, Font.PLAIN, 22));
       try {
         JarFile jar = new JarFile(
           new File(System.getProperty("java.home") + "/lib/rt.jar"));
         Enumeration<? extends JarEntry> enumeration = jar.entries();
         while (enumeration.hasMoreElements()) {
           ZipEntry zipEntry = enumeration.nextElement();
           if (zipEntry.getName().endsWith(className + ".class")) {
             ((DefaultListModel)this.list.getModel())
               .addElement(zipEntry.getName());
           }
         }
       } catch (IOException e) {}
       this.add(new JScrollPane(this.list));
     }
     public static void main(String[] args) throws Exception {
       SwingUtilities.invokeLater( new Runnable() {
        public void run() {
           ListRuntimeJar l = new ListRuntimeJar("ZipEntry");
           JOptionPane.showMessageDialog(null, new JScrollPane(l));
        }
      });
     }
   }

get a list of full java class names from the java api docs

   import java.io.*;
   import java.util.*;
   public class ClassNames {
     List classNames;
     File apiDocFolder;
     public ClassNames() {
       this.classNames = new ArrayList();
     }
     public void list(File dir) {
       FileFilter filter = new FileFilter(){
         public boolean accept(File file) {
           if (file.getAbsolutePath().indexOf("class-use") > 0) 
             return false;
           if (file.getAbsolutePath().indexOf("package-") > 0) 
             return false;
           if (file.getAbsolutePath().indexOf("doc-files") > 0) 
             return false;
           return (file.getAbsolutePath().endsWith(".html") || 
                    file.isDirectory());
         }
       };
       File[] files = dir.listFiles(filter);
       if (files != null) {
         for (File f : files) {
           if (f.isDirectory()) { this.list(f); }
           else {
             System.out.println(
               f.getPath()
                .replaceAll("/usr/lib/jvm/java-6-sun/docs/api/","")
                .replaceAll("[.]html","")
                .replace('/','.'));
           }
         }
       }
     }
     public static void main(String[] args) throws Exception {
       ClassNames cn = new ClassNames();
       cn.list(new File("/usr/lib/jvm/java-6-sun/docs/api/java"));
       cn.list(new File("/usr/lib/jvm/java-6-sun/docs/api/javax"));
     }
   }

put all java. and javax. class names into a JList component

   import java.io.*;
   import java.awt.Font;
   import java.util.*;
   import javax.swing.*;
   public class ClassList extends JList {
     List classNames;
     String apiDocFolder;
     public ClassList(String apiDocFolder) {
       super();
       this.setModel(new DefaultListModel());
       this.setFont(new Font("Georgia", Font.PLAIN, 18));
       this.classNames = new ArrayList();
       this.apiDocFolder = apiDocFolder;
       this.search(new File(this.apiDocFolder + "/java"));
       this.search(new File(this.apiDocFolder + "/javax"));
     }
     public void search(File dir) {
       FileFilter filter = new FileFilter(){
         public boolean accept(File file) {
           if (file.getAbsolutePath().indexOf("class-use") > 0) 
             return false;
           if (file.getAbsolutePath().indexOf("package-") > 0) 
             return false;
           if (file.getAbsolutePath().indexOf("doc-files") > 0) 
             return false;
           return (file.getAbsolutePath().endsWith(".html") || 
                    file.isDirectory());
         }
       };
       File[] files = dir.listFiles(filter);
       String sName = new String();
       DefaultListModel lm;
       if (files != null) {
         for (File f : files) {
           if (f.isDirectory()) { this.search(f); }
           else {
             sName =
               f.getPath()
                .replaceAll("/usr/lib/jvm/java-6-sun/docs/api/","")
                .replaceAll("[.]html","")
                .replace('/','.');
             this.classNames.add(sName);
             lm = (DefaultListModel)this.getModel();
             lm.addElement(sName);
           }
         }
       }
     }
     public static void main(String[] args) throws Exception {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           ClassList c = new ClassList("/usr/lib/jvm/java-6-sun/docs/api");
           JOptionPane.showMessageDialog(null, new JScrollPane(c));
        }
      });
     }
   }

todo: create a JCombobox with java class names and searchable

   import java.io.*;
   import java.awt.Font;
   import java.util.*;
   import javax.swing.*;
   public class ClassList extends JList {
     List classNames;
     String apiDocFolder;
     public ClassList(String apiDocFolder) {
       super();
       this.setModel(new DefaultListModel());
       this.setFont(new Font("Georgia", Font.PLAIN, 18));
       this.classNames = new ArrayList();
       this.apiDocFolder = apiDocFolder;
       this.search(new File(this.apiDocFolder + "/java"));
       this.search(new File(this.apiDocFolder + "/javax"));
     }
     public void search(File dir) {
       FileFilter filter = new FileFilter(){
         public boolean accept(File file) {
           if (file.getAbsolutePath().indexOf("class-use") > 0) 
             return false;
           if (file.getAbsolutePath().indexOf("package-") > 0) 
             return false;
           if (file.getAbsolutePath().indexOf("doc-files") > 0) 
             return false;
           return (file.getAbsolutePath().endsWith(".html") || 
                    file.isDirectory());
         }
       };
       File[] files = dir.listFiles(filter);
       String sName = new String();
       DefaultListModel lm;
       if (files != null) {
         for (File f : files) {
           if (f.isDirectory()) { this.search(f); }
           else {
             sName =
               f.getPath()
                .replaceAll("/usr/lib/jvm/java-6-sun/docs/api/","")
                .replaceAll("[.]html","")
                .replace('/','.');
             this.classNames.add(sName);
             lm = (DefaultListModel)this.getModel();
             lm.addElement(sName);
           }
         }
       }
     }
     public static void main(String[] args) throws Exception {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           ClassList c = new ClassList("/usr/lib/jvm/java-6-sun/docs/api");
           JOptionPane.showMessageDialog(null, new JScrollPane(c));
        }
      });
     }
   }

Reflection Apps ‹↑›

This section may contain some useful small applications for getting information about classes.

The following is a development on the MethodPanel class, hopefully more useful.

In the following we need to sort out what the actioncommand is when the combobox elements are changed. Too many events are firing. The program below is useful to see the methods and constructors for a class, and search for the class in the rt.jar file, but it needs alot of refining.

It can be used from the command line with

 java ClassInfo <searchclass>

select a class to display constructors and methods

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.lang.reflect.*;
    import java.util.jar.*;
    import java.util.zip.*;
    import java.io.*;
    import java.awt.*;
    import java.util.Enumeration;
    public class ClassInfo extends JPanel implements ActionListener {
      JList list;
      DefaultListModel model;
      JComboBox box;
      String className;
      String filterName; 
      public ClassInfo(String filterName) {
        super(new BorderLayout());
        this.filterName = filterName;
        this.className = new String(" ");
        this.box = new JComboBox(new DefaultComboBoxModel());
        this.box.setEditable(true);
        this.box.setFont(new Font("Georgia", Font.PLAIN, 24));
        this.add(this.box, BorderLayout.NORTH);
        this.model = new DefaultListModel();
        this.list = new JList(this.model);
        this.list.setFont(new Font("Georgia", Font.PLAIN, 20));
        this.list.setForeground(Color.darkGray);
        this.list.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
        this.setComboItems();
        this.box.addActionListener(this);
        JScrollPane scroll = new JScrollPane(list);
        scroll.setBorder(null);
        this.add(scroll, BorderLayout.CENTER);
        this.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
      }

      public void setComboItems() {
       this.box.removeAllItems();
       String name = new String();
       int index = 0;
       try {
         JarFile jar = new JarFile(
           new File(System.getProperty("java.home") + "/lib/rt.jar"));
         Enumeration<? extends JarEntry> enumeration = jar.entries();
         while (enumeration.hasMoreElements()) {
           ZipEntry zipEntry = enumeration.nextElement();
           name = zipEntry.getName().replace(".class", "")
              .replace("/", ".");
           //if (name.startsWith("com.") || name.startsWith("sun."))
           //  continue;

           if (name.endsWith(this.filterName)) {
             this.box.addItem(name);
           }
           if (name.matches(this.filterName)) {
             this.box.addItem(name);
           }


         }
       } catch (IOException e) {}
       // this is throwing an exception because the box is not visible
       //this.box.showPopup();
       //this.box.setSelectedIndex(index);
      }

      public void setListData() {
        this.model.removeAllElements();
        if (this.className == null) return;
        try {
          Class c = Class.forName(this.className);
          Constructor co[] = c.getConstructors();
          for (int i = 0; i < co.length; i++)
            this.model.addElement(
              co[i].toString()
                .replace("public ", "").replace("java.lang.", "") 
                .replace(this.className + ".", "")
            );
          Method mm[] = c.getMethods();
          for (int i = 0; i < mm.length; i++)
            this.model.addElement(
              mm[i].toString()
                .replace("public ", "").replace("java.lang.", "") 
                .replace(this.className + ".", "")
            );

        }
        catch (ClassNotFoundException e) { 
          this.model.addElement(
            String.format("class '%s' not found", this.className)); 
        }
      }

      public void actionPerformed (ActionEvent e) {
        if (e.getSource() == this.box) {
          if ("comboBoxEdited".equals(e.getActionCommand())) {
            this.filterName = (String)this.box.getSelectedItem();
            this.setComboItems();
          }
          else if ("comboBoxChanged".equals(e.getActionCommand())) {
            System.out.println("action command=" + e.getActionCommand());
            this.className = (String)this.box.getSelectedItem();
            this.setListData();
          }
        }
      }
  
      public static void main(String[] args) throws Exception {
        String filter;
        if (args.length > 0)
          filter = args[0];
        else
          filter = "ImageReader";
        ClassInfo p = new ClassInfo(filter);
        JFrame f = new JFrame("Information About Classes");
        f.add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
        f.setVisible(true);
      }
    }

Class Loaders ‹↑›

We can use a class loader such as java.net.URLClassLoader or along with the java.lang.reflect.Method.invoke(...) method to load and execute methods on classes at runtime.

load a class at runtime

    File outputDir = new File("c:/bin");
    URL[] urls = new URL[]{outputDir.toURL()};
    URLClassLoader ucl = new URLClassLoader(urls, cl);
    Class clazz = ucl.loadClass("com.juixe.Entity");

load and execute a class with URLClassLoader and method.invoke()

   import java.net.URL;
   import java.net.URLClassLoader;
   import java.lang.reflect.Method;
   import java.lang.reflect.Modifier;
   import java.lang.reflect.InvocationTargetException;
   public class LoadClass {
     public static void main(String[] args) throws Exception {
       URL url = new URL("file:MethodPanel.class");
       URLClassLoader cl = new URLClassLoader(new URL[] {url});
       Class c = cl.loadClass("MethodPanel");
       Method m = c.getMethod("main", new Class[] { args.getClass() });
       m.setAccessible(true);
       // check for valid java 'main' method
       int mods = m.getModifiers();
       if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
           !Modifier.isPublic(mods)) {
         throw new NoSuchMethodException("main");
       }
       try {
         m.invoke(null, new Object[] { args });
       } catch (IllegalAccessException e) {
         // This should not happen, as we have disabled access checks
       }
     }
   }

Serialization Of Objects ‹↑›

The serialization of objects is a way to turn the state of an object in memory (in the java virtual machine) into a stream which can then be written to a permanent data storage device. In other words serialization allows the programmer to save the state of objects.

Not all objects are serializable: for example Thread or streams

http://java.sun.com/developer/technicalArticles/Programming/serialization/ An chatty article about serialization

a simple serialisable object and code to write the object to file

   import java.io.ObjectOutputStream;
   import java.io.FileOutputStream;
   import java.io.IOException;
   import java.io.Serializable;
   import java.util.Date;
   import java.util.Calendar;
   public class PersistentTime implements Serializable
   {
     private Date time;
     public PersistentTime() {
       time = Calendar.getInstance().getTime();
     }
   
     public Date getTime() { return time; }
     public static void main(String [] args) {
       String filename = "time.ser";
       if (args.length > 0) { filename = args[0]; }
       PersistentTime time = new PersistentTime();
       FileOutputStream fos = null;
       ObjectOutputStream out = null;
       try
       {
         fos = new FileOutputStream(filename);
         out = new ObjectOutputStream(fos);
         out.writeObject(time);
         out.close();
       }
       catch (IOException ex)
       {
         ex.printStackTrace();
       }
     }
   }

restore an object saved with serialization

   import java.io.*;
   import java.util.Calendar;
   public class InflateTime {
     public static void main(String [] args) {
       String filename = "time.ser";
       if (args.length > 0) {
         filename = args[0];
       }
       PersistentTime time = null;
       FileInputStream fis = null;
       ObjectInputStream in = null;
       try {
         fis = new FileInputStream(filename);
         in = new ObjectInputStream(fis);
         time = (PersistentTime)in.readObject();
         in.close();
       }
       catch (IOException ex) {
         ex.printStackTrace();
       }
       catch (ClassNotFoundException ex) {
         ex.printStackTrace();
       }
       // print out restored time
       System.out.println("Flattened time: " + time.getTime());
       System.out.println();
       // print out the current time
       System.out.println("Current time: " + Calendar.getInstance().getTime());
     }
   }

Memory Usage ‹↑›

Java has 2 main memory areas: the heap memory and the stack memory. The heap is the area where objects are created. If you create a lot of large objects (say loaded BufferedImages) then you may run out of heap space. The stack memory area is where local variables and references to method calls are placed when a new method is executed. If you have very deeply nested method calls (using recursion for example) you may run out of stack memory space)

set the minimum heap size to 64m and the maximum to 256megabytes

 java -Xms64m -Xmx256m ..

The default value for the minimum is 2Mb, for the maximum it's 64Mb.

find out how much memory is available and free in a java program

   Runtime rt = Runtime.getRuntime();
   long freeMemory = rt.freeMemory();
   long totalMemory = rt.totalMemory();

Performance Of Java Programs ‹↑›

The performance of the java runtime engine has long been something of a sore point. One can often increase the users perception of the performance of an application by performing tasks in the background using thread.

In the following FileFilter accept method the commented out code was about 25% slower than the uncommented code. This is perhaps owing to the fact that the majority of Files were not directories.

return efficiently from a FileFilter accept method

   public boolean accept(File file) {
     /*
     if (file.isDirectory()) return true;
     if (file.getAbsolutePath().indexOf(this.text)>0) return true;
     return false;
     */
     return ((file.getAbsolutePath().indexOf(this.text)>0) ||
             file.isDirectory());
   }

Running Java Programs ‹↑›

Command Line Arguments ‹↑›

Command line arguments are strings typed after the name of the java class or application, for example in

 java ViewImage tree.jpg
The first command line argument (args[0]) is 'tree.jpg'

use the first command line argument, or provide a default

    if (args.length > 0)
      testData = new StringSelection( args[0] );
    else
      testData = new StringSelection( "Test Data" );

Compiling Java Programs ‹↑›

compile and run a java program

 javac Test.java
 java Test

In the example below the class Symbol in the file Symbol.java is not in a any package.

compile file ./eg/Symbol.java which depends on other classes in eg/

 javac -cp eg eg/Symbol.java

Compiling With Packages ‹↑›

Packages are a way of organising classes.

compile and run a single java file in package (and folder) greetings

    % cat greetings/Hello.java
    package greetings;
    public class Hello {
      public static void main(String[] args) {
        for (int i=0; i < args.length; i++) {
          System.out.println("Hello " + args[i]);
        }
      }
    }
    % javac greetings/Hello.java
    % ls greetings
    Hello.class   Hello.java
    % java greetings.Hello World Universe Everyone

Cross Compilation ‹↑›

In this context we mean compiling for older jre's using a newer javac version. This is important for deploying an application on the web where browsers may have older versions of the jre plugin installed

compile some code for jre version 1.5 with 1.5 class library

 javac -target 1.5 -bootclasspath jdk1.5.0/lib/rt.jar -extdirs "" OldCode.java

The above requires that the old jdk 'rt.jar' file is present on the local computer

try: compile code for jre version 1.5 from newer, without checking api

 javac -target 1.5 OldCode.java

The above code is not tested and will not check if the code in question uses java classes which were not available in the jre version specified. In other words the code may compile but fail to run on the old (1.5) jre.

Runtime Compiling Of Java Code ‹↑›

Around about java 1.6 an api (in the javax.tools.* package) was added to java to allow a java program to compile a java source code contained in a file, string, or anything else.

http://www.javabeat.net/2007/04/the-java-6-0-compiler-api/ a very good article about doing this

http://juixe.com/techknow/index.php/2006/12/13/java-se-6-compiler-api/ another article about this

create a list of files to compile

   File f1, f2, f3; ...
   Iterable<? extends JavaFileObject> list = 
     fm.getJavaFileObjects(f1, f2, f3);

another way to create the list of files to compile

   File[] files = {new File(...), new File(...)};
   Iterable<? extends JavaFileObject> compileList =
     fm.getJavaFileObjectsFromFiles(Arrays.asList(files));

In the example below, the class file is placed in the same folder as the source file (in this case 'eg/Test.java'). If the compilation fails, then the compiler (javac) prints message to standard-out or standard-error.

Apparently the jdk is required for the example below to work because it accesses the tools.jar file in the jdk lib/tools folder...

a simple programmatic compiling example

   import javax.tools.*;
   public class SimpleCompiler {
     public static void main(String[] args) {
       String fileToCompile = "Test.java";
       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
       int compilationResult = 
         compiler.run(null, null, null, "eg/Test.java");
       if (compilationResult == 0) {
         System.out.println("Compilation is successful");
       } else {
         System.out.println("Compilation Failed");
       }
     }
   }
   // the class that will be compiled
   class Test {
     public void myMethod() {
       System.out.println("My Method Called");
     }
   }

The getJavaFileObjects() parameter is a vararg (variable number of arguments)

If there are errors during the compilation below, they will be printed to 'standard-error'. The code Arrays.asList(options) is necessary because a String array is not regarded as Iterable, which seems strange.

compile java code specifying (command-line) options to the compiler

   import javax.tools.*;
   import java.net.*;
   import java.io.*;
   import java.util.Arrays;
   public class ApiCompiler {
     public static void main(String[] args) throws IOException {
       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
       StandardJavaFileManager fm = 
         jc.getStandardFileManager(null, null, null);
       File sourceFile = new File("eg/Test.java");
       Iterable<? extends JavaFileObject> compileList = 
         fm.getJavaFileObjects(sourceFile);
       String[] options = new String[] {"-d", "."};
       jc.getTask(null, fm, null, Arrays.asList(options), null, compileList)
         .call();
       /* Add more compilation tasks if required */
       fm.close();
     }
   }

The example below takes advantage of the fact that the fm.getJavaFileObjects(...) has a 'vararg' parameter, meaning that it can take a variable number of parameter arguments, and can take either a list of Strings or a list of Files

compile 2 java source files in the same compiler task

   import javax.tools.*;
   import java.net.*;
   import java.io.*;
   import java.util.Arrays;
   public class TwoFileCompiler {
     public static void main(String[] args) throws IOException {
       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
       StandardJavaFileManager fm = 
         jc.getStandardFileManager(null, null, null);
       Iterable<? extends JavaFileObject> compileList = 
         fm.getJavaFileObjects("eg/Test.java", "eg/SumArray.java");
       jc.getTask(null, fm, null, null, null, compileList)
         .call();
       /* Add more compilation tasks if required */
       fm.close();
     }
   }

The example below might be useful when building some kind of java code editor: the user can jump to the line number where the error occurs.

compile a java file and print 'diagnostics' (errors and warnings)

   import javax.tools.*;
   import java.net.*;
   import java.io.*;
   import java.util.Arrays;
   public class ErrorCompiler {
     public static void main(String[] args) throws IOException {
       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
       File[] files = {new File("eg/Test.java")};
       DiagnosticCollector<JavaFileObject> diagnostics =
         new DiagnosticCollector<JavaFileObject>();
       StandardJavaFileManager fm =
         compiler.getStandardFileManager(diagnostics, null, null);
       Iterable<? extends JavaFileObject> compileList =
         fm.getJavaFileObjectsFromFiles(Arrays.asList(files));
       compiler.getTask(null, fm, diagnostics, null, null, compileList)
         .call();
       for (Diagnostic d: diagnostics.getDiagnostics())
         System.out.format(
          "On line %d: (file %s)\n%s\n\n",
          d.getLineNumber(), 
          ((JavaFileObject) d.getSource()).toUri(),
          d.getMessage(null));
       fm.close();
     }
   }

the old way: before java 1.6 compile java code at runtime

   //put tools.jar from the jdk in your classpath,
   com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();
   String[] options = new String[] {
     "-classpath", classpath, "-d", outputDir, filename
   };
   javac.compile(options);

Compiling Strings And Streams ‹↑›

By extending the SimpleJavaFileObject class we can use the javax.tools.JavaCompiler to compile programs that are contained in Strings, streams or other exotic and interesting imaginary spaces. This gives those of us hankering for lisp-like functional languages something to think about.

To compile from a stream, we should extend the SimpleJavaFileObject and somehow convert the url.openStream() method to a CharSequence

In the example below, the 'name' parameter of the StringSource class is important because the java compiler requires that public classes be declared in 'files' with the class name, even if those classes are really contained in Strings, streams or what-not.

compile some java source contained in a String

   import javax.tools.*;
   import java.net.*;
   import java.io.*;
   import java.util.Arrays;
   public class StringCompiler {
     public static void main(String[] args) throws IOException {
       String s = "public class Test1 { String n = 2; }";
       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
       StringSource[] compileList = {new StringSource("Test1", s)};
       jc.getTask(null, null, null, null, null, Arrays.asList(compileList))
         .call();
     }
   }
   /* A file object used to represent java source code in a string.*/
   class StringSource extends SimpleJavaFileObject {
     final String code;
     public StringSource(String name, String code) {
       super(URI.create(
         "string:///" + name.replace('.','/') + Kind.SOURCE.extension),
         Kind.SOURCE);
       this.code = code;
     }
     public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       return code;
     }
   }

compile 2 java sources contained in strings with command-line options

   import javax.tools.*;
   import java.net.*;
   import java.io.*;
   import java.util.Arrays;
   public class TwoStringCompiler {
     public static void main(String[] args) {
       String s = "public class Test1 { String m; }";
       String r = "public class Test2 { String n; }";
       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
       StringSource[] compileList = 
         {new StringSource("Test1", s), new StringSource("Test2", r)};
       String[] options = new String[] {"-d", "."};
       jc.getTask(null, null, null, Arrays.asList(options), null, 
         Arrays.asList(compileList)).call();
     }
   }
   /* A file object used to represent java source code in a string.*/
   class StringSource extends SimpleJavaFileObject {
     final String code;
     public StringSource(String name, String code) {
       super(URI.create(
         "string:///" + name.replace('.','/') + Kind.SOURCE.extension),
         Kind.SOURCE);
       this.code = code;
     }
     public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       return code;
     }
   }

todo: we have to get the class name, and hand it to the StringSource class. Get all the diagnostics, and allow to jump to the line number, Display compiler messages somewhere.

the beginning of an example to compile text in a JTextArea

   import javax.tools.*;
   import java.net.*;
   import java.io.*;
   import java.util.Arrays;
   import javax.swing.*;
   import java.awt.*;
   import java.awt.event.*;
   
   public class TextCompiler extends JPanel {
     JTextArea area;
     public TextCompiler() {
       super(new java.awt.BorderLayout());
       this.area = new JTextArea(20, 60);
       this.area.setFont(new Font("Courier", Font.PLAIN, 20));
       this.add(this.area);
       this.setActionKeys();
       this.skeleton();
     }
     public void setActionKeys() {
       InputMap im = area.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
       ActionMap am = area.getActionMap();
       im.put(KeyStroke.getKeyStroke("control J"), "compile");
       am.put("compile", new CompileAction());
     }
     public void compile() {
       //String s = "public class Test1 { String n = 2; }";
       System.out.println("compiling...");
       String s = this.area.getText(); 
       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
       StringSource[] compileList = {new StringSource("Test", s)};
       jc.getTask(null, null, null, null, null, Arrays.asList(compileList))
         .call();
     }
     /** adds some java skeleton code to the text area */
     public void skeleton() {
       this.area.append("public class Test {\n");
       this.area.append("}\n");
     }
     public static void main(String[] args) {
       JFrame f = new JFrame();
       f.add(new TextCompiler()); f.pack();
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setExtendedState(JFrame.MAXIMIZED_BOTH);
       f.setVisible(true);
     }
     class CompileAction extends AbstractAction {
       public void actionPerformed(ActionEvent ev) {
         compile();
       }
     }
   
   }
   /* A file object used to represent java source code in a string.*/
   class StringSource extends SimpleJavaFileObject {
     final String code;
     public StringSource(String name, String code) {
       super(URI.create(
         "string:///" + name.replace('.','/') + Kind.SOURCE.extension),
         Kind.SOURCE);
       this.code = code;
     }
     public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       return code;
     }
   }

Diagnostics With The Compiler Api ‹↑›

The so-called javax.tools.Diagnostic class encapsulates both errors and warnings which are encountered during compilation. In the sun java implementation the getMessage() method returns the explanatory text (String) which includes the file-name, class name and line number.

Error Messages While Compiling ‹↑›

reached end of file while parsing You've missed a close-bracket somewhere.

Symbol not found: This either means that you have mispelled a java api class name, not included the appropriate import statement for a class which you are using, or, if the Symbol (class name) is a class which you have written, this compiler error message indicates that the class path has not been set properly. The following line will compile Test.java and use classes on which it depends which are located in the 'eg' subfolder.

 javac -cp eg Test.java

Building Projects ‹↑›

For large projects with many source files a build tool is often used to ensure that all files are properly built.

 if (method.getReturnType() == void.class) { ... }

The Maven Central repository maybe the closest things Java has to the Perl cpan repository.

Jar Archives ‹↑›

The 'jar' archive tool is a way to package several java class files and other application resources (such as images ...) in a single zip compressed file. Jar files may also be signed. The actual name of the jar file is not important (unlike java class files). Jar file metadata must be in UTF8 format

Creating Jar Archives ‹↑›

The jar tool will by default also create a manifest file 'manifest.mf' in the 'meta-inf' folder, but you still have to add the 'Main-Class:' field to the manifest.mf file (using a text editor for example) in order to run the jar file as an application with 'java -jar app.jar'

create a jar archive with entry point 'MyApp' (since java 1.6)

 jar cvfe app.jar MyApp MyApp.class

Using the 'e' option to jar avoids the annoying necessity to edit the jar manifest file to add the 'Main-Class:' field.

set the entry point in the manifest file to 'ViewImage' in 'Images' package

 echo "Main-Class: Images.ViewImage" > manifest.txt
 jar cfm MyJar.jar Manifest.txt MyPackage/*

This creates a manifest with:

    Manifest-Version: 1.0
    Created-By: 1.6.0 (Sun Microsystems Inc.)
    Main-Class: Images.ViewImage

do the same thing using the modern 'e' switch

 jar cfe Main.jar foo.Main foo/Main.class

create a jar file 'app.jar' from all .java file in this folder

 jar cf app.jar *.java

This also creates the default manifest file META-INF/MANIFEST.MF

create a jar file 'app.jar' from all .java file in this folder

 jar cf app.jar ViewData.class Utils.class
 echo "Main-Class: ViewData

create a jar file showing verbose information (file names archived ...)

 jar cvf app.jar Main.java Panel.java

create a jar file containing all files and folders in the current one

 jar cvf app.jar *

create an archive of all the files in the 'imorg' folder

 jar cvf app.jar imorg

create a jar including one class file and all files in 'audio' & 'images'

 jar cvf TicTacToe.jar TicTacToe.class audio images

create a jar archive without compressing the files

 jar 0cf app.jar imorg

Uncompressed jar files can be loaded more quickly than compressed ones (improving the startup time of an application or applet)

create a jar archive with an existing manifest file

 jar cmf existing-manifest jar-file input-file(s)

Manifest Files For Jar ‹↑›

The jar manifest file contains meta information. The last line must end with a newline character

tools
Ant -
maven - finds and solves class dependencies
make - the c language tool but maybe useful

Running Jar Applications ‹↑›

run an archived application (need the 'main-class' manifest header)

 java -jar app.jar

run class MethodPane in jar file without using the -jar switch

 java -classpath m.jar MethodPanel

view the contents of a jar file

 jar tf jar-file

a more complicated example with dependencies (on linux use ":" not ";" )

 java -classpath .;myjar.jar;lib/referenced-class.jar my.package.MainClass

Extracting From Jar Archives ‹↑›

jar files are compressed (if they are compressed) in the standard 'zip' format. the Jar tool can be used as a replacement for unzip or gunzip etc.

extract all files from "app.jar"

 jar xf app.jar

extract only some files from a jar archive

 jar xf jar-file archived-file(s)

unzip a normal zip file using the jar tool

 jar xvf jdk-6-doc.zip

Using Jar Files ‹↑›

create a web page with an applet packaged as a jar ------ <html> <applet code=AppletClassName.class archive="JarFileName.jar" width=width height=height> </applet> </html> ,,,

Programatic Use Of Jar Files ‹↑›

To list Jar files one can use either ZipFile and a ZipEntry or their children classes java.util.jar.JarFile and java.util.jar.JarEntry.

convert a jar file to a URL

 JarFile j = new JarFile(new File("x.jar")); j.toURI().toURL()

list the class files in a jar file (the java 'runtime' jar file)

   import java.util.jar.*;
   import java.util.zip.*;
   import java.io.File;
   import java.util.Enumeration;
   public class ListJar {
     public static void main(String[] args) throws Exception {
       JarFile jar = new JarFile(
         new File("/usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/rt.jar"));
       Enumeration<? extends JarEntry> enumeration = jar.entries();
       while (enumeration.hasMoreElements()) {
         ZipEntry zipEntry = enumeration.nextElement();
         if (zipEntry.getName().endsWith(".class")) {
           System.out.println(zipEntry.getName());
         }
       }
     }
   }

create a jar file programmatically with JarOutputStream

   import java.util.jar.*; 
   ...
   public void run() throws IOException
   {
     Manifest manifest = new Manifest();
     manifest.getMainAttributes().put(
       Attributes.Name.MANIFEST_VERSION, "1.0");
     JarOutputStream target = 
       new JarOutputStream(new FileOutputStream("output.jar"), manifest);
     add(new File("inputDirectory"), target);
     target.close();
   }
   
   private void add(File source, JarOutputStream target) throws IOException
   {
     BufferedInputStream in = null;
     try {
       if (source.isDirectory()) {
         String name = source.getPath().replace("\\", "/");
         if (!name.isEmpty()) {
           if (!name.endsWith("/"))
             name += "/";
           JarEntry entry = new JarEntry(name);
           entry.setTime(source.lastModified());
           target.putNextEntry(entry);
           target.closeEntry();
         }
         for (File nestedFile: source.listFiles())
           add(nestedFile, target);
         return;
       }
   
       JarEntry entry = new JarEntry(source.getPath().replace("\\", "/"));
       entry.setTime(source.lastModified());
       target.putNextEntry(entry);
       in = new BufferedInputStream(new FileInputStream(source));
   
       byte[] buffer = new byte[1024];
       while (true) {
         int count = in.read(buffer);
         if (count == -1) break;
         target.write(buffer, 0, count);
       }
       target.closeEntry();
     }
     finally {
       if (in != null) in.close();
     }
   }

Jar Api ‹↑›

Since java 1.2 there are apis to load and run jars programmatically

www: http://java.sun.com/developer/Books/javaprogramming/JAR/api/
A short article about this
www: http://docs.oracle.com/javase/tutorial/deployment/jar/apiindex.html
How to use the jar apis to load a jar app in a program
tools
fastjar - creates jar files

create a jar archive url from a normal url.

 URL url = new URL("http://bumble.sf.net/books/java/m.jar");
 URL u = new URL("jar", "", url + "!/");

Jar style urls have a strange syntax.

download a jar archive

   import java.net.URL;

   try {
     URL url = new URL("jar:http://hostname/my.jar!/");
     JarURLConnection conn = (JarURLConnection)url.openConnection();
     JarFile jarfile = conn.getJarFile();
     String entryName = conn.getEntryName();  // null
   } catch (MalformedURLException e) {
   } catch (IOException e) {}

create a jar url for a local jar archive

 URL url = new URL("jar:file:/c:/almanac/my.jar!/");

get just one file from a jar archive

   try {
     url = new URL("jar:file:/c:/almanac/my.jar!/com/mycompany/MyClass.class");
     conn = (JarURLConnection)url.openConnection();
     jarfile = conn.getJarFile();
     // Get the entry name; it should be the same as specified on URL
     entryName = conn.getEntryName();
     JarEntry jarEntry = conn.getJarEntry();
   } catch (MalformedURLException e) {
   } catch (IOException e) {}

load a jar and find out the main class (if there is one)

   import java.net.URL;
   import java.net.JarURLConnection;
   import java.util.jar.Attributes;
   public class MainJar {
     public static void main(String[] args) throws Exception {
       URL url = new URL("jar:http://bumble.sf.net/books/java/m.jar!/"); 
       JarURLConnection uc = (JarURLConnection)url.openConnection();
       Attributes aa = uc.getMainAttributes();
       if (aa != null) {
         System.out.format(
           "Main class is: %s\n", aa.getValue(Attributes.Name.MAIN_CLASS));
       }
       else { System.out.println("No main class"); }
     }
   }

load and execute a class with URLClassLoader and method.invoke()

   import java.net.URL;
   import java.net.URLClassLoader;
   import java.lang.reflect.Method;
   import java.lang.reflect.Modifier;
   import java.lang.reflect.InvocationTargetException;
   public class LoadClass {
     public static void main(String[] args) throws Exception {
       URL url = new URL("file:MethodPanel.class");
       URLClassLoader cl = new URLClassLoader(new URL[] {url});
       Class c = cl.loadClass("MethodPanel");
       Method m = c.getMethod("main", new Class[] { args.getClass() });
       m.setAccessible(true);
       // check for valid java 'main' method
       int mods = m.getModifiers();
       if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
           !Modifier.isPublic(mods)) {
         throw new NoSuchMethodException("main");
       }
       try {
         m.invoke(null, new Object[] { args });
       } catch (IllegalAccessException e) {
         // This should not happen, as we have disabled access checks
       }
     }
   }

load and execute the main class from a remote jar archive

   import java.net.URL;
   import java.net.URLClassLoader;
   import java.lang.reflect.Method;
   import java.lang.reflect.Modifier;
   import java.net.JarURLConnection;
   import java.util.jar.Attributes;

   public class LoadJar {
     public static void main(String[] args) throws Exception {
       String mainClass = new String("");
       URL url = new URL("jar:http://bumble.sf.net/books/java/m.jar!/"); 
       JarURLConnection uc = (JarURLConnection)url.openConnection();
       Attributes aa = uc.getMainAttributes();
       if (aa != null) {
         mainClass = aa.getValue(Attributes.Name.MAIN_CLASS);
         System.out.println(aa.getValue(Attributes.Name.MAIN_CLASS));
       }
       else { 
         System.out.println("No main class");
         System.exit(0);
       }
       URLClassLoader cl = new URLClassLoader(new URL[] {url});
       Class c = cl.loadClass(mainClass);
       Method m = c.getMethod("main", new Class[] { args.getClass() });
       m.setAccessible(true);
       // check for valid java 'main' method
       int mods = m.getModifiers();
       if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
           !Modifier.isPublic(mods)) {
         throw new NoSuchMethodException("main");
       }
       try {
         m.invoke(null, new Object[] { args });
       } catch (IllegalAccessException e) {
         // This should not happen, as we have disabled access checks
       }
     }
   }

run a class in subfolder 'eg' (but not in any package)

 java -cp eg Test

An Example Jar Manifest ‹↑›

an example manifest file with the class path set ---- Main-Class: org.mypackage.HelloWorld Class-Path: lib/supportLib.jar ,,,

Classpath ‹↑›

The classpath is the mechanism which the jre using to locate classes which are used in an application. The current directory is always included in the classpath. The classpath has a reputation for giving rise to tricky configuration problems.

place multiple jar files on the classpath (windows)

 java -cp "Test.jar;lib/*" my.package.MainClass

the same on Linux (colons and not semicolons!)

 java -cp "Test.jar:lib/*" my.package.MainClass

jar files can also be placed in the extension directory

 C:\JDK1.2.2\JRE\LIB\EXT   windows, very old java runtime

a typical extension folder list for java 1.7 on Linux

 /usr/lib/jvm/jdk1.7.0/jre/lib/ext:/usr/java/packages/lib/ext

another way of copying a jar file to the extensions folder

 cp mp3plugin.jar ${JAVA_HOME}/jre/lib/ext

display the java extensions folder ---- public class GetClassPath { public static void main(String[] args) { System.out.println(System.getProperty("java.ext.dirs")); } } ,,,

display the java classpath and the extensions folder ---- import java.util.Properties; public class GetClassPath { static Properties p = System.getProperties(); public static void main(String[] args) { System.out.println(p.getProperty("java.class.path", null)); System.out.println(System.getProperty("java.ext.dirs")); System.out.println(p.getProperty("java.ext.dirs", null)); } } ,,,

Randomness ‹↑›

Randomness is important since it is the seedling of artisticness and creativity.

generate some random bytes

    byte[] bytes = new byte[5];
    rand.nextBytes(bytes);

shuffle the order of elements in a java.util.List

    List list = new ArrayList();
    list.add("a"); list.add("b"); list.add("c");
    Collections.shuffle(list);

shuffle the order of elements in an array

    String[] array = new String[]{"a", "b", "c"};
    Collections.shuffle(Arrays.asList(array))

Syntax And Keywords ‹↑›

If Conditionals ‹↑›

The 'if' statement is used to branch program flow depending on a particular condition.

example

 String a="nn"; if (a.equals("NN")) { ... }

Ternary Operator ‹↑›

The ternary operator is a compact form of the if / else statement

find the minimum value

 minVal = a < b ? a : b;
 minVal = (a < b) ? a : b;

a print statement using a the ternary operator

  System.out.println("will last " + icecreamLife +
jar api packages and classes
java.util.jar - package
java.net.JarURLConnection class
java.net.URLClassLoader class

use the ternary operator

    " month" + (icecreamLife==1?"":"s") +" and " + icecreamFate);

Switch Statement ‹↑›

a simple switch statement

       int result = 0;
       switch (result)
       {
         case 0: 
           break;
         case 1: 
           break;
         default:
           break;
       }

Loops ‹↑›

Java does not have a 'map' function, which transforms each element of a collection using a function and without looping.

For Loops ‹↑›

loop over any type of collection (implements iterable)

   for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) {
     type var = iter.next();
     body-of-loop
   }

the same as above, but only since java 1.5

   for (type var : coll) {
     body-of-loop
   }

a simple counting loop

     for (int ii = 0; ii < 7; ii++) 
     {
        System.out.println("ii=" + ii + " ");
     }

a loop which runs until the user enters 'q'

    import java.util.Scanner;
    public class Test {
      public static void main(String[] args)
      {
        Scanner scan = new Scanner(System.in);
        for (String s = ""; !s.equals("q"); s = scan.nextLine())
        {
          System.out.println("You entered: " + s);
          System.out.println("Type q to quit");
        }
    } }

Foreach Loop ‹↑›

In java 1.5 a "for each" loop was introduced to allow programmers to use a more pleasant syntax for a very common task (looping over a collection or array)

loop through a the words of a string

    public class ForSplit {
      public static void main(String[] args) {
        String s = "red yellow blue";
        String[] splitString = (s.split("\\s+"));
        for (String ss: splitString) {
          System.out.println(ss);
        }
      }
    }

a for each loop to add all elements in an array (>= java 1.5) --------- import java.util.Arrays; public class SumArray { public static void main(String[] args) { double[] aa = {1.2, 3.0, 0.8}; double sum = 0; for (double d : aa) { sum += d; // d gets each value in aa. } System.out.format( "The sum of array %s is %g", Arrays.toString(aa), sum); } } ,,,

This loop only allows access to the elements and can only loop forward

print out command line arguments using foreach

   public class Freq {
     public static void main(String[] args) {
     for (String a : args) {
         System.out.println(a);
       }
     }
   }

iterate over a collection of Strings using explicit iterator

  void cancelAll(Collection<String> c) {
    for (Iterator<String> i = c.iterator(); i.hasNext(); )
        i.next().cancel();
  }

Use the explicit iterator if you have to modify elements of the collection

iterate over a collection of Strings with a foreach loop (java 1.5 >=)

  void cancelAll(Collection<String> c) {
    for (String t : c)
        t.cancel();
  }

iterate over a List collection using a foreach loop

   import java.util.*;
   public class ListLoop {
     public static void main(String[] args) {
       List<String> list = new ArrayList<String>();
       list.add("oak");
       list.add("yew");
       list.add("acacia");
       for (String item: list ) {
         System.out.println(item);
       }
     }
   }

loop over a list with an iterator to allow removal of elements -------- import java.util.*; public class ListLoop { public static void main(String[] args) { List<String> list = new ArrayList<String>() list.add("oak"); list.add("yew"); list.add("acacia"); for (Iterator<String> i = someList.iterator(); i.hasNext(); ) { String item = i.next(); System.out.println(item); } } } ,,,

Iterators And Enumerations ‹↑›

Iterators are a way of performing some task for every element of a Collection without retrieving the entire collection.

Enumerations are the older class to facilitate iterating over a set of objects. Iterators are the newer way to do the same thing. Enumerations are still used because many older api classes still in use return Enumerations.

In the code below, the for loop has the advantage of limiting the scope of the iterator variable to the for loop.

an iterator can be used with a while or a for loop

   Iterator<Integer> iterator = set.iterator();
   while (iterator.hasNext()) {
     Integer element = iterator.next();
     if (element % 2 == 0) {
       iterator.remove();
     }
   }
   //You will often see this pattern using a for loop 
   //rather than a while loop:
   for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
     Integer element = i.next();
     if (element % 2 == 0) {
       i.remove();
     }
   }

While Loops ‹↑›

a while loop

     String s = ""; 
     Scanner scan = new Scanner(System.in);
     while (!s.equals("q"))
     {
       System.out.print("type q to quit> "); 
       s = scan.nextLine();
     }

Arrays ‹↑›

Arrays can be passed to methods or functions, but changes made to the elements are permanent (no copy of the array is made when it is passed to the method).

declare a method 'do' which takes an integ

 public void do(int [] array);

create an anonymous String array to pass to a method or constructor

 object.doSomething(new String[]{"one","two"}));

Declaring Arrays ‹↑›

create an array of 4 integers, with the values initialized

 int[] ii = {100, 200, 300, 400};

declare an array of 30 integers

 int[30] a;

declare and initialise an array of colours

 Color[] colors = {Color.orange, Color.green, Color.yellow};

declare an array with space for 25 strings

 String[] ss = new String[25];  ???

declare an array of characters

 char[] c = {'a', 'b', 'c'};

declare an array of strings

 String[] ss = {"oak", "alder", "amber"};

another way?

 String[] ss = new String[]{"oak", "alder", "amber"};

Initialising Arrays ‹↑›

create and initialise an array of double values

 double[] array = new double[]{0D, 2D, 4D, 5D}

create a byte array and fill all items with the value 0xFF

 byte[] bytes = new byte[10]; Arrays.fill(bytes, (byte)0xFF);

create a 10 element 'char' array and initialise all elements to 'a'

 char[] cc = new char[10]; Arrays.fill(cc, 'a');

The example below will work for any type of object, not just Strings.

create an array of Strings and initialise all values to 'none'

 String[] ss = new String[10]; Arrays.fill(ss, "none");

initialise only values 0 to 3 to 'none'

 String[] ss = new String[10]; Arrays.fill(ss, 0, 4, "none");

Object Arrays ‹↑›

Arrays may contain any type of Object, but only one type

declare and array of File objects

   import java.io.File;
   public class FileArray {
     public static void main(String[] args) {
       File[] ff = {new File("."), new File("a")};
     }
   }

Anonymous Arrays ‹↑›

Anonymous arrays are useful for testing and making code more succint/obfuscated. The syntax is not immediately obvious.

pass an anonymous array of 2 colours to a method call

 object.doSomething(new Color[]{Color.orange, Color.green})

Displaying Arrays ‹↑›

print an array with Arrays.toString (since 1.5)

    import java.util.Arrays; 
    public class ArrayTest {
      public static void main(String[] args) {
        String[] ss = {"gold", "green", "red"};
        System.out.println(Arrays.toString(ss));
      }
    }

display an array with a JOptionPane list-box

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        String[] ss = {"gold", "green", "red"};
        Object r = JOptionPane.showInputDialog(
           null, "Choose one element:", "Displaying arrays",
           JOptionPane.PLAIN_MESSAGE, null, ss, ss[0]);
        System.out.println("element selected: " + r);
      }
    }

Looping Through Arrays ‹↑›

Java does have a way to apply a function to all elements of an array at once (although apparently scala does), so you have to loop through the array one element at a time.

Add all elements of the array nn

   int sum = 0;
   for (int v : nn) { sum += v; }

The above loop cannot be used to set the values of the array

assign random numbers to the elements of an array

int[] a = new int[1000]; for (int i = 0; i < a.length(); i++) { // Random number 0-99999 a[i] = (int)(Math.random() * 100000); } ,,,

Comparing Arrays ‹↑›

check if 2 arrays are equal (contain the same objects)

    import java.util.Arrays; 
    public class Test {
      public static void main(String[] args) {
        String[] ss = {"gold", "green", "red"};
        String[] tt = {"gold", "green", "red"};
        System.out.println("equal? " + Arrays.equals(ss, tt));
      }
    }

check if arrays of long, float, and double are equal

     b = Arrays.equals(new long[]{0L}, new long[]{0L});         // true
     b = Arrays.equals(new float[]{0F}, new float[]{0F});       // true
     b = Arrays.equals(new double[]{0D}, new double[]{0D});     // true

create an array of 10 integers

 anArray = new int[10];

copy one array to another

    public class Test {
      public static void main(String[] args) {
        char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e'};
        char[] copyTo = new char[7];
        System.arraycopy(copyFrom, 2, copyTo, 0, 3);
        System.out.println(new String(copyTo));
      }
    }

Joining Arrays ‹↑›

concatenate 2 arrays of strings

    String[] concat(String[] aa, String[] bb) {
      String[] C= new String[A.length+B.length];
      System.arraycopy(aa, 0, cc, 0, aa.length);
      System.arraycopy(B, 0, C, A.length, B.length);
      return C;
    }
   ,,,,

SORTING ARRAYS ....

   * sort an array of integers into ascending order 
    import java.util.Arrays; 
    public class Test {
      public static void main(String[] args) {
        int[] ii = {5, 3, 8, 1};
        System.out.println("array: " + Arrays.toString(ii));
        Arrays.sort(ii);
        System.out.println("sorted: " + Arrays.toString(ii));
      }
    }

using a comparator to sort an array

   Action actions[] = component.getActions();
   Comparator<Action> comparator = new Comparator<Action>() {
     public int compare(Action a1, Action a2) {
       String firstName = (String) a1.getValue(Action.NAME);
       String secondName = (String) a2.getValue(Action.NAME);
       return firstName.compareTo(secondName);
     }
   };
   Arrays.sort(actions, comparator);

Searching Arrays ‹↑›

determine if an array contains a certain element

 String ss = {"a","b","c"}; Arrays.asList(ss).contains("b");

Two Dimensional Arrays ‹↑›

declare and initialise a 2 dimensional array

    Object[][] data = {
      {aboutIcon, "About"},
      {addIcon, "Add"},
      {copyIcon, "Copy"},
    };

More Arrays ‹↑›

CAN create and return an array from a method arrays passed in are changed by methods.

different ways to initialize arrays

 int[] ii = {100, 200, 300, 400};
 int[30] a;
 char[] c = {'a', 'b', 'c'};
 double[] d = new double[5];
 String[] ss = new String[25];
 int[] aa = {1, 2, 3}; ob.doo(aa);

All c is initialised to (int)0

char[] c = new char[20]; for (int i=0; i < c.length; i++) System.out.println("c1=" + (int)c[i]);

Converting Between Arrays And Collections ‹↑›

From Maps ‹↑›

create an array of objects containing the keys in a map

 Object[] array = map.keySet().toArray();

create an array of strings containing the keys in a map

  array = (String[])map.keySet().toArray(new String[set.size()]);

Create an array containing the values in a map

 Object[] array = map.values().toArray();
 array = (MyClass[])map.values().toArray(new MyClass[set.size()]);

From Sets ‹↑›

Create an array containing the elements in a set

 objectArray = set.toArray();
 array = (MyClass[])set.toArray(new MyClass[set.size()]);

From Lists ‹↑›

Create an array containing the elements in a list

 Object[] objectArray = list.toArray();
 MyClass[] array = (MyClass[])list.toArray(new MyClass[list.size()]);

Enumerations ‹↑›

list all the system properties using an Enumeration

   public class SystemProps {
     public static void main(String[] args) {
       java.util.Properties p = System.getProperties();
       java.util.Enumeration en = p.propertyNames();
       while (en.hasMoreElements()) {
         String name = (String) en.nextElement();
         System.out.format("%s: %s\n", name, p.getProperty(name));
       }
     }
   }

loop through an enumeration using a for loop

    import java.io.*;
    import java.net.*;
    import java.util.*;
    public class ListNetInterfaces {
      public static void main(String args[]) throws SocketException {
        Enumeration<NetworkInterface> nets =
        NetworkInterface.getNetworkInterfaces();
        for (NetworkInterface ni : Collections.list(nets)) {
          System.out.println(
            "Display name:" + ni.getDisplayName());
          System.out.println("Hardware address:" +
                             Arrays.toString(ni.getHardwareAddress()));
        }
      }
    }

Generics ‹↑›

Since Java 1.5 (September 30, 2004) an important feature became part of the Java language: Generics. From a pragmatic point of view, generics avoid the need to cast objects to a specific object type when using Collections

declare and initialise a java.util.List of Strings.

 List<String> list = new ArrayList<String>();

specify a generic which is a descendant of JarEntry

 Enumeration<? extends JarEntry> enumeration = jar.entries();

Collections ‹↑›

Collections are the name java gives to objects which contain multiple object elements. Examples of these are sets, lists and maps. The collection framework was apparently designed by Joshua Bloch. Each collection type has a number of implementations, for example, the List type has the ArrayList, LinkedList etc. these implementations relate mainly to performance issues, and sometimes functionality.

In more recent versions of Java, use is made of 'generics' which allow the programmer to specify at compile time what type of object a collection will contain.

 int i = 1; String s = (i==0?"zero":"non-zero");

use ArrayList for resizable arrays

Vector is older (synchronised for multi threads?)

Sets ‹↑›

A set is an unordered collection of things which cannot contain duplicates.

create a set collection d from collection c with no duplicates

 Collection<Type> d = new HashSet<Type>(c);

Lists ‹↑›

A list is an ordered collection of objects. In general, and as with other collections you declare a variable as a List and then instantiate it as a particular List implementation.

create a List from a set of strings

 List<String> list = Arrays.asList( "first", "second", "third");

get the first element (an integer) from the array list

 Integer one = (Integer) arrayList.get(0)

Converting Lists ‹↑›

main collection types
set - an unordered collection with no duplicates
list - an ordered set of objects
map - a type of dictionary of key value pairs
length array is returned.

convert a java.util.List to an array of Integers

 return list.toArray(new Integer[list.size()]);

Arraylists ‹↑›

www: www.java2s.com/Code/Java/Collections-Data-Structure/ArrayList.htm
arraylist examples
create and add a mutable string to an array list.
     List l = new ArrayList();
     l.add(new StringBuffer());

loop through each element of an array list by index number

     import java.util.ArrayList;
     import java.util.List;
     public class LoopList {
       public static void main(String[] args) {
          List list = new ArrayList();
          for (int jj = 0; jj < list.size(); jj++) {
            System.out.println("[" + jj + "] - " + list.get(jj));
          }
       }
     }

List Gotchas ‹↑›

If you import java.awt.* but not java.util.List you will get some quite baffling error messages when you try to use you List (because java.awt.List exists, but is an old gui component)

Maps ‹↑›

A map is a type of 'dictionary' consisting of keys and their corresponding values. In perl these are called 'hashes' and in other languages 'dictionaries'.

create a map to contain the frequency of words in a document

   Map<String, Long> doc = new HashMap<String, Long>();
   doc.put("file", 6);
   doc.put("channel", 4);
   doc.put("size", 3);

get a value from a map by specifying its key

 doc.get("file");

create a new map and put some keys and values into it

  Map<String, Double> times = new HashMap<String, Double>();
  times.put("file", 0.0);
  times.put("channel", 0.0);
  times.put("raf", 0.0);

create a map contained string keys and arraylists

 Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>;

Tree maps are sorted by some ordering of keys or by a comparator specificied in the constructor.

create a frequency word list of from command line arguments

   import java.util.*;
   
   public class Freq {
     public static void main(String[] args) {
       Map<String, Integer> m = new HashMap<String, Integer>();
   
       // Initialize frequency table from command line
       for (String a : args) {
         Integer freq = m.get(a);
         m.put(a, (freq == null) ? 1 : freq + 1);
       }
   
       System.out.println(m.size() + " distinct words:");
       System.out.println(m);
     }
   }

a tree map stores its keys in alphabetical order (if they are strings)

 Map<String, Integer> m = new TreeMap<String, Integer>();

copy map m to map copy

 Map<K, V> copy = new HashMap<K, V>(m);

loop over the keys in a map --- import java.util.*;

for (KeyType key : m.keySet()) System.out.println(key); ,,,

loop over the values of a map, getting the keys and values import java.util.*; for (Map.Entry<KeyType, ValType> e : m.entrySet()) System.out.println(e.getKey() + ": " + e.getValue()); ,,,

test if 2 maps have the same set of keys

 if (m1.keySet().equals(m2.keySet())) { ... }

test if map m1 contains all the key/value pairs of map m2

 if (m1.entrySet().containsAll(m2.entrySet())) { ... }

determine which keys are common to both maps m1 and m2

   Set<KeyType>commonKeys = new HashSet<KeyType>(m1.keySet());
   commonKeys.retainAll(m2.keySet());

Numbers ‹↑›

Operators ‹↑›

Operator Precedence ‹↑›

In normal order, prints '2'

 System.out.println("\n result=" + 10*2%3);

Random Numbers ‹↑›

generate a random integer from 0-99

    Random rand = new Random();
    selected = rand.nextInt(100);

generate a random number from 0 to 100

 int r = (int)(Math.random() * 100)

generate a random boolean value

   import java.util.Random;
   public class RandomBoolean {
     public static void main(String[] args) { Random rand = new Random();
       boolean b = rand.nextBoolean();
       System.out.format("boolean value: %s", b);
     }
   }

A random number from 0-9

   public class RandomInteger {
     public static void main(String[] args) {
       java.util.Random g = new java.util.Random();
       int i = g.nextInt(10); System.out.println("i=" + i);
     }
   }

A random element of an array

   public class RandomArray {
     public static void main(String[] args) {
       java.util.Random g = new java.util.Random();
       char[] cc = {'a', 'b', 'c', 'd'};
       System.out.println(cc[g.nextInt(cc.length)]);
     }
   }

Double ‹↑›

A double is a number which can hold fractional (decimal) values and bigger values than an integer.

Convert a string to a double

 double d = Double.parseDouble("-0.223");

powers

 java.lang.Math.pow(3,4)

float f = rand.nextFloat(); // 0.0 <= f < 1.0

generate a random double number (0.0 <= d < 1.0)

 double d = rand.nextDouble();

Integers ‹↑›

declare an integer

 int x = 2;

parseInt is FUSSY, examples below throw number format exception

 int i = Integer.parseInt("123 ")'    !!! NO
 int i = Integer.parseInt(" 123")'    !!! NO
 int i = Integer.parseInt("123\n")'   !!! NO

convert a negative number from a string to an integer

 int i = Integer.parseInt("-123")'

Mathematics ‹↑›

Transendental Numbers ‹↑›

get an approximate value for PI

 Math.PI

Modulus ‹↑›

The modulus is a mathematical idea investigated by Gauss amongst others. Java provides support for this through the '%' operator.

get the hundreds digit (0-9) from an integer

 i = 1234; i=i/100%10;

Characters ‹↑›

get information about a character

   import java.text.*;
   char cc = 'a';
   if (Character.isLowerCase(cc)) { //true }

Char ‹↑›

The 'char' is the java primitive type for a character.

 char letter = 'a';
 char c = 'a' + 4;   (c='e')

implicitly cast a 'char' to an integer

 char c = 'A'; int i = 4 + c;

Implicit casts to integer are NOT allowed in methods calls

 Test.doo(25);   !!! no if "doo(char c)"

greater/less than comparisons with 'char' type is ok

 char c = 'A'; if (c <= 'B') {}
 'a'=97, 'A'=65

check if a char is a lower case roman letter (not a good way)

 lower case letter: if ((c >= 'a') && (c <= 'z'))

Convert case

 char c = Character.toLowerCase('A');
 char c = Character.toUpperCase('a');

Convert a decimal digit to a character

 char c = Character.forDigit(4, 10);

Boolean Values ‹↑›

A Boolean value is either true or false, and nothing else. In Java there is both a primitive type 'boolean' with a little b and a 'wrapper' object 'Boolean' with a big B.

initialize a boolean array (all element false)

 boolean[] array = new boolean[size];

initialize a boolean array to true

    Boolean[] array = new Boolean[size];
    Arrays.fill(array, Boolean.TRUE);

Unicode ‹↑›

Unicode is an important standard for mapping characters from any human language writing system or symbol system to 'code points' which are basically numbers.

One of the great strength of java is that it was designed with the unicode character set in mind. However a java 'char' primitive type is a 16 bit value. This means that a char or Character value can only contain unicode character in the BMP (Basic Multilingual Plane), not supplementary characters. A java 'int' value can contain any Unicode code point.

On a Linux system the Droid Sans Fallback font seems to have the largest number of glyphs and therefore is the font to use for displaying weird and wonderful characters

Even if the list.size() == 0 in the code below, a valid, zero

The code below progressively adds glyphs to a JPanel and updates the panel with revalidate(). For some reason panel.setVisible() must be called before maximising the window with Frame.MAXIMIZED_BOTH Adding the JLabels while the JPanel is visible is much slower than adding them all before it is visible, but the application remains responsive.

displays some unicode characters in a grid, with descriptions

    import javax.swing.*;
    import java.awt.*;
    public class Glyphs { public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        JFrame t = new JFrame();
        Font font; JLabel label;
        String name = new String();
        JPanel p = new JPanel(new GridLayout(0, 10));
        font = new Font("Droid Sans Fallback", Font.PLAIN, 30);
        t.getContentPane().add(new JScrollPane(p));
        t.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        t.setVisible(true);
        t.setExtendedState(Frame.MAXIMIZED_BOTH);
        String tipText;
        for (int i = (int)Character.MIN_VALUE; i < (int)Character.MAX_VALUE - 20000; i++)
        {
          if (font.canDisplay(i)) {
            label = new JLabel("" + (char)i); label.setFont(font);
            tipText = String.format("decimal: %d", i);
            //jre1.7: "decimal: %d name: %s", i, Character.getName(i));
            label.setToolTipText(tipText);
            p.add(label); p.revalidate();
          }
        }
        long endTime = System.currentTimeMillis();
        long loadTime = endTime - startTime;
        t.setTitle("glyphs displayed in: " + loadTime + " miliseconds");
      }
    }

The code above takes about a minute to display on a modern laptop.

Specifying Unicode Characters ‹↑›

It is possible to use the backslash u (\u) notation to specify a unicode character. This is an alternative to actually 'pasteing' in the character itself.

The \u notation uses the unicode 'code point' (which is a hexadecimal number).

initialise the 'symbol' variable to the 'fleur-de-lys' character

 String symbol = "\u269c";
 String symbol = "\u269C";  the same, upper or lower hex letters

initialise a character to the fleur-de-lys

 char c = '\u269c';

display the fleur-de-lys and snowman glyphs in a JLabel

    import javax.swing.*;
    import java.awt.Font;
    public class UniLabel {
     public static void main(String[] args) {
       JLabel l = new JLabel("\u269C \u2603");
       l.setFont(new Font("FreeSerif", Font.PLAIN, 40));
       JOptionPane.showMessageDialog(null, l);
     }
    }

The static method below is generally useful when trying to display a glyph, but is a tad slow.

get a list of fonts which contain a glyph

   import java.util.*;
   import java.awt.*;
   public class FontHelp {
     public static String[] getGlyphFonts(char c) {
       java.util.List<String> names = new ArrayList<String>();
       GraphicsEnvironment gre =
         GraphicsEnvironment.getLocalGraphicsEnvironment();
       for (Font f: gre.getAllFonts()) {
         if (f.canDisplay(c)) names.add(f.getName());
       }
       return (String[])names.toArray(new String[names.size()]);
     }
     public static void main(String[] args) {
       for (String s: FontHelp.getGlyphFonts('\u269c'))
         System.out.println(s);
     }
   }

Matching Unicode Characters ‹↑›

We can use java regular expressions (since j2se 1.4 -febuary 2002) to

www: http://www.regular-expressions.info/unicode.html
A good explanation of matching unicode letters in regular expression
match all characters in the Mongolian unicode block
 \p{InMongolian}

match any unicode letter

 \p{L}\p{M}*

determine if a char/codePoint is CJKV (Chinese, Japanese, Korean and Vietnamese) ideograph, as defined by the Unicode Standard (since Java 1.7)

 static boolean isIdeographic(int codePoint)

Unicode Character Blocks ‹↑›

The unicode code blocks are part of the unicode standard, and group together characters which have a similar function or usage. For example characters which form part of a particular language writing system are grouped together in a block.

Code blocks seem to be contiguous in the unicode standard but there seems no simple way to get the block starting code point (character) nor the last code point. This means that we may have to interate over all characters to retrieve the characters belonging to that block.

useful Unicode Character methods
getName() - gets the unicode descriptive name (since jre 1.7)

get a block by name

 Character.UnicodeBlock b = Character.UnicodeBlock.forName("BasicLatin");

print the name of the unicode block (calls toString() implicitly)

   public class UnicodeBlocks {
     public static void main(String[] args) {
       System.out.println("block name: " + Character.UnicodeBlock.CHEROKEE);
     }
   }

Character.UnicodeBlock methods
forName(String blockName) - returns the block with the given name.
of(char c) - returns the block containing the given character or null
of(int codePoint) - the same but for a codepoint not a Character.

The following works on my Linux Mint system, with gnome. Whether you can see the glyphs or not will probably depend on the console ('command line') having a suitable font installed.

displays some greek unicode characters

    public class GreekGlyphs {
      public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        int ii = (int)Character.MIN_VALUE;
        while (ii <= (int)Character.MAX_VALUE)
        {
          if (Character.UnicodeBlock.GREEK == Character.UnicodeBlock.of(ii)) 
          {
            System.out.print(String.format("%d: %c, ", ii, (char)ii));
              //jre1.7: "decimal: %d name: %s", i, Character.getName(i));
            if ((ii%5) == 0) System.out.println("");
          }
          ii++;
        }
        long endTime = System.currentTimeMillis();
        long loadTime = endTime - startTime;
        System.out.println(
          "glyphs displayed in: " + loadTime + " miliseconds");
      }
    }

As a side note about string matching, there is not a huge difference in performance between string.matches() and string.startsWith() in the code below (400ms compared to 700ms on my asus netbook)

displays characters from various miscelaneous symbol unicode blocks

    public class SymbolGlyphs {
      public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        Character.UnicodeBlock block = null;
        int ii = (int)Character.MIN_VALUE;
        while (ii <= (int)Character.MAX_VALUE) {
          ii++;
          block = Character.UnicodeBlock.of(ii);
          if (block == null) continue;
          if (block.toString().startsWith("MISC")) {
            System.out.print(String.format("%d: %c, ", ii, (char)ii));
            if ((ii%5) == 0) System.out.println("");
          }
        }
        long endTime = System.currentTimeMillis();
        long loadTime = endTime - startTime;
        System.out.println(
          "glyphs displayed in: " + loadTime + " miliseconds");
      }
    }

The default font on my linux system (Dialog, 12pt) doesnt have many glyphs, unfortunately. Another problem is that one needs to work out which font will be able to display the glyph, and this may change from computer to computer. Also if the font doesnt exist, no exception is thrown in the font constructor, the font just defaults to 'dialog' (on a linux system).

displays characters from miscelaneous symbol blocks in a JPanel

    import javax.swing.*;
    import java.awt.*;
    public class SymbolPanel extends JPanel {
      String blockPrefix;
      Font font;
      public SymbolPanel(String blockPrefix) {
        super(new GridLayout(0, 4)); 
        this.blockPrefix = blockPrefix;
        this.font = new Font("FreeSerif", Font.PLAIN, 50);
        this.showGlyphs();
      }
      private void showGlyphs() {
        // first remove all JLabels, but how?
        long startTime = System.currentTimeMillis();
        Character.UnicodeBlock block = null;
        int ii = (int)Character.MIN_VALUE;
        JLabel label = new JLabel();
        int missingGlyphs = 0;
        GraphicsEnvironment gr = 
          GraphicsEnvironment.getLocalGraphicsEnvironment();
        boolean isFound = false;
        while (ii <= (int)Character.MAX_VALUE) {
          ii++;
          block = Character.UnicodeBlock.of(ii);
          if (block == null) continue;
          if (block.toString().startsWith(this.blockPrefix)) {
            // search for a font which has a glyph for this character
            /*
            // this code is working but produces ugly results
            if (!this.font.canDisplay(ii)) {
              isFound = false; 
              for (Font f: gr.getAllFonts()) {
                if (f.canDisplay(ii)) {
                  if (f.getFamily().equals("unifont")) continue;
                  this.font = f.deriveFont(Font.PLAIN, 50); isFound = true;
                  System.out.println("using font:" + this.font.toString());
                  break;
                }
              }
            }
            */ 
            if (this.font.canDisplay(ii)) {
              label.setFont(this.font);
              label.setBorder(new RoundedBorder(Color.gray, 4));
              label = new JLabel(" " + (char)ii); 
              label.setToolTipText(String.format(
          "<html><big><big><ul>" +
          "<li>Font-family: %s<li>font-size, %d<li>decimal: %d</ul>",
                this.font.getFamily(), this.font.getSize(), ii));
              this.add(label);
            }
            else missingGlyphs++; 
          }
        }
        long endTime = System.currentTimeMillis();
        long loadTime = endTime - startTime;
        label = new JLabel(String.format(
          "time: %d ms, missing: %d", 
           loadTime, missingGlyphs));
        this.add(label);
      }

      public void copy() {
    Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
    StringSelection testData = new StringSelection("Clipboard testing");
    c.setContents(testData, testData);
      }

      public static void main(String[] args) {
        System.setProperty("awt.useSystemAAFontSettings","on");
        SymbolPanel p = new SymbolPanel("DING");
        JFrame f = new JFrame();
        f.add(new KeyScrollPane(p));
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.setVisible(true);
        f.setExtendedState(Frame.MAXIMIZED_BOTH);
      }
    }

The code below is freezing the computer.

displays some unicode characters from the 'greek' code block

   import javax.swing.*;
   import java.awt.*;
   public class UnicodeBlocks {
     public static void main(String[] args) {
       long startTime = System.currentTimeMillis();
       JFrame t = new JFrame();
       Font font;
       JLabel label;
       String name = new String();
       JPanel p = new JPanel(new GridLayout(0, 10));
       font = new Font("Droid Sans Fallback", Font.PLAIN, 30);
       t.getContentPane().add(new JScrollPane(p));
       t.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       t.setVisible(true);
       t.setExtendedState(Frame.MAXIMIZED_BOTH);
       String tipText;
       for (int i = (int)Character.MIN_VALUE; i < (int)Character.MAX_VALUE - 20000; i++)
       {
         if (font.canDisplay(i) &&
             (Character.UnicodeBlock.GREEK == Character.UnicodeBlock.of(i))) {
           {
             label = new JLabel("" + (char)i);
             label.setFont(font);
             tipText = String.format("decimal: %d", i);
             //jre1.7: "decimal: %d name: %s", i, Character.getName(i));
             label.setToolTipText(tipText);
             p.add(label);
             p.revalidate();
           }
         }
         long endTime = System.currentTimeMillis();
         long loadTime = endTime - startTime;
         t.setTitle("glyphs displayed in: " + loadTime + " miliseconds");
       }
     }
   }

By iterating over all characters (or more precisely, Unicode code points) it is possible to check each to find its Unicode Block:

iterate over all characters in a unicode block

   // Character.UnicodeBlock block = Character.UnicodeBlock.ARABIC;

   public static void main(String[] args) {
     Set<Character> arabicChars = 
       getUnicodeBlock(Character.UnicodeBlock.ARABIC);
     Set<Character> bengaliChars = 
       getUnicodeBlock(Character.UnicodeBlock.BENGALI);
   }
   
   private static Set<Character> getUnicodeBlock(final Character.UnicodeBlock block) {
     final Set<Character> chars = new HashSet<Character>();
     for (int codePoint = Character.MIN_CODE_POINT; codePoint <= Character.MAX_CODE_POINT; codePoint++) {
       if (block == Character.UnicodeBlock.of(codePoint)) {
         chars.add((char) codePoint);
       }
     }
     return chars;
   }

App To Show Glyphs ‹↑›

A simple application which displays glyphs in a block and copies the glyph to the system clipboard when the button is pressed.

ideas: It would be nice to append to the clipboard, but thats a bit more work. An information label at the bottom would be nice: load time, number of glyphs. Show all fonts in which the glyph exists. Use reflection to interate through the unicode blocks and make a combobox to choose them.

displays characters from symbol blocks in a JPanel

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.datatransfer.*;
    public class GlyphApp extends JPanel implements ActionListener {
      String blockPrefix;
      JTextField blockField;
      JPanel glyphPanel;
      Font font;

      public GlyphApp() {
        super(new BorderLayout(20, 20)); 
        this.blockField = new JTextField("dingbat");
        this.blockField.setFont(new Font("Georgia", Font.ITALIC, 22));
        this.blockField.addActionListener(this);
        //this.blockPrefix = blockPrefix;
        this.font = new Font("FreeSerif", Font.PLAIN, 50);
        this.glyphPanel = new JPanel(new GridLayout(0, 4));
        this.add(this.blockField, BorderLayout.NORTH);
        this.add(new KeyScrollPane(this.glyphPanel), BorderLayout.CENTER);
        this.showGlyphs();
      }
      public void actionPerformed(ActionEvent e) {
        if (e.getSource() instanceof JButton) {
          JButton b = (JButton) e.getSource();
          System.out.println("button push:" + b.getText());
          Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
          StringSelection ss = new StringSelection(b.getText());
          c.setContents(ss, ss);
        }
        else if (e.getSource() == this.blockField) {
          System.out.println("enter press");
          this.removeGlyphs(); this.revalidate();
          this.showGlyphs(); this.revalidate();
        }
      }
      /** removes all the buttons containing glyphs */
      private void removeGlyphs() {
        for (Component c: this.glyphPanel.getComponents()) {
          if (c instanceof JButton) this.glyphPanel.remove(c);
        }
      }
      private void showGlyphs() {
        // first remove all JLabels
        // this.glyphPanel.removeAll();
        long startTime = System.currentTimeMillis();
        Character.UnicodeBlock block = null;
        int ii = (int)Character.MIN_VALUE;
        JButton button = new JButton();
        int missingGlyphs = 0;
        GraphicsEnvironment gr = 
          GraphicsEnvironment.getLocalGraphicsEnvironment();
        boolean isFound = false;
        while (ii <= (int)Character.MAX_VALUE) {
          ii++;
          block = Character.UnicodeBlock.of(ii);
          if (block == null) continue;
          String pattern = "(?i).*" + this.blockField.getText() + ".*";
          if (block.toString().matches(pattern)) {
            // search for a font which has a glyph for this character
            /*
            // this code is working but produces ugly results
            if (!this.font.canDisplay(ii)) {
              isFound = false; 
              for (Font f: gr.getAllFonts()) {
                if (f.canDisplay(ii)) {
                  if (f.getFamily().equals("unifont")) continue;
                  this.font = f.deriveFont(Font.PLAIN, 50); isFound = true;
                  System.out.println("using font:" + this.font.toString());
                  break;
                }
              }
            }
            */ 
            if (this.font.canDisplay(ii)) {
              button.setFont(this.font);
              button.setBorder(new RoundedBorder(Color.gray, 4));
              button = new JButton(" " + (char)ii); 
              button.addActionListener(this);
              button.setToolTipText(String.format(
          "<html><big><big><ul>" +
          "<li>Font-family: %s<li>font-size, %d<li>decimal: %d" +
          "<li>hexadecimal: %x</ul>",
                this.font.getFamily(), this.font.getSize(), ii, ii));
              this.glyphPanel.add(button);
            }
            else missingGlyphs++; 
          }
        }
        long endTime = System.currentTimeMillis();
        long loadTime = endTime - startTime;
        button = new JButton(String.format(
          "time: %d ms, missing: %d", 
           loadTime, missingGlyphs));
        this.glyphPanel.add(button);
      }

      public static void main(String[] args) {
        System.setProperty("awt.useSystemAAFontSettings","on");
        JFrame f = new JFrame("Unicode Block Explorer");
        f.add(new GlyphApp());
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.setVisible(true);
        f.setExtendedState(Frame.MAXIMIZED_BOTH);
      }
    }

Gotchas For Unicode Character Blocks ‹↑›

The Character.UnicodeBlock.of(...) methods can return null, throwing around some nullpointer exceptions unless you are on your toes.

Symbols In Unicode ‹↑›

Many symbols are contained in the dingbats, and miscelaneous unicode blocks.

permissable block names
"Basic Latin" - official unicode name defined in 'blocks-<ver>.txt'
"BasicLatin" - official name but with no spaces
"BASIC_LATIN" - java class name
"basic_latin" - case insensitive java class name

display a character/codepoint in all fonts which have a glyph

   import javax.swing.*;
   import java.awt.*;
   public class CodePointPanel extends JPanel {
     int codePoint;
     Font font;
     public CodePointPanel(int codePoint) {
       super(new GridLayout(0, 4));
       this.codePoint = codePoint;
       this.showGlyphs();
     }
     private void showGlyphs() {
       long startTime = System.currentTimeMillis();
       int missingGlyphs = 0;
       JLabel label = new JLabel();
       GraphicsEnvironment gr =
         GraphicsEnvironment.getLocalGraphicsEnvironment();
       Character.UnicodeBlock block = null;
       block = Character.UnicodeBlock.of(this.codePoint);
       for (Font font: gr.getAllFonts()) {
         if (font.canDisplay(this.codePoint)) {
           font = font.deriveFont(Font.PLAIN, 50);
           label.setFont(font);
           label.setBorder(new RoundedBorder(Color.gray, 4));
           label = new JLabel(" " + (char)this.codePoint);
           label.setToolTipText(String.format(
              "<html><big><big><ul>" +
              "<li>Font-family: %s<li>font-size, %d" + 
              "<li>Unicode Block: %s<li>decimal: %d</ul>",
              font.getFamily(), font.getSize(), 
              block.toString(), this.codePoint));
           this.add(label);
         }
         else missingGlyphs++;
       }
   
       long endTime = System.currentTimeMillis();
       long loadTime = endTime - startTime;
       label = new JLabel(String.format("time: %d ms, missing: %d",
            loadTime, missingGlyphs));
       this.add(label);
     }
   
     public static void main(String[] args) {
       System.setProperty("awt.useSystemAAFontSettings","on");
       CodePointPanel p = new CodePointPanel(9992);
       JFrame f = new JFrame();
       f.add(new KeyScrollPane(p));
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
       f.setExtendedState(Frame.MAXIMIZED_BOTH);
     }
   }

Interesting Unicode Characters ‹↑›

http://unicode.org/Public/UNIDATA/NamesList.txt the official list of unicode character names. Helpful for finding something

U+2620 skull and cross bones U+2603 snow man U+2368 APL FUNCTIONAL SYMBOL TILDE DIAERESIS, looks like a sad face U+0E5B a spirally curly symbol, thai character khomut

www: http://coolunicodecharacters.blogspot.com/
some interesting fancy letter unicode characters
www: http://fsymbols.com/
graphical unicode characters, such as an aeroplane etc organised by type. Have to look at the source code for the numbers
The miscelaneous technical page has some clock symbols

#592 to #780 linguistic phonetic symbols

note: jdk7 has a String getName(int codepoint) function that will convert a codepoint into its official Unicode name.

Strings ‹↑›

Text (which is a series of characters) is referred to as a 'string' in nearly all programming languages.

some interesting symbols
u+2708 dec:9992 - airplane

declare a private string constant in a class file

 private static final String PACKAGE = "javax.swing.";

determine of a string contains a character

useful classes for dealing with strings
String - the most important class has lots of good methods
StringBuilder - for concatenating strings progressively
StringBuffer - exactly like StringBuilder but synchronized

append something to a string (but use a StringBuilder instead)

 String text = "tree"; text += ": ";

use regular expressions to check if a string is an integer

 boolean b = java.util.regex.Pattern.matches("^\\d*$", "1245");

write a string 'text' to a file 'test.txt'

    PrintWriter out = new PrintWriter("test.txt");
    out.println(text); out.flush(); out.close();

StringBuilder (since Java 1.5) is not synchronized, and is therefore more efficient, but not to be used in threads. StringBuffer can be used in threads. They have the same methods. Use StringBuilder unless you really are trying to share a buffer between threads

insert integers at the beginning of a StringBuilder (inefficient)

StringBuilder sb = new StringBuilder(); for (int i=0;i<100;i++) { sb.insert(0, Integer.toString(i)); } ,,,

 if (s.equals("tree") {}
 if (s.equalsIgnoreCase("trEE")) {}
 t = "TTR".toLowerCase();
 t = "TTR  ".trim();
 t = "TTR".indexOf('R');
 t = "TTR".indexOf("TT");

Starts with and ends with

 if ("big".startsWith("bi"))
 if ("big".endsWith("ig"))

Matches

 if ("009".matches("\\d")) System.out.println("\n\nyes");

Split a string into words

 String[] ss = ("Some new words".split("\\s+")); System.out.println(ss[1]);

Substrings

 if ("abcd".indexOf('e') == -1) System.out.println("no 'e' in string");

Analysing Strings ‹↑›

check if the 2nd character of a String is uppercase

 Character.isUpperCase("hEllo".charAt(1))

Parsing Strings ‹↑›

The topic of parsing is a large one, and probably not well understood by many people. Yet it is one of the most fundamental programming processes. Here we will not go into 'pumping lemmas' context free languages or push-down automata. No no no. We will just be dealing with simple cases, using regular expression, tokenising, etc.

process each word in a string using split()

   String s = "word1 word2 word3";
   for (String word : s.split())
   {
     processWord(word);
   }

The use of StringTokenizer below may well be outdated.

process each word using a StringTokenizer

   String aString = "word1 word2 word3";
   StringTokenizer parser = new StringTokenizer(aString);
   while (parser.hasMoreTokens()) {
     processWord(parser.nextToken());
   }

Splitting Strings ‹↑›

get 2 values from a JOptionPane input dialog using split

    import javax.swing.JOptionPane;
    public class SplitDialogResult {
      public static void main(String[] args) {
        String namepass = JOptionPane.showInputDialog(
                            "enter 'name:password'", "<name:password>");
        String[] info = namepass.split(":", 2);
        System.out.format("name:%s\npass:%s\n", info[0], info[1]);
      }
    }

Declaring Strings ‹↑›

 String r, s, t;

 String s = new String("cat");

Converting To And From Strings ‹↑›

convert a String to a double

 double d = Double.valueOf("2.333").doubleValue();

convert an integer to a String

     public class ConvertInteger {
       public static void main(String[] args) {
         String s = String.valueOf(200);
         System.out.println("length:" + s.length());
       }
     }

convert a double to a String

 String s = String.valueOf(2.333);

convert a string to an integer (throws NumberFormatException)

 int i = Integer.parseInt("124")

parse a string with whitespace into an integer

 int test= Integer.parseInt(s.trim());

Substituting In Strings ‹↑›

substitute in strings

     String t = new String("Content: one"
     String s = t.replace("Content:", "").replace("o", "O");

String Buffers ‹↑›

create and append something to a string buffer

      StringBuffer s = new StringBuffer("");
      s.append("hi");

Concatenating Strings ‹↑›

One can use either StringBuffer or StringBuilder to progressively add things to a string. Or else the format() method is similar to the c language 'sprintf' function.

concatenate two strings to create a third

 String s = string1.concat(string2);

using printf style format strings, for those who live in the 80s

 String.format("http://%s/manager/list", host + ":8080"));

format an integer or a long value

 String new = String.format("The rename status is (%d)", RENAME_SUCCEEDED);

use multiple values with String.format

 String new = String.format("%s is %d years old", "James", 45);

print a formatted string to standard output

   public class FormatPrint {
     public static void main(String[] args) {
       System.out.format("%s is %d years old", "James", 45);
     }
   }

 "big".substring(0,2) == "bi"
%c character %d decimal (integer) number (base 10) %e exponential floating-point number %f floating-point number %i integer (base 10) %o octal number (base 8) %s a string of characters %u unsigned decimal (integer) number %x number in hexadecimal (base 16) %% print a percent sign \% print a percent sign

concatenate 2 strings

 "A" + "B"

concatenate a string and an integer

 "A" + 2

Comparing Strings ‹↑›

Comparing strings

 System.out.println("this".compareTo("this")); // prints 0
 System.out.println("zed".compareTo("this"));  // prints 6
 System.out.println("us".compareTo("this"));   // prints 1
 System.out.println("this".compareTo("us"));   // prints -1
 System.out.println("this".compareTo("thks")); // prints -2

Regular Expressions ‹↑›

www: java.util.regex
Regular expressions are a way of describing text patterns. Regular expressions are also a way of defining a regular language which is the simplest type of formal language in the Chomski hierarchy of languages. These patterns have great significance mathematically and linguistically, but they are also of considerable practical use to programmers carrying out everyday tasks involving text processing.

Regular expressions have been available in Unix systems for many years (for example with grep, awk, sed) but became popularised through the Perl language and the need to do text processsing in (cgi) web applications.

With java, special character classes (such as \w) when written in string literals (which is nearly always) need to be escaped with 2 backslashes (for example "\\w") which looks messy.

replace all text between tree and leaf with "new" (this is 'non-greedy')

 String ResultString = subjectString.replaceAll("(tree).*?(leaf)", "$1new$2");

The $1 and $2 are back references. The .*? is non greedy matching

double all sequences of "a"s using a compiled regular expression

    Pattern p = Pattern.compile("(a+)");
    String ret = p.matcher(input).replaceAll("$1 $1");

Compiling the regular expression or pattern is supposed to be more efficient or provide better runtime performance.

match any sequence of characters which are not word chars or # or $

 Pattern p = Pattern.compile("^[\\w#$]+$");

use a matcher to print each occurence of the 2nd subgroup found

    String input = " ;1=2011-10-23T16:16:53+0530;   2=2011-10-23T16:17:53+0530;3=2011-10-23T16:18:53+0530;4=2011-10-23T16:19:53+0530;";
    Pattern p = Pattern.compile("(;\\d+?)?=(.+?);");
    Matcher m = p.matcher(input);
    while(m.find()){
      System.out.println(m.group(2));
    }

match a string starting with a digit, non-word char or whitespace char

    Pattern p = Pattern.compile("^\\d|^\\W|^\\s");
    Matcher m = p.matcher("stack overflow");  // no matches with this input

Basic Usage ‹↑›

A typical invocation using Pattern, Matcher and matcher.matchers()

    Pattern p = Pattern.compile("a*b");
    Matcher m = p.matcher("aaaaab");
    boolean b = m.matches();

a simple usage with the convenience method

 boolean b = Pattern.matches("a*b", "aaaaab");

Metacharacters ‹↑›

The meta characters supported by java regular expressions are <([{\^-=$!|]})?*+.>

Character Classes ‹↑›

summary of the available format specifiers:

examples of character classes
[^01] - matches any character which is not 0 or 1
[0-2[6-8]] - matches 012678 this is a union class
[0-4&&[3-9]] - matches only 3 or 4 this is an intersection class
[1-6&&[^345]] - matches 12 or 6, a subtraction class

Groups ‹↑›

predefined character classes
\d A digit: [0-9]
\D A non-digit: [^0-9]
\s A whitespace character: [ \t\n\x0B\f\r]
\S A non-whitespace character: [^\s]
\w A word character: [a-zA-Z_0-9]
\W A non-word character: [^\w]

Backreferences ‹↑›

examples of groups
(it){3} - matches 'ititit'

Matching Patterns ‹↑›

The String.matches() and Pattern.matches() methods both match on all of the supplied string- in other words "hello".matches("lo") returns false but "hello".matches(".*lo") will return true. This may be surprising to the unsuspecting.

check if '1245' contains only digits.

 boolean b = java.util.regex.Pattern.matches("^\\d*$", "1245");

The code above is a simple way to perform a pattern match check on a string, using the static method.

a matcher loop example

   import java.util.regex.Pattern;
   import java.util.regex.Matcher;
   public class MatcherLoop {
     public static void main(String[] args) {
       Pattern pattern =
         Pattern.compile("[^ ]*");
       Matcher matcher =
         pattern.matcher("one fine day in the forest");
       boolean found = false;
       while (matcher.find()) {
         System.out.format(
          "Found the text '%s' starting at " +
          "index %d and ending at index %d.%n",
          matcher.group(), matcher.start(), matcher.end());
         found = true;
       }
       if (!found) System.out.format("No match found.%n");
     }
   }

see if a string starts with a space (this prints 'false')

 System.out.println("A big tree".matches("^ .*"));

test if a string starts with a 'word' character (letter)

 System.out.println("A big tree".matches("^\\w.*"));

This prints 'true'

Replacing Patterns ‹↑›

Replace all whitespace with tab characters

 System.out.println("the green grass".replaceAll("\\s+", "\t"));

Replace all whitespace with a dot '.'

 System.out.println("the green grass".replaceAll("\\s+", "."));

split a string into words using the 'split' method

    public class Test
    {
      public static void main(String[] args) {
        String[] splitString = ("Some new words".split("\\s+"));
        for (String word : splitString) {
          System.out.println(word);
        }
      }
    }

use compiled patterns and matching loops

      Pattern pattern = Pattern.compile("\\w+");
      Matcher matcher = pattern.matcher("some test string");
      
      while (matcher.find()) {
        System.out.print("Start index: " + matcher.start());
        System.out.print(" End index: " + matcher.end() + " ");
        System.out.println(matcher.group());
      }

replace all occurances of whitespace with tabs

     Pattern pat = Pattern.compile("\\s+");
     Matcher m = pat.matcher("The green grass");
     System.out.println(m.replaceAll("\t"));

use the String built in pattern matching

   public class PatternTest {
     public static final String S = 
       "This is my small example string for testing";
     public static void main(String[] args) {
       System.out.println(S.matches("\\w.*"));
       String[] splitString = (S.split("\\s+"));
       for (String string : splitString) {
         System.out.println(string);
       }
       // Replace all whitespace with tabs
       System.out.println(S.replaceAll("\\s+", "\t"));
     }
   }

use compiled patterns and matching loops ------- Pattern pattern = Pattern.compile("\\w+"); Matcher matcher = pattern.matcher("some test string");

// Check all occurances while (matcher.find()) { System.out.print("Start index: " + matcher.start()); System.out.print(" End index: " + matcher.end() + " "); System.out.println(matcher.group()); } ,,,

replace all occurance of whitespace with tabs

    Pattern replace = Pattern.compile("\\s+");
    Matcher matcher2 = replace.matcher("some example string");
    System.out.println(matcher2.replaceAll("\t"));

Compiled Patterns ‹↑›

compile a pattern to match without regard for letter case

 Pattern.compile("s+", Pattern.CASE_INSENSITIVE);

Case Insensitive Matching ‹↑›

Before jdk 6update2 there were some problems with case insensitive matching for unicode characters in java regular expressions. Namely UNICODE_CASE was equivalent to case insensitive matching.

create a case-insensitive pattern for Ascii characters only >jdk6u2

 Pattern p = Pattern.compile("YOUR_REGEX", Pattern.CASE_INSENSITIVE);

a case-insensitive pattern for Unicode characters

 Pattern p = Pattern.compile("YOUR_REGEX", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);

case-insensitive matching on a String for ascii characters only

 "XYZxyz".matches("(?i)[a-z]+")

case-insensitive matching on a String for unicode characters >jdk6u2

 "XYZxyz".matches("(?iu)[a-z]+")

match 'green' and 'tree' case insensitively but only those words

 strText.Matches("(?i:green)[a-z ]+(?i:tree)" )

User Input From The Console ‹↑›

a loop to receive user input from the console

   import java.io.Console;
   public class ConsoleLoop {
     public static void main(String[] args) {
       Console console = System.console();
       if (console == null) {
         System.err.println("No console.");
         System.exit(1);
       }
       while (true) {
         String s = console.readLine("%nEnter your regex: ");
         boolean found = false;
       }
     }
   }

Unicode Regular Expressions ‹↑›

match a range of unicode characters

 "[\\u00e0-\\u00e5]"

examples of backreferences
(it)\1 - matches the string 'itit'

Printing ‹↑›

Java includes support for printing Java2D graphics and other information.

unicode classes
\*\\u0400-\\u04f9 - Cyrillic
*\\u0080-\\u00ff - Latin-1 Supplement

relevant packages
java.awt.print.* - print Graphic2D objects
javax.print.* - java print service discover printers

show a page setup dialog

    PrinterJob pj = PrinterJob.getPrinterJob();
    PageFormat pf = pj.pageDialog(pj.defaultPage());

display a print dialog for setting number of copies etc

    import java.awt.print.*;
    ...
    PrinterJob job = PrinterJob.getPrinterJob();
    job.setPrintable(new HelloWorldPrinter());
    boolean doPrint = job.printDialog();
    ...
    class HelloWorldPrinter implements Printable { ... }

a 2d printing example

   import java.awt.print.*;
   ...
   PrinterJob job = PrinterJob.getPrinterJob();
   job.setPrintable(new HelloWorldPrinter());
   boolean doPrint = job.printDialog();
   if (doPrint) {
     try {
       job.print();
     } catch (PrinterException e) {
       // The job did not successfully complete
     }
   }
   class HelloWorldPrinter implements Printable {}

a complete example of 2d printing

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import java.awt.print.*;
   
   public class HelloWorldPrinter implements Printable, ActionListener {
     public int print(Graphics g, PageFormat pf, int page) throws
           PrinterException {
       if (page > 0) { 
         /* only one page, and page is zero-based */
         return NO_SUCH_PAGE;
       }
       /* User (0,0) is typically outside the imageable area, so we must
        * translate by the X and Y values in the PageFormat to avoid clipping
        */
       Graphics2D g2d = (Graphics2D) g;
       g2d.translate(pf.getImageableX(), pf.getImageableY());
       /* Now we perform our rendering */
       g.drawString("Hello world!", 100, 100);
       // tell the caller that this page is part of the printed document 
       return PAGE_EXISTS;
     }
   
     public void actionPerformed(ActionEvent e) {
       PrinterJob job = PrinterJob.getPrinterJob();
       job.setPrintable(this);
       boolean ok = job.printDialog();
       if (ok) {
         try { job.print(); }
         catch (PrinterException ex) {
           // The job did not successfully complete 
           ex.printStackTrace();
         }
       }
     }
   
     public static void main(String args[]) {
       JButton printButton = new JButton("Print Something");
       printButton.addActionListener(new HelloWorldPrinter());
       JFrame f = new JFrame("A Simple Printing Example");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add("Center", printButton);
       f.pack(); f.setVisible(true);
     }
   }

System Information ‹↑›

Systemproperties ‹↑›

Using the System.getProperties() method we can retrieve some important information about the system on which the current java vm is running. unsigned Applets may only be able to access some of these system properties.

list all the system properties

   public class SystemProps {
     public static void main(String[] args) {
       java.util.Properties p = System.getProperties();
       java.util.Enumeration en = p.propertyNames();
       while (en.hasMoreElements()) {
         String name = (String) en.nextElement();
         System.out.format("%s: %s\n", name, p.getProperty(name));
       }
     }
   }

Operating System Interaction ‹↑›

While Java is supposed to be a 'platform independant' system, at times one wants to know about, and use, features of the operating system on which the Java Runtime Engine is running.

display the operating system name and version

   import javax.swing.JOptionPane;
   public class OsType {
     public static void main(String[] args) {
       String info = String.format("os.name: %s, os.version: %s",
          System.getProperty("os.name"), System.getProperty("os.version"));
       JOptionPane.showMessageDialog(null, info);
     }
   }

Executing Programs ‹↑›

There may be an occasion when Java is unable to perform the task that is required. In this case you may execute a program which is installed in the underlying operating system from within your Java program.

start the 'notepad' text editor in a new thread

 proc = Runtime.getRuntime().exec("notepad");

In the example below, the input and error streams should probably be closed in a 'finally' block.

a simple method to execute an 'external' program and read the output

   import java.io.*;
   public class Sys {
     public static void exec(String command) {
       System.out.println(":> " + command);
       try {
         String line;
         Process p = Runtime.getRuntime().exec(command);
         BufferedReader input =
           new BufferedReader(new InputStreamReader(p.getInputStream()));
         BufferedReader error =
           new BufferedReader(new InputStreamReader(p.getErrorStream()));
         while ((line = input.readLine()) != null) { 
           System.out.println(line);
         }
         while ((line = error.readLine()) != null) { 
           System.out.println(line);
         }
         input.close();
         error.close();
       } catch (Exception err) { err.printStackTrace(); }
     }
     public static void main(String[] args) {
       Sys.exec("javac -version");
     }
   }

run a system command with environment variable

    ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
    Map<String, String> env = pb.environment();
    env.put("VAR1", "myValue");
    env.remove("OTHERVAR");
    env.put("VAR2", env.get("VAR1") + "suffix");
    pb.directory("myDir");
    Process p = pb.start();

Files And Directories ‹↑›

printing methods
job.print() - send a job to the printer cant detect paper jam
job.printDialog() - show a print dialog for selecting copies etc

File information methods
File[] listFiles() - returns all the files in the folder
long length() - returns the size of the file in bytes
boolean isDirectory() - if the file is a folder
boolean isFile() - if the file is not a folder

The code below requires the toURI() call because toURL() does not do its esaping work properly.

convert a file object to a URL

 URL u = new File("hi.txt").toURI().toURL();

get the absolute file name from a relative name.

    file = new File("dir" + File.separatorChar + "filename.txt");
    file = file.getAbsoluteFile();  // c:\temp\dir\filename.txt

create a temporary file and delete it when the program exits

  File file = File.createTempFile("realhowto",".vbs");
  file.deleteOnExit();

get the size of a file in bytes

   import java.io.File;
   public class FileSize {
     public static void main(String[] args) {
       File file = new File("FileSize.class");
       long length = file.length();
       System.out.format("The size of the file is %d bytes", length);
     }
   }

print a list of files in the current directory

   import java.io.File;
   import java.util.Arrays;
   public class Test {
     public static void main(String[] args) {
       File[] ff = (new File(".")).listFiles();
       System.out.println(Arrays.toString(ff));
     }
   }

print a list of files and their sizes in the current directory

   import java.io.File;
   import java.util.Arrays;
   public class FileList {
     public static void main(String[] args) {
       File[] ff = (new File(".")).listFiles();
       for (File file: ff)
         System.out.println(file.toString() + " " + file.length());
     }
   }

open a file within a jar file or in the local file system.

 URL url = this.getClass().getClassLoader().getResource("gameover.wav");

print the java runtime engine folder

   public class JavaHome {
     public static void main(String[] args) throws Exception {
       System.out.println(System.getProperty("java.home"));
     }
   }

List all files recursively

   import java.io.*;
   public class FileList {
       public static void listFiles(File dir) {
         File[] files = dir.listFiles();
         if (files != null) {
           for (File f : files) {
             if (f.isDirectory()) {
               listFiles(f);
             }
             else { System.out.println(f.getPath()); }
           }
         }
       }
       public static void main(String[] args) throws Exception {
         listFiles(new File("/usr/lib/jvm/java-6-sun/docs/api/java")); 
       }
     }

File Paths ‹↑›

The File object has a number of methods for extracting the path from an object.

file paths

   import java.io.*;
   public class NewFile {
     public static void main(String[] args) throws IOException {
       File f = new File("..");
       System.out.println(f.getCanonicalPath());
     }
   }

construct a file path in a cross-platform kind of way

 String file = "eg" + java.io.File.separator +"MyClass.java";

Initialising File Objects ‹↑›

The code below does not throw an exception but doesnt produce a useful existing file.

you cant initialise a file with a url string string

 File f = new File("file:.")   no wrong 

try to initialise a file object

   import java.io.*;
   public class NewFile {
     public static void main(String[] args) throws IOException {
       File f = new File("..");
       System.out.println(f.getCanonicalPath());
     }
   }

Searching For Files ‹↑›

search files using grep

 Runtime.getRuntime().exec("grep", new String[]{"-r"}, <searchText>);

The code below is possibly the simplest recursive file search class. It might be simpler to use a static method.

List all files in a folder tree that contain a string in the path

   import java.io.*;
   public class FileList implements FileFilter {
     String searchText;
     public FileList(String searchText) {
       this.searchText = searchText;
     }
     public boolean accept(File file) {
       return ((file.getAbsolutePath().indexOf(this.searchText)>0) || 
         file.isDirectory());
     }
     public void list(File dir) {
       for (File f: dir.listFiles(this)) {
           if (f.isDirectory()) { this.list(f); }
           else System.out.println(f.getPath());
       }
     }
     public static void main(String[] args) throws Exception {
       File dir = new File("/home/");
       FileList searcher = new FileList(".mp3");
       searcher.list(dir);
     }
   }

List all files recursively that contain a string in the path

   import java.io.*;
   public class FileList {
     public static void list(File dir, final String filter) {
       FileFilter ff = new FileFilter(){
         public boolean accept(File file) {
           return ((file.getAbsolutePath().indexOf(filter)>0) || 
                    file.isDirectory());
         }
       };
       File[] files = dir.listFiles(ff);
       if (files != null) {
         for (File f : files) {
           if (f.isDirectory()) { FileList.list(f, filter); }
           else System.out.println(f.getPath());
         }
       }
     }
     public static void main(String[] args) throws Exception {
       File dir = new File("/usr/lib/jvm/java-6-sun/docs/api/");
       FileList.list(dir, "String");
     }
   }

A non-static version of the folder search. The code below may form a useful way to select a folder which contains a certain type of file. Using 2 endsWith() methods to check for .jpg and .JPG files is slightly faster than using string.matches() The code could be made faster by returning only folders from the .list() method using a FileFilter. No the FileFilter doesnt seem to speed anything up. Also could experiment using a compiled pattern for the regular expression

With a regular expression (string.matches) on an eee netbook

 Searched 3261 folders in 3048 miliseconds

Using 2 'endsWith()' method calls to search the results were

 Searched 3261 folders in 2698 miliseconds

List all folders that contain at least one '.jpg' file in them

   import java.io.*;
   import java.util.*;
   public class JpegFolderList {
     List<File> folders;
     int foldersSearched;
     File rootFolder;
     boolean searchHidden;

     public JpegFolderList(String rootFolder) {
       this.searchHidden = false;
       this.rootFolder = new File(rootFolder);
       this.foldersSearched = 0;
       this.folders = new ArrayList<File>(); 
     }

     public List<File> getFolders() { return this.folders; }
     public int getFoldersSearched() { return this.foldersSearched; }
     public File getRoot() { return this.rootFolder; }
     public void searchHidden(boolean b) {
       // set if unix hidden folders (.xxx) will be searched
     }
     /** tests if a folder contains at least one .jpg file */
     public boolean hasJpeg(File file) {
       if (!file.isDirectory()) return false;
       for (String name: file.list()) {
         if (name.matches(".*(?i)\\.jpg$")) return true; 
       }
       return false;
     }
     /** compiles a List of folders containing jpegs */
     public void findJpegFolders(File dir) {
       this.foldersSearched++;
       /*
       if ((foldersSearched % 20) == 0)
         System.out.println("Folders searched: " + this.foldersSearched);
       */
       if (!dir.isDirectory()) return;
       // whether to search unix hidden folders
       if (!this.searchHidden) {
         if (dir.getPath().startsWith(".")) return;
       }
       for (File f: dir.listFiles()) {
         if (f.isDirectory()) { 
           if (this.hasJpeg(f)) { this.folders.add(f); }
           this.findJpegFolders(f);
         }
       }
     }
     public static void main(String[] args) {
       long startTime = System.currentTimeMillis();
       File dir = new File("/home/matth3wbishop/");
       JpegFolderList list = new JpegFolderList("/home/matth3wbishop/");
       list.findJpegFolders(list.getRoot());
       for (File f: list.getFolders())
         System.out.println(f.getPath());
       long loadTime = System.currentTimeMillis() - startTime;
       System.out.format(
         "Searched %d folders in %d miliseconds\n" +
         "Found %d folders containing .jpg files", 
         list.getFoldersSearched(), loadTime, list.getFolders().size());
     }
   }

List all folders that contain at least one '.jpg' file in them

   import java.io.*;
   import java.util.*;
   public class JpegFolderList {
     public static List<File> folders = new ArrayList<File>(); 
     public static int progress = 0;
     /** tests if a folder contains at least one .jpg file */
     public static boolean hasJpeg(File file) {
       if (!file.isDirectory()) return false;
       for (String name: file.list()) {
         if (name.endsWith(".jpg") || name.endsWith(".JPG")) 
           return true; 
       }
       return false;
     }

     /** compiles a List of folders containing jpegs */
     public static void getJpegFolders(File dir) {
       progress++;
       if ((progress % 20) == 0)
         System.out.println("Folders searched: " + progress);
       if (!dir.isDirectory()) return;
       // dont search hidden folders
       if (dir.getPath().startsWith(".")) return;
       for (File f: dir.listFiles()) {
         if (f.isDirectory()) { 
           //System.out.println(f.getPath());
           if (JpegFolderList.hasJpeg(f)) { folders.add(f); }
           JpegFolderList.getJpegFolders(f);
         }
       }
     }
     public static void main(String[] args) throws Exception {
       File dir = new File("/home/matth3wbishop/");
       JpegFolderList.getJpegFolders(dir);
       for (File f: JpegFolderList.folders)
         System.out.println(f.getPath());
     }
   }

Filtering Files ‹↑›

It is possible to use the FileFilter and FilenameFilter interfaces to limit the number of files returned by file.listFiles(...) and file.list() respectively. These filters only have one method to implement namely accept(...)

Opening Files ‹↑›

The term 'opening' a file refers to the process of obtain some object (usually a stream) which can read from or write to the file.

open a file in the same folder as the Main application class

 this.getClass().getResourceAsStream()
 Class.getResourceAsStream()

In the example below, the current working directory is usually the folder from which the java application was run (and this is not necessarily the same folder where the main application class or jar resides)

open a jpg file which is in the current working directory

    URL imgUrl = new URL("file:big.jpg");
    InputStream is = imgUrl.openStream();

read a file which is in the same folder as the compiled class

    import java.net.URL;
    import java.io.*;
    public class ClassFolder {
      public static void main(String[] args) {
        try {
          InputStream in = 
            Main.class.getResourceAsStream("ClassFolder.java");
          BufferedReader br = new BufferedReader(new InputStreamReader(in));
          String line;
          while ((line = br.readLine()) != null)
            System.out.println(line);
          in.close();
        } catch (IOException e) { e.printStackTrace(); }
      }
    }

get information about the main application class

    import java.net.URL;
    public class MainName {
      public static void main(String[] args) throws Exception {
        URL main = Main.class.getResource("Main.class");
        System.out.format(
          "Main protocol: %s \nMain path: %s \nMain url: %s", 
          main.getProtocol(),
          main.getPath(),
          main.toString());
      }
    }

open the compiled main class within a jar or normal class file

    import java.net.URL;
    import java.io.*;
    public class OpenMain {
      public static void main(String[] args) {
        try {
          InputStream in = Main.class.getResourceAsStream("Main.class");
          /* do something here */
          in.close();
        } catch (IOException e) { e.printStackTrace(); }
      }
    }

Text Files ‹↑›

read and display text file line by line, using default encoding ---- import java.io.*; public class FileReadTest { public static void main(String[] args) throws Exception { String line; File f = new File("FileReadTest.java"); BufferedReader in = new BufferedReader(new FileReader(f)); while ((line = in.readLine()) != null) System.out.println(line); in.close(); } } ,,,

read a text file into a string buffer line by line

    import java.io.*;
    public class FileReadTest {
      public static void main(String[] args) throws Exception {
        String line;
        File f = new File("FileReadTest.java");
        BufferedReader in = new BufferedReader(new FileReader(f));
        StringBuffer result = new StringBuffer();
        while ((line = in.readLine()) != null)
          result.append(line + "\n");
        in.close();
        System.out.println(result);
      }
    }

---- BufferedReader br = new BufferedReader(fr); String buffer; StringBuffer result = new StringBuffer(); while ((buffer = br.readLine()) != null) { result.append(buffer); } ,,,

It would probably be faster to read into a larger buffer (8k ?) rather than just one line.

Folders ‹↑›

list all files in the current folder

   import java.io.File;
   import java.util.Arrays;
   public class ListFiles {
     public static void main(String[] args) {
       System.out.format("%s is %d years old", "James", 45);
       File f = new File(".");
       File[] ff = f.listFiles();
       System.out.println(Arrays.toString(ff));
     }
   }

list java files in the current folder

   import java.io.*;
   import java.util.Arrays;
   public class ListFiles {
     public static void main(String[] args) {
       System.out.format("%s is %d years old", "James", 45);
       File f = new File(".");
       File[] ff = f.listFiles(new FilenameFilter() {
         public boolean accept(File dir, String name) {
          return name.endsWith("java");
         }
       });
       System.out.println(Arrays.toString(ff));
     }
   }

File System Types ‹↑›

list file system labels or names

   import java.io.File;
   import java.util.Arrays;
   import java.util.List;
   import javax.swing.filechooser.FileSystemView;
   
   public class FileSystemLabels {
     public static void main(String args[]) {
       List <File>files = Arrays.asList(File.listRoots());
       for (File f : files) {
         String s = 
           FileSystemView.getFileSystemView().getSystemDisplayName(f);
         System.out.println("*" + s);
       }
     }
   }

On a Microsoft Windows computer the code above may produce something like: REGA1 (C:) My Book (F:) But on linux there is only one root, namely '/'

print the types of storage devices currently mounted as filesystems

   import java.io.File;
   import java.util.Arrays;
   import java.util.List;
   import javax.swing.filechooser.FileSystemView;
   
   public class FileSystemTest {
     public static void main(String args[]) {
       List <File>files = Arrays.asList(File.listRoots());
       for (File f : files) {
         String s = FileSystemView.getFileSystemView().getSystemTypeDescription(f);
         System.out.println("*" + s);
       }
       /* sample output (French WinXP)
             *Disquette 3 1/2 pouces
             *Disque local
             *Lecteur CD
             *Disque local
       */
     }
   }

The code above doesnt produce any results on a linux computer. the above is from rgagnon.com

Input And Output ‹↑›

get one line of input from the user

     BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
     in.readLine();

Scanner ‹↑›

use the Scanner class to get and parse user input

    import java.util.Scanner;
    public class ScannerTest {
     public static void main(String[] args) {
       String s = "";
       Scanner input = new Scanner(System.in);
       System.out.println("enter something, 'q' to end");
       while (!s.equals("q")) {
         s = input.next();
         System.out.println("entered: " + s);
       }
     }
   }

read all numbers from a string, ignoring anything else

    import java.util.Scanner;
    public class NumberScanner {
      public static void main(String args[]) {
        String s = "10 99.88 words 44.1 are ignored. Only numbers 3.1";
        Scanner scan = new Scanner(s);
        while (scan.hasNext()) {
          if (scan.hasNextDouble()) 
            System.out.println(scan.nextDouble());
          else scan.next();
        } 
      }
    }

Streams ‹↑›

Streams are an important concept. Essentially a stream is a first in last out (filo) queue or buffer. An important feature of a stream is that a program can start reading from the beginning of a stream before the entire contents of the stream become available.

Filtering Streams ‹↑›

The Unix/Linux operating system makes heavy use of stream 'filters' which are programs which operate on a stream changing its content is some way. The importance of these filters is that they can be 'chained' together (using pipes - represented by the | bar symbol in a command shell) thus creating more complex filters from simpler ones.

Standard Input Stream ‹↑›

Text Files ‹↑›

read long integers from a text file

     // since 1.6
     Scanner scanner = new Scanner(new File("numbers.txt"));
     while (scanner.hasNextLong())
       { long aLong = scanner.nextLong(); }

read a textfile line by line

     try {
       BufferedReader in = 
         new BufferedReader (new FileReader("infilename"));
       String s;
       while ((s = in.readLine()) != null)
         { System.out.println(s); }
       in.close ();
     } catch (IOException e) { }

read either a file or a Url (file://c:/.. or http://)

      URL url = new URI(http://www.google.com).toURL();
      URLConnection conn = url.openConnection ();
      Reader rd = new InputStreamReader (conn.getInputStream ());

reading a utf-8 file in a non utf-8 locale

     FileInputStream fis = new FileInputStream("test.txt");
     InputStreamReader in = new InputStreamReader(fis, "UTF-8"); 

Reading And Writing Text Files ‹↑›

FileReader and FileWriter can only use the default system encoding

read a file which is encoded in utf8

  FileInputStream fis = new FileInputStream("test.txt"); 
  InputStreamReader in = new InputStreamReader(fis, "UTF-8");

write a text file encoded as utf8

    FileOutputStream fos = new FileOutputStream("test.txt"); 
    OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");

If the encoding is not specified then the default system encoding is used

read utf8 text data from a file

import java.io.*; public class FileReadTest { public static void main(String[] args) { try { File file = new File("c:\\temp\\test.txt"); BufferedReader in = new BufferedReader( new InputStreamReader(new FileInputStream(file), "UTF8")); String str; while ((str = in.readLine()) != null) { System.out.println(str); } in.close(); } catch (UnsupportedEncodingException e) { System.out.println(e.getMessage()); } catch (IOException e) { System.out.println(e.getMessage()); } catch (Exception e) { System.out.println(e.getMessage()); } } } ,,,

Writing Text ‹↑›

write utf8 text data to a file

import java.io.*; public class test { public static void main(String[] args){ try { File file = new File("c:\\temp\\test.txt"); Writer out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(file), "UTF8")); out.append("Website UTF-8").append("\r\n"); out.append("??????? UTF-8").append("\r\n"); out.flush(); out.close(); } catch (UnsupportedEncodingException e) { System.out.println(e.getMessage()); } catch (IOException e) { System.out.println(e.getMessage());} catch (Exception e) { System.out.println(e.getMessage());} } } ,,,

The BufferedWriter class has a .newLine() method, but it uses the default newline character(s) for the system.

Working With Html ‹↑›

http://www.exampledepot.com/egs/javax.swing.text.html/pkg.html an example of getting the links in an html document

Fonts ‹↑›

The default fonts for Java are not very pleasant. They dont seem to be well antialiases or smoothed and this does alot to put people of developing in Java even before they get started

Fonts bundled with the Java development kit are stored in

 J:\Program Files\java\jdk1.7.0_04 \jre\lib\fonts\.

They are only available to java applications unless they are explicitly installed in the Windows or Unix font repositories

Logical Fonts ‹↑›

The logical font families may span several actual fonts in order to include many glyphs.

File manipulation methods
boolean renameTo(File) - rename (move) the file

the Java logical font families
Serif
SansSerif
Monospaced - fixed-width pitch glyphs
Dialog
DialogInput.

create a new monospace courier font, size 20 points

 Font font = new Font("Courier", Font.PLAIN, 20);

make a bold serifed font, 10 points in size

 Font font = new Font("Serif", Font.BOLD, 10);

create a 24 point italic font

 Font f = new Font("Times New Roman", Font.ITALIC, 24);

get all available font family names

      GraphicsEnvironment ge =  
        GraphicsEnvironment.getLocalGraphicsEnvironment();
      String fontNames[] = ge.getAvailableFontFamilyNames();

show a list of all available font families and select one

    import javax.swing.*;
    import java.awt.*;
    public class FontList {
      public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
       public void run() {
        GraphicsEnvironment ge =  
          GraphicsEnvironment.getLocalGraphicsEnvironment();
        String fontNames[] = ge.getAvailableFontFamilyNames();
        Object r = JOptionPane.showInputDialog(
           null, "Choose a font:", "Available Fonts",
           JOptionPane.PLAIN_MESSAGE, null, fontNames, fontNames[0]);
        System.out.println("font selected: " + r);
        }
       });
      }
    }

displays fonts in a listbox and uses the font for the item

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

   public class ShowFonts {
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           GraphicsEnvironment ge = GraphicsEnvironment.
                                    getLocalGraphicsEnvironment();
           String[] fonts = ge.getAvailableFontFamilyNames();
           JList fontChooser = new JList(fonts);
           fontChooser.setCellRenderer(new FontCellRenderer());
           JOptionPane.showMessageDialog(
             null, new JScrollPane(fontChooser));
         }
       });
     }
   }
   
   class FontCellRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object value, int index, boolean isSelected,
       boolean cellHasFocus) 
     {
       JLabel label = (JLabel)super.getListCellRendererComponent(
                        list,value,index,isSelected,cellHasFocus);
       Font font = new Font((String)value, Font.PLAIN, 20);
       label.setFont(font);
       return label;
     }
   }

displays fonts in a combobox and uses the font for the item

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

   public class ShowFonts {
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           GraphicsEnvironment ge = GraphicsEnvironment.
                                    getLocalGraphicsEnvironment();
           String[] fonts = ge.getAvailableFontFamilyNames();
           JComboBox fontChooser = new JComboBox(fonts);
           fontChooser.setRenderer(new FontCellRenderer());
           JOptionPane.showMessageDialog(null, fontChooser);
         }
       });
     }
   }
   
   class FontCellRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object value, int index, boolean isSelected,
       boolean cellHasFocus)
     {
       JLabel label = (JLabel)super.getListCellRendererComponent(
                        list,value,index,isSelected,cellHasFocus);
       Font font = new Font((String)value, Font.PLAIN, 20);
       label.setFont(font);
       return label;
     }
   }

displays a list of fonts available in a list box

    import javax.swing.*;
    import java.awt.*;
    public class FontList {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        GraphicsEnvironment ge =  
          GraphicsEnvironment.getLocalGraphicsEnvironment();
        String fontNames[] = ge.getAvailableFontFamilyNames();
        JList lb = new JList(fontNames);
        JPanel p = new JPanel();
        p.add(new JScrollPane(lb));
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setLocationRelativeTo(null);
        t.setVisible(true);
      }
    }

displays all fonts in labels

    import javax.swing.*;
    import java.awt.*;
    public class FontList {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        Font font; JLabel label;
        String name = new String();
        String[] fonts = 
          GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
        JPanel p = new JPanel(new GridLayout(0, 1));
        for (int i = 0; i < fonts.length; i++) {
          name = fonts[i]; 
          font = new Font(name, Font.PLAIN, 20);
          label = new JLabel(name + " glyphs:" + font.getNumGlyphs());
          label.setFont(font);
          p.add(label);  
        }
        t.getContentPane().add(new JScrollPane(p));
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.setExtendedState(Frame.MAXIMIZED_BOTH); t.pack(); 
        t.setVisible(true);
      }
    }

create a JLabel with a large Georgia font in grey colour

    import javax.swing.*;
    import java.awt.*;
    public class LabelFont {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        Font font = new Font("Georgia", Font.PLAIN, 40);
        JLabel l = new JLabel("This is the Georgia Font size 40");
        l.setFont(font);
        l.setForeground(Color.gray);
        JPanel p = new JPanel(); p.add(l);
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setVisible(true);
      }
    }

By using grey instead of black the java fonts dont look quite as bad as normal.

print something like "mono bold" etc

 fonts.getName();

print all font family names to standard output

    import java.awt.Font; 
    import java.awt.GraphicsEnvironment;
    public class FontTest {
      public static void main(String[] args) {
        Font[] fonts = 
          GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        for (int i = 0; i < fonts.length; i++)
        {
          String familyName = fonts[i].getFamily();
          System.out.println(i + ": " + familyName);
        }
       }
     }

Antialiasing Fonts ‹↑›

The Graphics2D class and Swing components support high quality anti-aliasing through the java.awt.RenderingHints class which allows us to specify the algorithm used, which in some cases can be optimised for the type of LCD screen in use.

We can antialias fonts drawn with the Graphics2D.drawString() method by setting some rendering hints. The improvement is very noticeable.

www: http://mindprod.com/jgloss/antialiasing.html
good antialias info for different versions of java
www: http://download.oracle.com/javase/7/docs/technotes/guides/2d/flags.html#aaFonts
what sun says about text antialiasing in Java 1.6 >
The following noticeably improved text antialiasing on my Gnome Linux netbook.

In java 1.6 ensure that text antialiasing is switched on

 System.setProperty("awt.useSystemAAFontSettings","on");

The java 1.6/1.7 JRE may take its text antialiasing settings from the Computer Desktop settings. In some cases this results in an inferior, or no, antialiasing technique to be used. The line above remedies that problem

some notes about particular fonts
unifont - has a lot of glyphs but unpleasant
freeserif - nice symbols for the 'miscelaneous' unicode blocks
Georgia Italic - a nice font (used by El Pais newspaper)

values for AAFontSettings in >= Java 1.6
lcd use ClearType style sub-pixel anti-aliasing.
false no anti-aliasing. Fast with jaggies.
on Gnome Best shapes/Best contrast. Not available in Windows.
gasp Windows standard anti-aliasing.
System Property Value | java.awt.RenderingHint value "off"|"false"|"default" : VALUE_TEXT_ANTIALIAS_DEFAULT "on" : VALUE_TEXT_ANTIALIAS_ON "gasp" : VALUE_TEXT_ANTIALIAS_GASP "lcd"|"lcd_hrgb" : VALUE_TEXT_ANTIALIAS_LCD_HRGB "lcd_hbgr" : VALUE_TEXT_ANTIALIAS_LCD_HBGR "lcd_vrgb" : VALUE_TEXT_ANTIALIAS_LCD_VRGB "lcd_vbgr" : VALUE_TEXT_ANTIALIAS_LCD_VBGR

In java 1.6 it seems that some AA settings come from the os. You can see these in Toolkit.getDesktopProperty(awt.font.desktophints)

turn on antialiased text in Java 1.5

 java.exe -Dswing.aatext=true

we can antialias g2d.drawString() text with either of the following

  g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                     RenderingHints.VALUE_ANTIALIAS_ON);
            //or
  g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                     RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

comparing aliased and antialiased fonts with g2d.drawString()

   import javax.swing.*;
   import java.awt.*;
   import java.text.AttributedString;
   import java.awt.font.TextAttribute;
   import java.util.*;
   public class AntialiasTextPanel extends JPanel {
     public AntialiasTextPanel() {
       super();
     }
     @Override
     public void paintComponent(Graphics gg) {
       Graphics2D g = (Graphics2D) gg;
       super.paintComponent(g);
       Font font = new Font("Georgia", Font.PLAIN, 60);
       g.setFont(font);
       g.drawString("Not Anti-aliased", 50, 50);
       g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                          RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
       g.drawString("Anti-aliased", 50, 130);
     }
     public Dimension getPreferredSize() {
       return new Dimension(500, 500);
     }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new AntialiasTextPanel());
     }
   }

In the example below, the quality of the anti-aliasing for the drawString() method and the text contained in the JTextField seems to be the same.

compare antialiasing in a JTextField and with drawString()

   import javax.swing.*;
   import java.awt.*;
   public class TextPanel extends JPanel {
     JTextField field;
     Font font;
     public TextPanel() {
       super();
       this.font = new Font("Georgia", Font.PLAIN, 60);
       this.field = new JTextField("Aliased");
       this.field.setFont(this.font);
       this.add(this.field);
     }
     @Override
     public void paintComponent(Graphics gg) {
       Graphics2D g = (Graphics2D) gg;
       super.paintComponent(g);
       g.setFont(this.font);
       g.drawString("Not Anti-aliased", 50, 130);
       g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                          RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
       g.drawString("Anti-aliased", 50, 200);
     }
     public Dimension getPreferredSize() {
       return new Dimension(500, 500);
     }
     public static void main(String[] args) {
       // the next line may improve Swing JTextComponent antialiasing
       System.setProperty("awt.useSystemAAFontSettings","on");
       JOptionPane.showMessageDialog(null, new TextPanel());
     }
   }

antialias text in a JLabel - untested, this seems unnecessary

   JLabel lblFont = new JLabel() {
     @Override
     public void paintComponent(Graphics g) {
       Graphics2D graphics2d = (Graphics2D) g;
       graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                   RenderingHints.VALUE_ANTIALIAS_ON);
       super.paintComponent(g);
     }
   };

turn on/off? antialiasing in some older java versions - untested

    jtextcomponent.putClientProperty(
     com.sun.java.swing.SwingUtilities2.AA_TEXT_PROPERTY_KEY, Boolean.TRUE);

Drawing With Fonts ‹↑›

create shapes from character glyphs and then use those shapes to draw

   Font font = new Font("Serif", Font.BOLD, 10);  // a basic font
   // a scaled up version
   Font bigfont =
     font.deriveFont(AffineTransform.getScaleInstance(30.0, 30.0));
   GlyphVector gv = bigfont.createGlyphVector(g.getFontRenderContext(),                 "JAV");
   Shape jshape = gv.getGlyphOutline(0);   // Shape of letter J
   Shape ashape = gv.getGlyphOutline(1);   // Shape of letter A
   Shape vshape = gv.getGlyphOutline(2);   // Shape of letter V
   g.fill(jshape);

http://www.javadocexamples.com/java_source/__/tt/TTFontDemo.java.html an example of loading a true type font from an input stream

http://www.javadocexamples.com/java/awt/Font/deriveFont(int%20style,float%20size).html some interesting java examples

Loading Fonts ‹↑›

how to load a font from a file

   // First, see if we can load the font file.
   InputStream is = this.getClass().getResourceAsStream(fontFileName);
   if (is == null) {
     throw new IOException("Cannot open " + fontFileName);
   }
   // createFont makes a 1-point font, bit hard to read :-)
   Font ttfBase = Font.createFont(Font.TRUETYPE_FONT, is);
   // So scale it to 24 pt.
   Font ttfReal = ttfBase.deriveFont(Font.PLAIN, 24);

a japanese font loading example

   // Create a label in Japanese.
   String message = "かつ、尊厳と権利とについて平等である。";
   JLabel label = new JLabel(message);
   // Load the TrueType font with Japanese characters and apply it.
   File file = new File("msmincho.ttf");
   Font font = Font.createFont(Font.TRUETYPE_FONT, file);
   font = font.deriveFont(Font.PLAIN, 14f);
   label.setFont(font);

check whether a font has a glyph to display a specified character

 font.canDisplay(char c)

there are a number of other canDisplay methods

create a font from a file or stream bundled with an application

 font.createFont(int fontFormat, InputStream fontStream)

Transforming Fonts ‹↑›

we apply rotates/scales/shears to fonts

 deriveFont(AffineTransform trans)

create a backward slanting font with a shear transform

Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Font font = new Font("Serif", Font.PLAIN, 24); float x = 20, y = 20; AffineTransform at = new AffineTransform(); at.shear(.2, 0); Font fontShear = font.deriveFont(at); g2.setFont(fontShear); g2.drawString("font.deriveFont(at)", x, y += 30); ,,,

Derived Fonts ‹↑›

increase the size of a font by 2 points

 font = font.deriveFont(font.getSize2D() + 2.0f);

getSize2D returns a float value

make a bold italic version of the current font

 font = font.deriveFont(Font.ITALIC + Font.BOLD);

create a derived font with a map of text attributes

Font font = new Font("Serif", Font.PLAIN, 24); float x = 20, y = 20; Hashtable attributes = new Hashtable(); attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); Font fontBold = font.deriveFont(attributes); g2.setFont(fontBold); g2.drawString("font.deriveFont(attributes)", x, y += 30); ,,,

Font Size ‹↑›

increase the size of a font in a JTextArea component

    Font font = textArea.getFont();
    float size = font.getSize() + 1.0f;
    textArea.setFont( font.deriveFont(size) );

the same as above but conflated

 ta.setFont(font.deriveFont(ta.getFont().getSize()+1.0f));

Font Metrics ‹↑›

create a new image and determine its font metrics

   BufferedImage image = 
     new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
   Graphics2D g = (Graphics2D)image.getGraphics();
   FontMetrics fm = g.getFontMetrics();
   int w = fm.stringWidth("Hello");
   int h = fm.getHeight() + fm.getMaxDescent();

The Java2D api allow more precise ways to get font metrics than the old AWT FontMetrics class.

get the bounding rectangle for a string in a font


  Graphics2D g;  
  Font f;                           // Initialized elsewhere
  String message = "Hello World!";  
  Rectangle2D box;          // The display box: initialized elsewhere

  // Measure the font and the message
  FontRenderContext frc = g.getFontRenderContext();
  Rectangle2D bounds = f.getStringBounds(message, frc);
  LineMetrics metrics = f.getLineMetrics(message, frc);
  float width = (float) bounds.getWidth();     // The width of our text
  float lineheight = metrics.getHeight();      // Total line height
  float ascent = metrics.getAscent();          // Top of text to baseline

  // Now display the message centered horizontally and vertically in box
  float x0 = (float) (box.getX() + (box.getWidth() - width)/2);
  float y0 = (float) (box.getY() + (box.getHeight() - lineheight)/2 + ascent);
  g.setFont(f);
  g.drawString(message, x0, y0);

Font Information ‹↑›

get the number of glyphs contained in a font

 font.getNumGlyphs()

Japanese Fonts ‹↑›

1) Download one of the truetype fonts from here : http://www.wazu.jp/gallery/Fonts_Japanese2.html

2) Use the following code to allow your swing clients to use your fonts:

InputStream fontStream = getClass().getResourceAsStream("/locationoffontonclasspath/myfontname.ttf"); Font japaneseEnabledFont = null; boolean japaneseDisplayEnabled = false; try { japaneseEnabledFont = Font.createFont(Font.TRUETYPE_FONT, fontStream); GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(japaneseEnabledFont); japaneseDisplayEnabled = true; } catch (Exception e) { // handle exceptions here } finally { if (fontStream != null) { try {fontStream.close();} catch (Exception e1) {} } }

Colors ‹↑›

In Java colours are colors. And grey is gray. In general when creating rgb (red, green, blue) colours, the higher the numbers the lighter the colour, and the lower the numbers the darker the colours.

http://docs.oracle.com/javase/7/docs/ nice colors in the java api table

create a new rgb colour

 Color c = new Color(int red, int green, int blue)

create a light turqoisy colour

 Color c = new Color(0, 230, 230);

In order to set the background color for many JComponent, we first have to set the component to be opaque (since by default the component will be transparent).

set the background colour for a JLabel

     JLabel label = new JLabel("A rounded corner border");
     label.setOpaque(true);
     label.setBackground(Color.orange);

set the background for a component using a hex string for the colour

 this.setBackground(new Color(Integer.decode("#eeff99")));

colours in rgb format

 red is (255, 0, 0)
 green is (0, 255, 0)
 white is (255, 255, 255)
 black is (0,0,0)

mix colors using the HSB color model when creating a new colour

 Color c = Color.getHSBColor(hue, saturation, brightness)

The hue parameter is a decimal number between 0.0 and 1.0 which indicates the hue of the color. You'll have to experiment with the hue number to find out what color it represents.

The saturation is a decimal number between 0.0 and 1.0 which indicates how deep the color should be. Supplying a "1" will make the color as deep as possible, and to the other extreme, supplying a "0," will take all the color out of the mixture and make it a shade of gray.

The brightness is also a decimal number between 0.0 and 1.0 which obviously indicates how bright the color should be. A 1 will make the color as light as possible and a 0 will make it very dark.

A swing textarea with a foreground and background colour

   import javax.swing.*;
   import java.awt.*;
   public class ColourArea {
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JTextArea ta = new JTextArea("Botany and Trees");
           ta.setForeground(Color.gray);
           ta.setBackground(Color.white);
           ta.setFont(new Font("Georgia", Font.PLAIN, 30));
           JOptionPane.showMessageDialog(null, ta);
         }
       });
     }
   }

Analysing Colors ‹↑›

use the tostring method

   import java.awt.*;
   public class ColorValues {
     public static void main(String[] args) {
        //Color c = new Color(Color.orange);
        Color c = Color.orange;
        System.out.format("toString(): %s\n", c.toString());
     }
   }

Mixing Colors ‹↑›

It would be nice to be able to 'mix' colours in the same way that an artist mixes them on a palette. But what is the mathematics of this.

Brightness And Darkness ‹↑›

Java has some useful methods for making a colour brighter or darker. This has to do with the amount of saturation (I think).

a trick to create nice gradients using the brighter() and darker()

  GradientPaint gp = new GradientPaint(0, 0,
             getBackground().brighter().brighter(), 0, getHeight(),
             getBackground().darker().darker());

The example below may allow us to learn how to mix darker colours.

display named colours, darker variants and rgb values

   import java.lang.reflect.*;
   import javax.swing.*;
   import java.awt.*;
   public class NamedColors extends JPanel {
     public NamedColors() {
       super(new GridLayout(0, 3)); 
       JLabel label;
       try {
         for (Field f: Color.class.getFields()) {
           if (f.getType().equals(Color.class) && 
               !Character.isUpperCase(f.getName().charAt(0)) &&
               Modifier.isStatic(f.getModifiers())) {
              Color c = (Color)f.get(null);
              Color[] colors = {c, c.darker(), c.darker().darker()};
              for (Color color: colors) {
                label = new JLabel();
                label.setText(String.format(
                  "<html><center>%s<br> rgb[%d,%d,%d]", 
                   f.getName(), color.getRed(), color.getBlue(), 
                   color.getGreen()));
                label.setFont(new Font("Georgia", Font.ITALIC, 20));
                label.setBackground(color);
                label.setOpaque(true);
                this.add(label);
              }
           }
         }
       } catch (IllegalAccessException e) {}
     }
     public static void main(String args[]) {
       NamedColors c = new NamedColors();  
       JFrame frame = new JFrame("Named Colors and darker");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.getContentPane().add(new JScrollPane(c));
       frame.pack(); frame.setVisible(true);
     }
   }

Translucent Colors Or Colors With The Alpha Channel ‹↑›

Around about java 1.2 an interesting new capability was added to Java Colors, that is the ability to define colours with an alpha channel. The alpha channel is just a fancy name for translucency. Really the alpha channel just indicates how this color will be mixed with other colours to create the illusion of translucency. Transparency is total (1.0) traslucency and opaqueness is zero translucency.

create a darkish red color half translucent.

 Color translucentRed = new Color(150, 0, 0, 0.5);

You can create interesting GradientPaints using a translucent colour at one end and an opaque colour at the other end of the paint.

Named Colors ‹↑›

The java.awt.Color class contains several named Color fields in upper and lower case.

display the named Colors within the Color class using reflection

   import java.lang.reflect.*;
   import javax.swing.*;
   import java.awt.*;
   public class NamedColors extends JPanel {
     public NamedColors() {
       super(new GridLayout(0, 3)); 
       JLabel colorLabel;
       try {
         for (Field f: Color.class.getFields()) {
           if (f.getType().equals(Color.class) && 
               !Character.isUpperCase(f.getName().charAt(0)) &&
               Modifier.isStatic(f.getModifiers())) {
              colorLabel = new JLabel(f.getName());
              colorLabel.setFont(new Font("Georgia", Font.ITALIC, 22));
              colorLabel.setBackground((Color)f.get(null));
              colorLabel.setOpaque(true);
              this.add(colorLabel);
           }
         }
       } catch (IllegalAccessException e) {}
     }
     public static void main(String args[]) {
       JOptionPane.showMessageDialog(null, new NamedColors());
     }
   }

Choosing Colors ‹↑›

Use the JColorChooser dialog

The example below could be used as a very basic colour chooser for the java named colours. The only problem is that the color names are not displayed, because the Field.getName() method is not available to the cellrenderer.

Ideas: we could add darker() colors, and make the component a JPopupMenu, which allows multiple columns. Also the code should subclass a JComboBox or a JPanel, not be entirely in the 'main' method.

a combobox in which each row has a color

   import java.awt.*;
   import java.io.File;
   import javax.swing.*;
   import java.lang.reflect.*;
   public class ChooseColorComboBox {
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           JComboBox box = new JComboBox(new DefaultComboBoxModel());
           box.setFont(new Font("Georgia", Font.ITALIC, 22));
           try {
             for (Field f: Color.class.getFields()) {
               if (f.getType().equals(Color.class) && 
                   !Character.isUpperCase(f.getName().charAt(0)) &&
                   Modifier.isStatic(f.getModifiers())) {
                  //colorLabel = new JLabel(f.getName());
                  box.addItem((Color)f.get(null));
               }
             }
           } catch (IllegalAccessException e) {}
           box.setRenderer(new ChooseColorRenderer());
           JOptionPane.showMessageDialog(null, box);
         }
       });
     }
   }
   class ChooseColorRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object value, int index,
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel)super.getListCellRendererComponent(
         list,value,index,isSelected,cellHasFocus);
       if (value instanceof Color) {
         Color c = (Color)value;
         label.setBackground(c);
         label.setText(String.format("rgb color (%d,%d,%d)", 
           c.getRed(), c.getGreen(), c.getBlue()));
       } 
       return label;
     }
   }

Gotchas For Colors ‹↑›

You cant make the named colours any brighter because they are already as bright as they can be, but you can make them darker.

Internationalization ‹↑›

Localizing Messages ‹↑›

an example of using a properties file for messages in other languages

     file 'messages_en.properties':
     hello = Hello bye = Goodbye
     ...
     file 'messages_fr.properties':
     hello = Bonjour bye = Au Revoir
     ...

     try
     {
       // Get the resource bundle for the default locale
       ResourceBundle rb = ResourceBundle.getBundle("messages");
       String key = "hello"; String s = rb.getString (key); 
       key = "bye"; s = rb.getString(key);              
       rb = ResourceBundle.getBundle("messages", Locale.FRENCH);
       key = "hello"; s = rb.getString(key);   // Bonjour
       key = "bye"; s = rb.getString(key);     // Au Revoir
     }
     catch (MissingResourceException e)
     {
       // No ResourceBundle file or no key in the file
     }

Packages ‹↑›

how to create a package o- put 'package namea.nameb;' at the top of the .java file - place the .java file in the folder namea/nameb - compile from 'nameb' with javac class.java - run with java namea.nameb.class

Swing Gui Applications ‹↑›

The Swing set of components (called generally JComponents) is a set of graphical user interface components designed to replace the older AWT component set. The Swing apis provide a comprehensive and highly flexible set of components for building user interfaces. However at times, the Swing system can seem like a labyrinth to the new user (programmer). Hopefully the notes which follow will provide some guidance.

The term 'gui' (graphical user interface) application refers to an application which uses 'windows' in order to display various graphical components to interact with the user, such as 'text boxes', 'buttons', 'labels' and various other elements. The swing tool set replaced the older awt set in java version 1.2

www: http://www.rgagnon.com/topics/java-swing.html
good practical examples of using swing
possibly the simplest java 'gui' application
    import javax.swing.*;
    public class SimpleGui {
      public static void main(String[] args) {
        JOptionPane.showMessageDialog(null, "Hello!");
      }
    }

make an application exit when the window is closed

 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

According to the experts one should use the SwingUtilities.invokeLater(runnable) method to launch a swing application. Apparently this is to start the application on the 'Event Dispatch Thread' (EDT) which is the main swing thread which updates each of the graphical components in the application. The thread which starts from the java static main() method is *not* the EDT, in fact the main method thread exits after starting the swing edt thread.

On Linux I have noted at times some strange behaviors when using this invokeLater() method.

the correct way to start an application

   public class MainFrame extends javax.swing.JFrame {
     ...
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           new MainFrame().setVisible(true);
         }
       });
     }
   }

apparently the following 2 methods are exactly the same

 jframe.getContentPane().add(new ApplicationPanel());
 jframe.add(new ApplicationPanel());

create a simple 'windowed' application

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   
   public class ApplicationPanel extends JPanel {
     public ApplicationPanel() {
       super();
       JLabel label = new JLabel("A very simple Swing application");
       this.add(label);
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame frame = new JFrame("LabelDemo");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           frame.getContentPane().add(new ApplicationPanel());
           frame.pack(); frame.setVisible(true);
         }
       });
     }
   }

another way to start a swing application (correct)

    public static void main(String[] args) {
      Runnable r = new Runnable() {
        public void run() {
          final JFrame frame = new JFrame("Testing swing");
          ...
        }
      };
      SwingUtilities.invokeLater(r);
    }

create an empty window 300x300 pixels, centered in the screen

    import javax.swing.*;
    public class FrameTest {
      public static void main(String[] args) {
        JFrame f = new JFrame("a centered empty window");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(new java.awt.Dimension(300, 300));
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

a application skeleton which extends the JFrame window class

    import javax.swing.*;
    public class ExtendFrame extends JFrame {
      public ExtendFrame () {
        super();
        JLabel label = new JLabel("extending a jframe");
        this.getContentPane().add(label);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack(); this.setLocationRelativeTo(null);
        this.setVisible(true);
      }
      public static void main(String[] args) {
        JFrame f = new ExtendFrame();
      }
    }

Jcomponents ‹↑›

All javax.swing components descend from the JComponent and thus inherit its capabilities. The JComponent in-turn descends from the older java.awt.Component which is much less capable than the JComponent. Interestingly, all JComponents are containers which means that you essentially add any set of components you like to any swing component. An example of this is adding multiple components to a JToolTip, which by default only displays (html) text. All JComponents all support keybindings, borders, drag-and-drop and the list goes on. ...

All the swing components are subclasses of JComponent. We can therefore manipulate components in a gui in a generic way.

get a component from a built gui and cast it to its type.

    Component c = tabPane.getComponentAt(tabPane.getSelectedIndex());
    JScrollPane sp = (JScrollPane)c;

Extending And Customising Jcomponents ‹↑›

Paintcomponent Method ‹↑›

On common technique for customising the appearance of swing components is to override the paintComponent() method for the JComponent. (Note that in the AWT component system, it was the paint() method which was usually overridden). This technique allows, for example, a GradientPaint to be used as the background for the swing component, or an Image.

When drawing shapes with paintComponent() it is necessary to subtract one from the width and height of the component.

a simple paintComponent method override for a JLabel.

    import javax.swing.*;
    import java.awt.*;
    public class PaintLabel extends JLabel {
      public PaintLabel(String text) {
        super(text);
      }
      public void paintComponent(Graphics g) {
        g.setColor(Color.green);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
          }
        });
      }
    }

The example below draws an oval underneath the text of a JLabel.

override the paintComponent() method for an anonymous JLabel subclass

   import javax.swing.*;
   import java.awt.*;
   public class AnonymousLabel extends JLabel {
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JLabel label = new JLabel("paint component") {
             @Override
             public void paintComponent(Graphics g) {
               Graphics2D g2d = (Graphics2D) g;
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                               RenderingHints.VALUE_ANTIALIAS_ON);
               g2d.drawOval(0,0,this.getWidth()-1,this.getHeight()-1);
               super.paintComponent(g);
             }
           };
           label.setFont(new Font("Georgia", Font.PLAIN, 30));
           JOptionPane.showMessageDialog(null, label);
         }
       });
     }
   }

Container Components ‹↑›

Removing Components From A Container ‹↑›

remove all components from a JPanel

 jpanel.removeAll();

to remove all JLabels from a JPanel, try

    for (Component c: jpanel.getComponents()) {
      if (c instanceof JLabel) jpanel.remove(c);
    }
  ,,,,

FOCUS ....
 
  In an active Java Swing application one component has the 'keyboard focus'
  at any one time. This focus is important because it determines
  which component or components will fire and receive events- especially
  keyboard events. Knowing which component will be focussed is a times
  tricky.

  When a component is placed in a JScrollPane, the component receives focus
  (for example by tabbing, mouse click) but it seems the scrollpane does
  not. This means, for keybindings on a JTextArea in a JScrollPane we use
  the WHEN_FOCUSED input map to set up the binding.

  http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html
    The Sun tutorial on keyboard focus.

  * attempt to set the focus on a JPanel component
  >> panel.requestFocusInWindow();

  This method apparently only works after a frame.pack() method
  (for some arcane reasons). AncestorListeners may be used in cases
  where the above method is not available.

  * another method for focussing recommended by camickr- investigate
  >> jpanel.setFocusable()

  * make textField get the focus whenever frame is activated.
    jframe.addWindowFocusListener(new WindowAdapter() {
      public void windowGainedFocus(WindowEvent e) {
        textField.requestFocusInWindow();
      }
    });

According to the Sun tutorial on component focussing, you can request focus "after the component has been realized (ie after frame.pack()), but before the frame is displayed."

set a JButton to have focus before the frame is displayed

    ... 
    JButton button = new JButton("I am first");
    panel.add(button);
    frame.getContentPane().add(panel);  
    
    frame.pack();  // Realize the components.
    button.requestFocusInWindow();
    frame.setVisible(true);

more text antialias settings for java 1.6

make a jlabel focusable and draw a border when focussed

   import javax.swing.*;
   import java.awt.event.*;
   import java.awt.BorderLayout;
   public class FocusLabel extends JLabel {
     public FocusLabel(String text) {
       super(text);
       this.setFocusable(true);
       this.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent e) { requestFocus(); }
       });
       this.addFocusListener(new FocusListener() {
         public void focusGained(FocusEvent e) {
           setBorder(BorderFactory.createEtchedBorder());
         }
         public void focusLost(FocusEvent e) { setBorder(null); }
       });
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame();
           f.setSize(new java.awt.Dimension(300, 300));
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.add(new FocusLabel("A focusable JLabel"));
           f.add(new JTextField("south"), BorderLayout.SOUTH);
           f.add(new JTextField("north"), BorderLayout.NORTH);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

Focuslisteners And Focusevents ‹↑›

It is possible to perform actions when a JComponent receives or loses focus. This is achieved with a FocusListener.

a JTextField which turns background blue when it has keyboard focus

   import javax.swing.*;
   import javax.swing.plaf.*;
   import java.awt.event.*;
   import java.awt.*;
   public class FocusField extends JTextField {
     public FocusField(String text) {
       super(text);
       this.setFocusable(true);
       this.addFocusListener(new FocusListener() {
         public void focusGained(FocusEvent e) {
           FocusField.this.setBackground(Color.green); 
         } 
         public void focusLost(FocusEvent e) { 
           FocusField.this.setBackground(Color.white); 
         }
       });
     }
     public static void main(String[] args) {
       UIManager.put("TextField.font", 
         new FontUIResource("Georgia", Font.PLAIN, 30));
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame();
           f.setSize(new java.awt.Dimension(300, 300));
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.add(new FocusField("Click in here"));
           f.add(new JTextField("south"), BorderLayout.SOUTH);
           f.add(new JTextField("north"), BorderLayout.NORTH);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

Focustraversalpolicy ‹↑›

If we want to change the order in which components receive the focus in a swing application we can create a custom FocusTraversalPolicy to the frame.

To set the initially focussed component we call the getDefaultComponent() method of the FocusTraversalPolicy

Size Of Jcomponents ‹↑›

This section will discuss general techniques for dealing with swing gui components.

set a component to fill all the area of its parent

   public Dimension getPreferredSize() {
     return this.getParent().getSize(); 
   }

old methods (before java 1.4), discouraged
requestFocus
setNextFocusableComponent
etc

These methods often return 0,0 as the size. The reason is, they rely on the underlying GUI (Graphic User Interface) to compute the size, and if there is no peer object yet, there is no hook to ask the native GUI. See addNotify. If you want to manually control any of these sizes, e.g. to create a fixed size Component, override : getMinimumSize(), getMaximumSize() and getPreferredSize().

In Java version 1.5 or later, alternatively you can use Component. setMinimumSize, Component. setMaximumSize, and Component. setPreferredSize instead of overriding getXXXXsize methods.

Exiting Swing Applications ‹↑›

The people who know seem to prefer DISPOSE_ON_CLOSE to EXIT_ON_CLOSE

 f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

Jframe Windows ‹↑›

www: http://java.sun.com/docs/books/tutorial/uiswing/components/frame.html
Application windows are created using the JFrame class. These are also known as top level windows because they are not contained by any other element (window, container component ...). In order to create a new window, which will in turn contain panels, buttons, textboxes and all the other bricabrac, there are 2 choices: Create a JFrame within a main method (or other suitable method)
 JFrame f = new JFrame();
and then add stuff to it, or else subclass the JFrame, for example
 public class NewFrame extends JFrame { ...
and add the bric-abrac within the constructor method of the of the NewFrame class

create a 300x300 Window which is centered in the screen

    import javax.swing.*;
    public class NewFrame {
      public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setSize(new java.awt.Dimension(300, 300));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

It is necessary to call the "pack" method before the "setLocationRelativeTo" because java uses the pack method to work out how big the window will need to be in order to contain all its elements, so it wont be able to centre the window on the screen before that. set the size of a window. Its better to call .pack()

 jframe.setSize(220, 90);

If you call setSize, its difficult to know if the window will be big enough to display all the stuff it contains.

set the title of the window to hi

 jframe.setTitle("hi");

set the image icon in a window

 jframe.setIconImage(new ImageIcon(imgURL).getImage());

set the absolute location of the window

 f.setLocation(200,300);

make a JFrame open in the centre of the screen

 jframe.setLocationRelativeTo(null);

make the jframe open big enough to contain its components

 jframe.pack();

make the application exit when the window is closed

 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

set the size of a jframe window

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setSize(new java.awt.Dimension(300, 300));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

Contentpane For Jframe ‹↑›

The JFrame windows component contains a JPanel swing component which is referred to as the 'contentpane'. This content pane by default has a BorderLayout manager. Components can not be added to a JFrame directly but instead to its contentpane. This is done with jframe.getContentPane().add() method. The jframe.add() method is a convenience method which adds a component to the content pane (by default to the BorderLayout.CENTER position).

"The default content pane is a JPanel that uses a BorderLayout. When you add a component and don't specify a constraint, then it defaults to the CENTER. However you can only add a single component in the center so the layout manager only knows about the last one added. When the layout manager is invoked it sets the size() and location() of that component. The other component has a size of 0, so it is never painted." (camickr)

Full Screen Windows ‹↑›

On a linux system it appears that the setVisible or the show method needs to be invoked before the maximized property is set, strangely. On an ubuntu linux system pack() must be called before the "frame.setExtendedState(Frame.MAXIMIZED_BOTH)" code

For complete full screen applications (to change the screen resolution etc) search for the sun tutorial on fullscreen applications

make the application window maximized

    import java.awt.Frame;  
    import javax.swing.*;  
    public class MaxFrame  
    {  
      JFrame frame;  
      public MaxFrame()  
      {  
        frame = new JFrame("Test");  
        frame.setVisible(true);  
        frame.setExtendedState(Frame.MAXIMIZED_BOTH);
      }  
      public static void main(String[] args) { new MaxFrame(); }  
    }  

The frame.show method is probably not very good anymore

make the application window maximized and no window decorations

    import java.awt.Frame;  
    import javax.swing.*;  
    public class UndecoratedFrame  
    {  
      JFrame frame;  
      public UndecoratedFrame()  
      {  
        frame = new JFrame("Test");  
        frame.setUndecorated(true);
        frame.show();  
        frame.setExtendedState(Frame.MAXIMIZED_BOTH);
      }  
      public static void main(String[] args)
        { new UndecoratedFrame(); }  
    }  

make the application window as big as the screen (but not maximized)

    import javax.swing.JFrame;  
    import java.awt.Toolkit;  
    public class Test  
    {  
      JFrame frame;  
      public Test()  
      {  
        frame = new JFrame("Test");  
        Toolkit tk = Toolkit.getDefaultToolkit();  
        int xSize = ((int) tk.getScreenSize().getWidth());  
        int ySize = ((int) tk.getScreenSize().getHeight());  
        frame.setSize(xSize,ySize);  
        frame.setVisible(true);  
      }  
      public static void main(String[] args)  
        { Test app = new Test(); }  
    }  

Jinternalframe ‹↑›

Dont know much about this. A frame within a window which can be minimized etc.

Dialog Boxes ‹↑›

A dialog box or window is a window which displays some message and refuses to go away until you click one of its buttons. They are intensely annoying and should be avoided like botulism.

size methods for java.awt.Components
getMinimumSize() — smallest could be shrunk to.
getMaximumSize() — largest it makes sense to grow it to.
getPreferredSize() — ideal size.
getSize() — actual size it is now.

Alternative tools
tk - a script based dialog tool
perl-tk - the perl version of the 'tk' tool
zenity - a linux command line dialog tool

A simple use of a joptionpane dialog box

    import javax.swing.*;
    public class MessageDialog {
      public static void main(String[] args) {
        JOptionPane.showMessageDialog(null, "Hello!");
      }
    }

According to Oracle, there are some thread problems with directly executing the showMessageDialog() method. The following technique is supposed to solve these problems.

display a message dialog using a 'thread-safe' technique

    import javax.swing.*;
    public class MessageDialog {
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() 
            { JOptionPane.showMessageDialog(null, "A thread safe dialog"); }
        });
      }
    }

a dialog box with no icon and a window title

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
       JOptionPane.showMessageDialog(
          null, "Hello!", "Testing Dialogs", JOptionPane.PLAIN_MESSAGE);
      }
    }

a dialog box with a custom icon image

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        int messageType = JOptionPane.PLAIN_MESSAGE; 
        String s = "/usr/share/icons/gnome/24x24/apps/config-users.png";
        ImageIcon icon = new ImageIcon(s, "blob");
        JOptionPane.showMessageDialog(
          null, "New User", "User System", messageType, icon);
      }
    }

JOptionPane dialog boxes
JOptionPane.showMessageDialog()
JOptionPane.showInputDialog()
JOptionPane.showConfirmDialog()
JOptionPane.showOptionDialog()

Input Dialogs ‹↑›

an inputbox which returns the text

    import javax.swing.*;
    public class InputBox {
      public static void main(String[] args) {
        String r = JOptionPane.showInputDialog(
          "Enter address:", "<your address>");
        System.out.println("text entered: " + r);
      }
    }

Combobox Dialog ‹↑›

In Java a combobox is a small box with one line of text in it, and a down-arrow which allows the user to select a different value to place in the combobox. In html these are called "select boxes".

a combobox dialog with an array of values which return the selected value

    import javax.swing.*;
    public class ListBoxDialog {
      public static void main(String[] args) {
        Object[] values = { "Almond", "Oak", "Cork Oak" };
        Object result = JOptionPane.showInputDialog(
           null, "Choose a tree to plant:", "Testing the Combobox Dialog",
           JOptionPane.PLAIN_MESSAGE, null, values, values[0]);
        System.out.println("value selected: " + result);
      }
    }

a list box with an array of values with a custom icon image

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        Object[] selValues = { "abc", "def", "ghi" };
        ImageIcon icon = new ImageIcon("blob.gif", "blob");
        Object res = JOptionPane.showInputDialog(
           null, "Enter value:", "Message Title",
           JOptionPane.PLAIN_MESSAGE, icon, selValues, selValues[0]);
        System.out.println( "value selected: " + res );
      }
    }

Joptionpane ‹↑›

The JOptionPane is useful for prototyping applications since the showMessageDialog(...) method can contain any swing component It can also be used as a simple way to get some input from the user. The javadocs for JOptionPane are very informative.

One can also use an internalFrame format for the dialog.

display a JLabel in a option pane message dialog

 JOptionPane.showMessageDialog(null, new JLabel("Message"));

set the window title for a JOptionPane.showMessageDialog

     JOptionPane.showMessageDialog(frame,
        "A Message with a window title",
        "The Window Title",
        JOptionPane.PLAIN_MESSAGE);

a dialog box with a row of buttons to choose from

    import javax.swing.*;
    public class OptionDialog {
      public static void main(String[] args) {
        Object[] trees = { "oak", "yew", "elm" };
        int r = JOptionPane.showOptionDialog(
          null, 
          "Choose a letter",           // dialog message string
          "Letters",                   // dialog window title
          JOptionPane.DEFAULT_OPTION, 
          JOptionPane.PLAIN_MESSAGE,   // no default icon
          null,                        // no icon
          trees,                       // an array of objects to choose from 
          trees[0]                     // default element
          );
        System.out.format("Option selected: %s", trees[r]);
      }
    }

a dialog with a row buttons and an image

    import javax.swing.*;
    public class ImageOptionPane {
      public static void main(String[] args) {
        ImageIcon icon = new ImageIcon("blob.gif", "blob");
        Object[] vv = { "oak", "yew", "jarrah" };
        int result = JOptionPane.showOptionDialog(
          null, 
          "Which Tree?", // the message in the dialog
          "Trees",       // the dialog window title 
          JOptionPane.DEFAULT_OPTION, 
          JOptionPane.PLAIN_MESSAGE,  // no standard icon
          icon,
          vv, vv[0]);
        System.out.format("Option selected: %s", result);
      }
    }

If the image doesnt exist no exception is thrown.

Option Pane button configuration
JOptionPane.DEFAULT_OPTION - OK button
JOptionPane.YES_NO_OPTION - YES and NO buttons
JOptionPane.YES_NO_CANCEL_OPTION - YES NO, and CANCEL buttons
JOptionPane.OK_CANCEL_OPTION - OK and CANCEL buttons

allow the user to enter a password

 String password = JOptionPane.showInputDialog("Enter mail password:");

Jcolorchooser ‹↑›

The swing component JColorChooser allows the user to choose a colour using different colour models. The component can be used as a dialog box or as a component within a container (for example a JPanel)

create a swing colorchooser component

 colorChooser = new JColorChooser();

Jcolorchooser Dialog ‹↑›

show a color chooser dialog and determine the result

    import javax.swing.*;
    public class ChooseColor {
      public static void main(String[] args) {
        JColorChooser chooser = new JColorChooser();
        int result = chooser.showDialog(...); 
      }
    }

Jfilechooser ‹↑›

The JFileChooser and JColorChooser components can be used either as components added to a container, such as a panel, or else as dialog boxes, that is, contained within a new window.

Filechooser Dialog ‹↑›

display a file chooser with nimbus look and feel

    import javax.swing.*;
    public class NiceFileDialog {
      public static void main(String[] args) throws Exception {
       UIManager.setLookAndFeel(
         "javax.swing.plaf.nimbus.NimbusLookAndFeel");
        JFileChooser c = new JFileChooser();
        c.showOpenDialog(null);
        System.exit(-1);
      }
    }

show a file chooser dialog and determine the result

    import javax.swing.*;
    public class ChooseFile {
      public static void main(String[] args) {
        JFrame f = new JFrame("test file chooser");
        JFileChooser chooser = new JFileChooser();
        int result = chooser.showOpenDialog(f);
        java.io.File file = chooser.getSelectedFile();
        switch (result)
        {
          case JFileChooser.APPROVE_OPTION:
            break;
          case JFileChooser.CANCEL_OPTION:
            break;
        }
      }
    }

Using setFont to set the font for a builtin dialog box doesnt work. Another technique is to set the FileChooser font in the UIManager defaults.

display only directories in a file chooser box

    import javax.swing.*;
    public class ChooseFile {
      public static void main(String[] args) {
        JFrame f = new JFrame("test file chooser");
        JFileChooser c = new JFileChooser();
        c.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int result = c.showOpenDialog(f);
        java.io.File file = c.getSelectedFile();
        switch (result)
        {
          case JFileChooser.APPROVE_OPTION:
            break;
          case JFileChooser.CANCEL_OPTION:
            System.exit(-1);
            break;
        }
      }
    }

The example below is by a thompson and illustrate several techniques.

Accesories With Jfilechooser ‹↑›

The accessory is a panel which can be inserted in the JFileChooser dialog to add extra functionality to the file chooser (for example a list of recent files).

According to A.Thompson the FileSystemView.getSystemIcon(File) method should return a nicer icon than the standard look and feel, but on a gnome-linux computer this doesnt seem to be true. (On windows yes)

customising a JFileChooser with an 'accessory' and system icons

   import java.awt.*;
   import java.io.File;
   import javax.swing.*;
   import javax.swing.border.EmptyBorder;
   import javax.swing.event.*;
   import javax.swing.filechooser.FileSystemView;
   public class Chooser extends JPanel {
     private static final File[] RECENT_DIRECTORIES = File.listRoots();
     public Chooser() {
       this.setLayout(new BorderLayout());
       JPanel labelPanel = new JPanel(new BorderLayout());
       JLabel label = new JLabel("Recent Directories:");
       labelPanel.add(label, BorderLayout.LINE_START);
       labelPanel.setBackground(Color.LIGHT_GRAY);
       labelPanel.setBorder(new EmptyBorder(5, 10, 5, 0));
   
       JList list = new JList(RECENT_DIRECTORIES);
       list.setCellRenderer(new DefaultListCellRenderer() {
         FileSystemView fsv = FileSystemView.getFileSystemView();
         @Override
         public Component getListCellRendererComponent(
         JList list, Object value, int index, 
         boolean isSelected, boolean cellHasFocus) {
           JLabel label = (JLabel) super.getListCellRendererComponent(
             list, value, index, isSelected, cellHasFocus);
           if (value instanceof File) {
             label.setIcon(fsv.getSystemIcon((File)value));
           }
           return label;
         }
       });
   
       list.setBorder(new EmptyBorder(0, 5, 5, 0));
       list.addListSelectionListener(new ListSelectionListener() {
         public void valueChanged(ListSelectionEvent e) {
           // respond to selection here
         }
       });
   
       add(labelPanel, BorderLayout.PAGE_START);
       add(new JScrollPane(list), BorderLayout.CENTER);
     }
   
     public static void main(String[] args) throws Exception {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFileChooser fileChooser = new JFileChooser();
           Chooser c = new Chooser();
           fileChooser.setAccessory(c);
           fileChooser.showOpenDialog(null);
         }
       });
     }
   }

Jcombobox ‹↑›

The JComboBox component provides an one line text box which may or may not be editable and an attached pop-up or drop-down list of items to choose from. The combobox can be either editable or non-editable and mutable or non-mutable which means that items can be added and removed from the list.

www: http://www.exampledepot.com/egs/javax.swing/combobox_CbKeyPopup.html
Good JComboBox examples
JOptionPane dialog types
showInputDialog() - allows the user to enter some text
showInternalInputDialog() -
showConfirmDialog() -
showInternalConfirmDialog() -
showMessageDialog() - display a message or any component
showInternalMessageDialog() -
showOptionDialog() -

Strangely, the methods for a mutable JComboBox which change the box dropdown menu do not act upon the ComboBoxModel but on the box itself. This is in contrast to the JList component.

useful methods for the JComboBox
setSelectedIndex(4) - make the 5th element the selected one
setEditable(true) - make the JComboBox editable
setEditor(ComboBoxEditor) - sets the editor to use
getItemCount() - how many items are in the dropdown menu
getSelectedItem() - get the text in the box for an editable combobox
setModel(model) - sets the ComboBoxModel
getModel() - returns the ComboBoxModel
isPopupVisible() - whether the dropdown (or popup) menu can be seen
showPopup(true) - shows the dropdown menu
setMaximumRowCount(20) - make 20 items visible in the dropdown menu
getMaximumRowCount() - how many items are visible (the default is 8)

initialize a JComboBox with an array of strings

    String[] animals = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
    JComboBox box = new JComboBox(animals);

Popupmenu For Jcombobox ‹↑›

How to keep the popup menu from closing http://stackoverflow.com/questions/2778682/how-to-keep-the-popup-menu-of-a-jcombobox-open-on-populating-it

Editable Jcomboboxes ‹↑›

The default editing component for a JComboBox is a JTextField

An editable Swing JComboBox allows the user to modify the text in the field. Since JComboBox has a setEditor() method, it seems possible to use any JTextComponent as the editor for a combobox. This means we could use a styled editor such as JTextPane.

But first some simple examples of editable comboboxes.

create an editable JComboBox

   import java.awt.*;
   import javax.swing.*;
   public class ComboPanel extends JPanel {
     JComboBox box;
     public ComboPanel() {
       super(new BorderLayout());
       String[] aa = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
       this.box = new JComboBox(aa);
       this.box.setEditable(true); 
       this.box.setFont(new Font("Georgia", Font.PLAIN, 30));
       this.add(this.box, BorderLayout.CENTER);
     }
     public static void main(String[] args) throws Exception {
       JPanel p = new ComboPanel();
       JOptionPane.showMessageDialog(null, p);
     } 
   }

In the example above the box uses the default editor (what ever that may be) to allow editing of the box.

In the example below, when the user modifies the text in the JComboBox and presses enter, a new item with the modified text is added to the items of the dropdown menu for the box.

The component below can become a very useful user interface element since it provides an easy way for a user to add items to a list, or search a list.

create an editable and mutable JComboBox, add new items

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   public class ComboPanel extends JPanel implements ActionListener {
     JComboBox box;
     public ComboPanel() {
       super(new BorderLayout());
       this.box = new JComboBox(new DefaultComboBoxModel());
       this.box.setEditable(true); 
       this.box.setFont(new Font("Georgia", Font.PLAIN, 30));
       this.box.addItem("Oak"); this.box.addItem("Acacia");
       this.box.addItem("Yew");
       this.box.addActionListener(this);
       this.add(this.box, BorderLayout.CENTER);
     }
     public void actionPerformed(ActionEvent e) {
       JComboBox cb = (JComboBox) e.getSource();
       String s = (String) cb.getSelectedItem();
       if ("comboBoxEdited".equals(e.getActionCommand())) 
         this.box.addItem(s);
     }
     public static void main(String[] args) throws Exception {
        JPanel p = new ComboPanel();
        JFrame t = new JFrame();
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setLocationRelativeTo(null);
        t.setVisible(true);
     } 
   }

Cellrenderers And Customising Combobox Item Appearance ‹↑›

The JComboBox uses, by default, the same cell renderer as the JList component. This is the DefaultListCellRenderer component, which is really just a type of JLabel with some performance modifications.

To customise the appearance of items in the 'pop-up' menu for a JComboBox there are 3 choices (in increasing order of flexibility): set a property on the default renderer with for example

 ((JLabel)combobox.getCellRenderer()).setBackground(Color.orange);

Or, subclass (extend) the DefaultListCellRenderer and the new subclass to the JComboBox with the setCellRenderer() method. Or finally, implement the ListCellRenderer interface. The 2nd method is probably the best, since it offers great flexibility for the appearance of the combobox pop-up menu items, without much complexity for the programmer.

Another technique maybe to override the toString() method for the class which is contained in the pop-up list.

displays fonts in a combobox and uses the font for the item

   import java.awt.*;
   import javax.swing.*;
   public class ShowFonts {
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           GraphicsEnvironment ge = GraphicsEnvironment.
                                    getLocalGraphicsEnvironment();
           String[] fonts = ge.getAvailableFontFamilyNames();
           JComboBox fontChooser = new JComboBox(fonts);
           fontChooser.setRenderer(new FontCellRenderer());
           JOptionPane.showMessageDialog(null, fontChooser);
         }
       });
     }
   }
   class FontCellRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object value, int index,
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel)super.getListCellRendererComponent(
         list,value,index,isSelected,cellHasFocus);
       Font font = new Font((String)value, Font.PLAIN, 20);
       label.setFont(font);
       return label;
     }
   }

make alternate rows in the pop-up menu different colours

   import java.awt.*;
   import java.io.File;
   import javax.swing.*;
   public class RowColorBox {
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           JComboBox box = new JComboBox(new File(".").list());
           box.setRenderer(new RowColorRenderer());
           JOptionPane.showMessageDialog(null, box);
         }
       });
     }
   }
   class RowColorRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object value, int index,
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel)super.getListCellRendererComponent(
         list,value,index,isSelected,cellHasFocus);
       if ((index % 2)==0) label.setBackground(Color.orange);
       return label;
     }
   }

another cellrenderer eg from camickr, not compiling (setdragenabled?)

   import java.awt.*;
   import java.awt.event.*;
   import java.util.*;
   import javax.swing.*;
   import javax.swing.plaf.basic.*;
   
   public class ComboBoxItem extends JFrame implements ActionListener {
     public ComboBoxItem() {
       Vector model = new Vector();
       model.addElement( new Item(1, "car" ) );
       model.addElement( new Item(2, "plane" ) );
       model.addElement( new Item(3, "train" ) );
       model.addElement( new Item(4, "boat" ) );
   
       JComboBox comboBox;
   
       //  Easiest approach is to just override toString() method
       //  of the Item class
       comboBox = new JComboBox( model );
       //comboBox.setDragEnabled(true);
       comboBox.addActionListener( this );
       getContentPane().add(comboBox, BorderLayout.NORTH );
   
       //  Most flexible approach is to create a custom renderer
       //  to display the Item data
       comboBox = new JComboBox( model );
       //comboBox.setDragEnabled(true);
       comboBox.setRenderer( new ItemRenderer() );
       comboBox.addActionListener( this );
       getContentPane().add(comboBox, BorderLayout.SOUTH );
     }
   
     public void actionPerformed(ActionEvent e) {
       JComboBox comboBox = (JComboBox)e.getSource();
       Item item = (Item)comboBox.getSelectedItem();
       System.out.println( item.getId() + " : " + item.getDescription() );
     }
   
     class ItemRenderer extends BasicComboBoxRenderer {
       public Component getListCellRendererComponent(
         JList list, Object value, int index,
         boolean isSelected, boolean cellHasFocus) {
         super.getListCellRendererComponent(list, value, index,
                                            isSelected, cellHasFocus);
         if (value != null) {
           Item item = (Item)value;
           setText( item.getDescription().toUpperCase() );
         }
         if (index == -1) {
           Item item = (Item)value;
           setText( "" + item.getId() );
         }
         return this;
       }
     }
   
     class Item {
       private int id;
       private String description;
       public Item(int id, String description) {
         this.id = id;
         this.description = description;
       }
   
       public int getId() {
         return id;
       }
       public String getDescription() { return description; }
       public String toString() { return description; }
     }
   
     public static void main(String[] args) {
       JFrame frame = new ComboBoxItem();
       frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
       frame.pack();
       frame.setVisible( true );
     }
   }

Comboboxmodels ‹↑›

In order to supply data, or items to the JComboBox we use the ComboBoxModel interface or one of its implementations. The simplest model to use is the DefaultComboBoxModel which is an implementation of MutableComboBoxModel (an abstract class) and therefore allows the adding and removal of items in the drop down menu.

create a box and pass some values to its (mutable) ComboBoxModel

 JComboBox box = new JComboBox(new DefaultComboBoxModel(new String[]{"one","two"}));

pass an array of initial values to a combobox's (mutable) ComboBoxModel

    String[] ss = {"cloud", "star", "sky"};
    JComboBox box = new JComboBox(new DefaultComboBoxModel(ss));

This is a simple way to initialize the dropdown (or pop-up) menu for a mutable JComboBox. After the box is created items can be added with box.addItem(object)

The Vector use here below seems unnecessarily outdated.

create a combobox model which maintains its items sorted alphabetically

   import java.util.Vector;
   import javax.swing.DefaultComboBoxModel;
   public class SortedComboBoxModel extends DefaultComboBoxModel {
     public SortedComboBoxModel(Object[] element) {
       for (int i =0, l =element.length; i <l; i++) {
         addElement(element[i]);
       }
     }
     public SortedComboBoxModel(Vector element) {
       for (int i =0, l =element.size(); i <l; i++) {
         addElement(element.elementAt(i));
       }
     }
     public void addElement(Object element) {
       int i, l;
       for (i =0, l =getSize(); i <l; i++) {
         if (((String)element).compareTo(getElementAt(i)) <0) break;
       }
       insertElementAt(element, i);
     }
   }

Jcombobox Events And Listeners ‹↑›

Itemlisteners ‹↑›

implement ItemListener interface

   public void itemStateChanged(ItemEvent e) {
     String componentName = (String)e.getItem();
     selectedItem = componentName;
   }

when we change the elements the box we have to remove itemlistener

   comboBox.removeItemListener( this );
   comboBox.setModel( new DefaultComboBoxModel( comboBoxItems ) );
   comboBox.setSelectedIndex(-1);
   comboBox.addItemListener( this );

Documentlistener For A Jcombobox ‹↑›

Probably the correct way to listen for changes in the text field of an editable combobox is to use a DocumentListener.

When a JComboBox is editable, the editable text field, like all JTextComponents, has an associated Document (which is the model which manages the text in the component). That means that you can create a DocumentListener to listen to changes made by typing in the editable JComboBox.

install a DocumentListener for a JComboBox

   final JTextComponent tc = 
     (JTextComponent) combo.getEditor().getEditorComponent();
   tc.getDocument().addDocumentListener(this);

install an anonymous DocumentListener

   final JTextComponent tc = (JTextComponent) comboA.getEditor().getEditorComponent();
   tc.getDocument().addDocumentListener(new DocumentListener() {
     ...
   });

The following code needs alot of work to stop IllegalStateExceptions. I think I am violating the principle of not modifying a document from within the Event handler. Also this should extend the JComboBox class to allow it to be easily used. Also there is the problem of how to keep the popup menu open (not reopen it, because that causes an unpleasant flashing effect). All this might be easier with a KeyListener because the DocumentListener has a tendency to go into an infinite loop.

Despite these problems, this component has the potential to be a useful searcher and selector.

filter a combobox list of class methods based on keystrokes

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.swing.text.*;
   import javax.swing.event.*;
   import java.lang.reflect.*;
   public class ComboPanel extends JPanel implements ActionListener, DocumentListener {
     JComboBox box;
     public ComboPanel() {
       super(new BorderLayout());
       Class c = "s".getClass();
       Method mm[] = c.getMethods();
       this.box = new JComboBox(new DefaultComboBoxModel(mm));
       this.box.setEditable(true);
       this.box.setFont(new Font("Georgia", Font.PLAIN, 30));
       this.box.addItem("Oak");
       this.box.addItem("Acacia");
       this.box.addItem("Yew");
       this.box.addActionListener(this);
       final JTextComponent tc = (JTextComponent) this.box.getEditor().getEditorComponent();
       tc.getDocument().addDocumentListener(this);
       this.add(this.box, BorderLayout.CENTER);
     }
     public void insertUpdate(DocumentEvent e) {
       this.filter(e);
     }
     public void removeUpdate(DocumentEvent e) {
       this.filter(e);
     }
     public void changedUpdate(DocumentEvent e) {
       //JTextFields dont fire these events
     }
   
     public void filter(DocumentEvent e) {
       // this.box.showPopup();
       String s =
         String.format(
           "Action type: %s, Doc Offset: %d, Change Length: %d \n",
           e.getType().toString(), e.getOffset(), e.getLength());
       System.out.println(s);
       // a trick
       SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
           ComboPanel.this.box.removeItemAt(ComboPanel.this.box.getSelectedIndex());
         }
       });
   
       /*
       for (int i = 0; i < this.box.getItemCount(); i++)
       {
         if (this.box.getItemAt(i).toString().toLowerCase().indexOf(s) > 0)
           System.out.println(this.box.getItemAt(i));
       }
       */
     }
     public void actionPerformed(ActionEvent e) {
       JComboBox cb = (JComboBox) e.getSource();
       String s = (String) cb.getSelectedItem().toString();
       //if ("comboBoxEdited".equals(e.getActionCommand()))
       //this.box.addItem(s);
     }
     public static void main(String[] args) throws Exception {
       JPanel p = new ComboPanel();
       JFrame t = new JFrame();
       t.getContentPane().add(p);
       t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       t.pack();
       t.setLocationRelativeTo(null);
       t.setVisible(true);
     }
   }

Keylisteners For A Jcombobox ‹↑›

The sun/oracle swing tutorial for JComboBoxes explicitly recommends not to use KeyListeners on a combobox, since it is a compound component. Apparently a keylistener would be dependant on the look and feel of the interface. However this makes implementing a search box (where the dropdown list is progressively filtered based on the contents of the editable text box) difficult. The alternative is to use a DocumentListener but that fires events when the user selects from the list.

We will ignore the advice, for the time being.

listen to any printable keystroke and show the combobox popupmenu

   JComboBox cb = new JComboBox(items);
   cb.addKeyListener(new MyKeyListener());
   class MyKeyListener extends KeyAdapter {
     public void keyPressed(KeyEvent evt) {
       JComboBox cb = (JComboBox)evt.getSource();
       char ch = evt.getKeyChar();
       // If not a printable character, do nothing
       if (ch != KeyEvent.CHAR_UNDEFINED) {
         cb.showPopup();
       }
     }
   }

handle how keystrokes select an item in a JComboBox

    cb.setKeySelectionManager(new MyKeySelectionManager());
    class MyKeySelectionManager implements JComboBox.KeySelectionManager {
    ...

Actionlistener For A Jcombobox ‹↑›

The ActionEvent for a JComboBox is fired when a user select a new item from the combobox drop down menu. It is also fired when the JComboBox is editable and the user presses the Enter key.

The code snippet below is important because a JComboBox fires an ActionEvent when a user presses enter in an editable box, and also when the user selects a new item. And maybe also when the user moves the selection down the dropdown menu.

distinguish between a text edit and new selection in an ActionListener

   if ("comboBoxEdited".equals(evt.getActionCommand())) {
     // User has typed in a string; only possible with an editable combobox
   } else if ("comboBoxChanged".equals(evt.getActionCommand())) {
     // User has selected an item; it may be the same item
   }

write information about JComboBox ActionEvents to a JTextArea

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   public class ComboPanel extends JPanel implements ActionListener {
     JComboBox box;
     JTextArea area;
     public ComboPanel() {
       super(new BorderLayout());
       String[] aa = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
       this.box = new JComboBox(aa);
       this.box.addActionListener(this);
       this.area = new JTextArea(60, 10);
       this.area.setLineWrap(true);
       this.add(this.area, BorderLayout.CENTER);
       this.add(this.box, BorderLayout.NORTH);
     }
     public void actionPerformed(ActionEvent e) {
       JComboBox cb = (JComboBox) e.getSource();
       String s = (String) cb.getSelectedItem();
       this.area.append(e.toString());
     }
     public static void main(String[] args) throws Exception {
       JPanel p = new ComboPanel(); 
       p.setPreferredSize(new Dimension(300, 600));
       JOptionPane.showMessageDialog(null, p);
     } 
   }

Itemlisteners For Jcombobox ‹↑›

An ItemEvent is fired by a JComboBox when an item in the drop down menu is selected or unselected (eg: highlighted blue) This is subtly different from the ActionEvent selection event. An ItemListener can be used to react to changes in the item selection state.

Jlists ‹↑›

The Swing JList component displays a vertical list of items (objects). Like many Swing components the data is supplied by a model, in this case a ListModel.

To supply content to the JList box the programmer has several choices: implement the ListModel interface, extend the AbstractListModel, or use the DefaultListModel. JLists can also be initialized with an array but in that case it is not possible to add or remove elements in the JList after it has been created.

methods for a mutable JComboBox (uses MutableComboBoxModel)
addItem("oak") - adds "oak" at the end of the box menu
insertItem("acacia" 1) - adds 'acacia' just after the first item
removeAllItems() - removes all items from the JComboBox menu

set some parameters for a listbox

    list = new JList(data); //data has type Object[]
    list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
    list.setVisibleRowCount(-1);

set the selectmode, but is all this necessary?

 list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

get the value of an element in a list at in 4

 s = (String)list.getModel().getElementAt(4);

create an immutable JList supplying the elements from an array

    import javax.swing.*;
    import java.io.*;
    public class ListBox {
      public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JFrame t = new JFrame();
        String[] ss = {"Eucalypt", "Oak", "Apple", "Walnut"};
        JList trees = new JList(ss);
        JPanel pl = new JPanel();
        pl.add(new JScrollPane(trees));
        t.getContentPane().add(pl);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setLocationRelativeTo(null);
        t.setVisible(true);
      }
    }

a listbox with a different font and colour

    import javax.swing.*;
    import java.awt.Font;
    public class Box {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        String[] ss = {"Eucalypt", "Cork Oak", "Apple", "Walnut"};
        JList trees = new JList(ss);
        trees.setFont(new Font("Georgia", Font.PLAIN, 30));
        JPanel p = new JPanel(); p.add(trees);
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.setLocationRelativeTo(null);
        t.pack(); t.setVisible(true);
      }
    }

If we explicitly use the DefaultListModel as the 'data model' for the swing listbox, then we can add and remove elements from the listbox after it has been created.

create a list box to which elements can be added or removed

    import javax.swing.*;
    import java.awt.Font;
    public class Box {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        DefaultListModel listModel = new DefaultListModel();
        listModel.addElement("Tibouchina");
        listModel.addElement("Siete Cueros");
        listModel.addElement("Hevea Brasiliensis");
        JList trees = new JList(listModel);
        trees.setFont(new Font("Georgia", Font.PLAIN, 30));
        JPanel p = new JPanel(); p.add(trees);
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.setLocationRelativeTo(null);
        t.pack(); t.setVisible(true);
      }
    }

displays a file list in the center of the screen

    import javax.swing.*;
    import java.io.*;
    import java.awt.Font;
    public class FileList {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        JList fileList = new JList((new File(".")).listFiles());
        fileList.setFont(new Font("Georgia", Font.PLAIN, 50));
        JPanel pl = new JPanel();
        pl.add(new JScrollPane(fileList));
        t.getContentPane().add(pl);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setLocationRelativeTo(null);
        t.setVisible(true);
      }
    }

Selections For Jlists ‹↑›

A JList can allow the user to select items from the list in various ways- such as only allowing one item to be selected, several contiguous items selected or non-contiguous multiple items selected.

set the selection mode for a JList component.

 list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);

useful methods for the JList box
getSelectedIndex - get the index number of the selected item
getSelectedValue - get the value (usually text) associated with selected item
setSelectionBackground(Color.RED) - set the selection backgroud color

Listmodels ‹↑›

The task of the ListModel is to supply data, or objects to the JList component. The interface contains a set of methods which the JList can use to interrogate the ListModel for available data.

The simplest way to use a model with a JList box is to use the ListModel subclass DefaultListModel. The most flexible way is to implement the ListModel interface.

jlist box with lots of numbers using an AbstractListModel

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        ListModel bigData = new AbstractListModel() {
           public int getSize() { return Short.MAX_VALUE; }
           public Object getElementAt(int index) { return "Index " +
           index; }
         };
        JList dataList = new JList(bigData);
        // the following makes rendering quicker
        dataList.setPrototypeCellValue("Index 1234567890");
        JFrame f = new JFrame();
        f.getContentPane().add(new JScrollPane(dataList));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);  
        f.pack();
        f.setVisible(true);
      }
    }

a list box with an AbstractListModel and unicode characters

    import javax.swing.*;
    public class UnicodeBox {
      public static void main(String[] args) {
        ListModel bigData = new AbstractListModel() {
           public int getSize() { return Short.MAX_VALUE; }
           public Object getElementAt(int index)
            { return "unicode " + index + 1000 + ":" + (char)(index + 1000); }
         };
        JList unicodeList = new JList(bigData);
        unicodeList.setPrototypeCellValue("Index 1234567890");
        JPanel p = new JPanel(); 
        p.add(new JScrollPane(unicodeList));
        JFrame f = new JFrame();
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null); 
        f.pack();
        f.setVisible(true);
      }
    }

Defaultlistcellrenderer ‹↑›

The javax.swing.JList component by default uses a type of JLabel to render each item in the list- this is called a DefaultListCellRenderer. It is possible to customise the elements in a JList by setting properties of the CellRenderer. The default cell renderer is an opaque label, whereas JLabels by default are not.

The JComboBox also uses the DefaultListCellRenderer class to display each item of its 'pop-up' list, so all the techniques learnt here are applicable also to that component.

right align text in JList elements

     DefaultListCellRenderer r = 
       (DefaultListCellRenderer)list.getCellRenderer();
     r.setHorizontalAlignment(SwingConstants.RIGHT);

another way to set a property of each element of a list

    JLabel l = (JLabel) list.getCellRenderer();
    l.setHorizontalAlignment(SwingConstants.RIGHT);

a more succint method to do the same

 ((JLabel)list.getCellRenderer()).setHorizontalAlignment(JLabel.RIGHT);

right align all elements in a jlist using the default cell renderer

    import javax.swing.*;
    import java.io.*;
    import java.awt.Font;
    public class ListRenderer  {
      public static void main(String[] args) {
        JList list = new JList((new File(".")).list());
        list.setFont(new Font("Georgia", Font.PLAIN, 20));
        DefaultListCellRenderer r = 
          (DefaultListCellRenderer) list.getCellRenderer();
        r.setHorizontalAlignment(JLabel.RIGHT);
        JOptionPane.showMessageDialog(null, list);
      }
    }

It seems that it is necessary to subclass the DefaultListCellRenderer in order to put a Border or an Icon in each JList item cell. This is because these properties get 'cleared' by the default renderer and so we *cant* just use:

 ((JLabel)list.getCellRenderer().setIcon(...)

Extending The Defaultlistcellrenderer ‹↑›

Possibly the simplest way to customise the appearance of JList cells (the component which contains each item), is to extend the DefaultListCellRenderer (which is a type of JLabel). It may only be necessary to override the getListCellRendererComponent() method, which returns the component which contains each item of the list.

set a border for each JList item

   import javax.swing.*;
   import java.io.File;
   import java.awt.Component;
   public class BorderList {
     public static void main(String[] args) {
       JList list = new JList(new File(".").list());
       list.setCellRenderer(new BorderRenderer());
       JOptionPane.showMessageDialog(null, list);
     }
   }
   class BorderRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object o, int index, 
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel) super.getListCellRendererComponent(
         list, o, index, isSelected, cellHasFocus); 
       label.setBorder(BorderFactory.createEtchedBorder());
       return label;
     }
   }

The code below may have the problem that the 'index' value is apparently not alway valid, so use instead:

 int selectedIndex = ((Integer)object).intValue();

make the rows of the JList alternate colours

   import javax.swing.*;
   import java.io.File;
   import java.awt.*;
   public class RowColorList {
     public static void main(String[] args) {
       JList list = new JList(new File(".").list());
       list.setCellRenderer(new ColorRenderer());
       JFrame f = new JFrame("A JList with alternate coloured rows");
       f.add(new JScrollPane(list));
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
     }
   }
   class ColorRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object o, int index, 
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel) super.getListCellRendererComponent(
         list, o, index, isSelected, cellHasFocus); 
       if ((index % 2) == 0) label.setBackground(Color.lightGray);
       return label;
     }
   }

The icons which are displayed in the example below are not very nice, at least on my gnome-linux system, they are not the same icons used by the nautilus file browser for example.

The example below is succint and powerful. By subclassing the DefaultListCellRenderer not much code needs to be written in order to achieve interesting things.

a technique to display the system file/folder icon for each item

   import javax.swing.*;
   import javax.swing.filechooser.FileSystemView;
   import java.io.File;
   import java.awt.*;
   public class FileIconList {
     public static void main(String[] args) {
       JList list = new JList(new File(".").listFiles());
       list.setFont(new Font("Georgia", Font.PLAIN, 20));
       list.setCellRenderer(new DefaultListCellRenderer() {
         FileSystemView fsv = FileSystemView.getFileSystemView();
         @Override
         public Component getListCellRendererComponent(
         JList list, Object value, int index,
         boolean isSelected, boolean cellHasFocus) {
           JLabel label = (JLabel) super.getListCellRendererComponent(
               list, value, index, isSelected, cellHasFocus);
           if (value instanceof File) {
             label.setIcon(fsv.getSystemIcon((File)value));
             label.setText(((File)value).getName());
           }
           return label;
         }
       });
       JOptionPane.showMessageDialog(null, list);
     }
   }

According to "howard": The DefaultListCellRenderer clears the icon whenever its getListCellRendererComponent method is called. So the same probably applies to the border property

The method below (suggested by howard@stackoverflow) creates an anonymous subclass of the default renderer for JList cells. The technique below could also be used to set the border for all JList items.

one method to set the icon for each item in a JList

   list.setCellRenderer(new DefaultListCellRenderer() {
     @Override
     public Component getListCellRendererComponent(
       JList list, Object value, int index, 
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel) super.getListCellRendererComponent(
         list, value, index, isSelected, cellHasFocus);
       label.setIcon(icon);
       return label;
     }
   });

Listcellrenderer Interface ‹↑›

It is possible to customize the way that each list element in a swing list box is rendered by implementing the ListCellRenderer interface. This involves writing a body for the getListCellRendererComponent method

Another method is simply to customize the DefaultListCellRenderer which is a type of opaque JLabel.

Extending a JLabel to implement a ListCellRenderer probably will have performance problems.

An example of a ListCellRenderer implementation

   import javax.swing.*;
   class ColourCell extends JLabel implements ListCellRenderer {
     public ColourCell() { setOpaque(true); }
     public Component getListCellRendererComponent(
       JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
     {
       this.setText(value.toString());
       // Is the listbox item currently selected?
       if (isSelected) {
         this.setBackground(Color.RED);
         this.setForeground(Color.WHITE);
       } else {
         this.setBackground(Color.WHITE);
         this.setForeground(Color.GRAY);
       }
       return this;
     }
   }

There maybe performance problems with the technique used below because of the JLabel. For this reason it may be preferable to extend the DefaultListCellRenderer class, since that class uses a modified JLabel with the performance problems fixed.

create a cellrenderer to make the selection white on red and the font big

   import javax.swing.*;
   import java.awt.*;
   import java.io.File;
   public class ColorSelectionList {
     public static void main(String[] args) {
       JFrame t = new JFrame();
       JList fileList = new JList((new File(".")).listFiles());
       ColourCell renderer = new ColourCell();
       //renderer.setPreferredSize(new Dimension(200, 130));
       fileList.setCellRenderer(renderer);
       JPanel pl = new JPanel();
       pl.add(new JScrollPane(fileList));
       t.add(pl); t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       t.pack(); t.setLocationRelativeTo(null);
       t.setVisible(true);
     }
   }
   class ColourCell extends JLabel implements ListCellRenderer {
     public ColourCell() {
       this.setOpaque(true);
       this.setFont(new Font("Georgia", Font.PLAIN, 30));
     }
   
     public Component getListCellRendererComponent(
       JList list, Object o, int index, boolean isSelected, boolean cellHasFocus)
     {
       this.setText(value.toString());
       // Is the listbox item currently selected?
       if (isSelected) {
         this.setBackground(Color.RED);
         this.setForeground(Color.WHITE);
       } else {
         this.setBackground(Color.WHITE);
         this.setForeground(Color.GRAY);
       }
       return this;
     }
   }

According to the Sun java tutorial site the índex parameter to the getListCellRendererComponent is not always valid. Which seems odd. So instead we can use

 int selectedIndex = ((Integer)value).intValue(); ???

See the DefaultListCellRenderer section above for an alternative (and probably better) way to do this.

create a cellrenderer to colour alternate rows light blue in the jlistbox

   import javax.swing.*;
   import java.awt.*;
   import java.io.File;
   public class AlternateRowList {
     public static void main(String[] args) {
       JFrame t = new JFrame();
       JList fileList = new JList((new File("..")).listFiles());
       ColourCell renderer = new ColourCell();
       fileList.setCellRenderer(renderer);
       JPanel pl = new JPanel();
       pl.add(new JScrollPane(fileList));
       t.getContentPane().add(pl);
       t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       t.setLocationRelativeTo(null);
       t.pack();
       t.setVisible(true);
     }
   }
   
   class ColourCell extends JLabel implements ListCellRenderer {
     public ColourCell() {
       this.setOpaque(true);
       this.setFont(new Font("Georgia", Font.PLAIN, 20));
     }
   
     public Component getListCellRendererComponent(
       JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
     {
       this.setText(value.toString());
       if (isSelected) /* if the listbox element is currently selected */
       {
         this.setBackground(Color.blue);
         this.setForeground(Color.white);
       } else {
         this.setForeground(Color.darkGray);
         if ((index % 2) == 0)
           this.setBackground(Color.white);
         else
           this.setBackground(new Color(Integer.decode("#ffffdd")));
           //this.setBackground(new Color(0, 220, 250));
       }
       return this;
     }
   }

If the opacity of the cell renderer is false then the renderer doesnt seem to do its job properly

 this.setOpaque(true);

Jlist Events And Listeners ‹↑›

In order to fire events when an item is selected in a JListBox you need to implement an ListSelectionListener by defining one method valueChanged(ListSelectionEvent e).

The getValueIsAdjusting() method returns true if the user is still manipulating the selection for example, is dragging the selection to include more elements.

selection modes of the ListSelectionModel
SINGLE_INTERVAL_SELECTION - multiple contiguous items

An example of a valueChanged method for responding to listbox selections

     public void valueChanged(ListSelectionEvent e) {
         if (e.getValueIsAdjusting() == false) {
             if (list.getSelectedIndex() == -1) { /* No selection */ }
             else { /* do something */ }
         }
     }

create a listbox which reacts to changes of the selected item(s)

   import javax.swing.*;
   import javax.swing.event.*;
   import java.awt.*;
   public class BoxEvent extends JFrame implements ListSelectionListener {
     String[] ss = {"Yew", "Oak", "Elder", "Myoporum"};
     JList list;
     public BoxEvent() {
        list = new JList(ss); 
        list.addListSelectionListener(this);
        list.setFont(new Font("Georgia", Font.PLAIN, 40));
        JPanel p = new JPanel(); p.add(list);
        this.getContentPane().add(p);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        this.pack(); this.setVisible(true);
     }
     public void valueChanged(ListSelectionEvent e) {
        if (e.getValueIsAdjusting() == false) {
             if (list.getSelectedIndex() == -1) { /* No selection */ }
             else { 
               System.out.println(list.getSelectedIndex()); 
             }
         }
     }
     public static void main(String[] args)
       { BoxEvent b = new BoxEvent(); }
   }

do something when a jlist item is double clicked

    final JList list = new JList(dataModel);
    MouseListener mouseListener = new MouseAdapter() {
      public void mouseClicked(MouseEvent e)
      {
        if (e.getClickCount() == 2) {
          int index = list.locationToIndex(e.getPoint());
          System.out.println("Double clicked on Item " + index);
        }
      }
    };
    list.addMouseListener(mouseListener);

Mouselisteners With The Jlist Component ‹↑›

do something when a jlist item is double clicked

  final JList list = new JList(dataModel);
  MouseListener mouseListener = new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
          if (e.getClickCount() == 2) {
              int index = list.locationToIndex(e.getPoint());
              System.out.println("Double clicked on Item " + index);
           }
      }
  };
  list.addMouseListener(mouseListener);

Gotchas For Jlist ‹↑›

If you add a very large number of elements to a swing JList component (or rather to its ListModel) without placing the JList in a JScrollPane, Exceptions will be generated, and on Linux at least the window will flash eternally.

Jpanels ‹↑›

Panels are important for grouping and laying out graphical components on a window. Panels can be created with a 'layout' which determines how the components (such as text-boxes, labels list boxes etc will be placed within the panel when the the 'add()' method of the panel is used.

Panels, unless they have a border, are usually invisible to the user.

create a panel with a 2 by 2 gridlayout

 JPanel p = new JPanel(new GridLayout(2, 2));

create a panel with 2 columns and unlimited rows

 JPanel p = new JPanel(new GridLayout(0, 2);

add a component to a visible jpanel

 panel.add(component); panel.revalidate();

a simple frame window with a panel and 3 labels

    import javax.swing.*;
    import java.awt.*;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("a simple window");
        JPanel p = new JPanel(new GridLayout(0, 1));
        p.add(new JLabel("1st label"));
        p.add(new JLabel("2nd label"));
        p.add(new JLabel("3rd label"));
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

create a 2 column grid layout, 5px vertical separation, 1px horizontal

  java.awt.GridLayout g = new GridLayout(0, 2, 5, 1));

a panel containing a user-name and password entry fields

    import javax.swing.*;
    import java.awt.*;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("a simple window");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        p.add(new JLabel("user"));
        p.add(new JTextField());
        p.add(new JLabel("password"));
        p.add(new JPasswordField());
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

The problem with the window above, it that it doesnt resize is a pleasant fashion, the text boxes become very large and the space between the labels increases.

remove a JLabel from a JPanel or JFrame

   Container parent = label.getParent();
   parent.remove(label);
   parent.validate();
   parent.repaint();

Borders ‹↑›

Just about any swing JComponent can have a border or to be more precise, a javax.swing.border.Border. Borders in general make things look nicer and are a good way of grouping sets of components.

www: http://leepoint.net/notes-java/GUI-appearance/borders/15bordersex.html
some good notes about creating borders
relevant listeners for a JList

In the code below the LineBorder with rounded corners doesnt really produce noticeably rounded corners.

show what various borders look like

    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.plaf.*;
    import java.awt.*;
    public class BorderPanel extends JPanel {
      public BorderPanel() {
        super(new GridLayout(0, 1, 10, 10));
        this.setBorder(new EmptyBorder(10,10,10,10));
        UIManager.put(
          "Label.font", new FontUIResource("Georgia", Font.PLAIN, 18));
        JLabel label;
        label = new JLabel("BevelBorder raised");
        label.setBorder(new BevelBorder(BevelBorder.RAISED)); 
        this.add(label);
        label = new JLabel("BevelBorder lowered");
        label.setBorder(new BevelBorder(BevelBorder.LOWERED)); 
        this.add(label);
        label = new JLabel("EtchedBorder");
        label.setBorder(new EtchedBorder()); 
        this.add(label);
        label = new JLabel("EtchedBorder raised");
        label.setBorder(new EtchedBorder(EtchedBorder.RAISED)); 
        this.add(label);
        label = new JLabel("MatteBorder with insets (10,5,5,5)");
        label.setBorder(
          new MatteBorder(new Insets(10,5,5,5), Color.blue)); 
        this.add(label);
        label = new JLabel("4px blue LineBorder, rounded corners");
        label.setBorder(new LineBorder(Color.blue, 4, true)); 
        this.add(label);
        label = new JLabel("1px black LineBorder, rounded corners");
        label.setBorder(new LineBorder(Color.black, 1, true)); 
        this.add(label);
      } 

      public static void main(String[] args) {
        BorderPanel p = new BorderPanel(); 
        JOptionPane.showMessageDialog(null, new JScrollPane(p)); 
      }
   }

a username and password panel with a titled, etched border

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    public class EtchedBorderTest {
      public static void main(String[] args) {
        JFrame f = new JFrame("an EtchedBorder example");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        Border eb = BorderFactory.createEtchedBorder();
        Border tb = BorderFactory.createTitledBorder(eb, "Login");
        p.setBorder(tb);
        p.add(new JLabel("User")); p.add(new JTextField());
        p.add(new JLabel("Password")); p.add(new JPasswordField());
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

The problem with the panel above is that it doesnt resize well. The text boxes become very large.

JPanel with titled etched border with some extra space inside it

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    public class SpacedBorder {
      public static void main(String[] args) {
        JFrame f = new JFrame("An Etched, Titled and Empty border");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        Border etb = BorderFactory.createEtchedBorder();
        Border tb = BorderFactory.createTitledBorder(etb, "Login");
        Border eb  = BorderFactory.createEmptyBorder(5,5,5,5);
        Border cb = BorderFactory.createCompoundBorder(tb, eb);
        p.setBorder(cb);
        p.add(new JLabel("User")); p.add(new JTextField());
        p.add(new JLabel("Password")); p.add(new JPasswordField());
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

The technique about adds some extra space (5 pixels) inside the titled etched border, but not outside of it. To place the extra space outside of the titled border, reverse the order of the arguments to createCompoundBorder()

 Border cb = BorderFactory.createCompoundBorder(eb, tb);

create an etched border, with a title and some extra space

     import javax.swing.border.*;
     . . .
     JPanel p = new JPanel();
     Border etchedBdr = BorderFactory.createEtchedBorder();
     Border titledBdr = 
       BorderFactory.createTitledBorder(etchedBdr, "Process");
     Border emptyBdr  = BorderFactory.createEmptyBorder(10,10,10,10);
     Border compoundBdr = 
       BorderFactory.createCompoundBorder(titledBdr, emptyBdr);
     processPanel.setBorder(p);

border types
BevelBorder - the raised style looks like an old-fashioned button
EtchedBorder - looks like a groove

Etchedborder ‹↑›

an etched border example

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    public class EtchedBorder {
      public static void main(String[] args) {
        JFrame f = new JFrame("An Etched border");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        for (String s: new java.io.File(".").list()) {
          JLabel l = new JLabel(s);
          l.setBorder(BorderFactory.createEtchedBorder());
          p.add(l);
        }
        f.add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

Emptyborder ‹↑›

The javax.swing.border.EmptyBorder is useful for making everything look nicer by placing space around a component. In a gnome linux java1.6 system, a JScrollBar occupies some of the empty space in the EmptyBorder.

put 20 pixels of space around the outside of a JPanel

 JPanel p = new JPanel(); p.setBorder(new EmptyBorder(20,20,20,20));

Custom Borders ‹↑›

Java swing provides a great deal of flexibility with how borders are painted around components.

www: http://www.javarichclient.com/how-to-create-a-custom-swing-border/
different kinds of borders
BorderFactory.createLineBorder(Color.black);
BorderFactory.createEtchedBorder();
BorderFactory.createRaisedBevelBorder();
BorderFactory.createLoweredBevelBorder();

The Insets push the contents of the JComponent away from the border. For example, increasing the size of the Insets places more space around text in a JLabel with a Border. The Insets do not create any extra space outside of the Border.

Setting the label to opaque and a background colour for the JLabel is useful for detecting problems when painting Borders.

the isBorderOpaque() method may be important

how to extend AbstractBorder to create a custom Border

   public class NewBorder extends AbstractBorder {
     private int thickness;
     public NewBorder(int thick) {
       this.thickness = thick;
     }
     public void paintBorder(
       Component c, Graphics g, int x, int y, int width, int height) {
       // draw the border
     }
   
     public Insets getBorderInsets(Component c) {
       return new Insets(thickness, thickness, thickness, thickness);
     }
   
     public Insets getBorderInsets(Component c, Insets insets) {
       insets.left = insets.top = insets.right = insets.bottom = thickness;
       return insets;
     }
   }

The javadoc comments for the parameters of the paintBorder() method are confusing. The (x,y,width,height) parameters basically mark the bounding rectangle of the component (JLabel, JPanel etc) on which the border is being painted. If a thick stroke is used then this rectangle has to be shrunk so that all of the stroke is painted on the component, since half of a BasicStroke gets painted outside of the shape which it paints.

the parameters for the paintBorder method

     public void paintBorder(
       Component c, // the component on which to paint the border
       Graphics g,  // cast this to a Graphics2D for nice drawing 
       int x,       // (x,y) the top left corner of the component (label..) 
       int y,
       int width,   // the width of the component which will have the border
       int height)  // the height of the component with the border
     )

In the code below, if a compound border is not used with the custom border the left and bottom dashed border draws at half the thickness. why?

create a dashed border

   import java.awt.*;
   import javax.swing.*;
   import javax.swing.border.AbstractBorder;
   public class DashBorder extends AbstractBorder {
     protected int strokeWidth;
     protected int margin;
     protected Color lineColor;
   
     public DashBorder(Color color, int thickness)  {
       this.lineColor = color;
       this.strokeWidth = thickness;
       this.margin = thickness + 5;
     }
   
     public void paintBorder(
       Component c, Graphics g, int x, int y, int width, int height) {
       Graphics2D g2d = (Graphics2D) g;
       g2d.setColor(lineColor);
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                            RenderingHints.VALUE_ANTIALIAS_ON);
       float dash[] = {strokeWidth * 2};
       g2d.setStroke(new BasicStroke(
         this.strokeWidth, BasicStroke.CAP_SQUARE, 
         BasicStroke.JOIN_MITER, 1f, dash, 0));
       // shrink the painting rectangle by half the stroke width
       int halfWidth = 1 + this.strokeWidth/2;
       g2d.drawRect(x+halfWidth, y+halfWidth, 
        width-(2*halfWidth), height-(2*halfWidth));
     }
   
     public Insets getBorderInsets(Component c) {
       return new Insets(this.margin,this.margin,this.margin,this.margin);
     }
     public Insets getBorderInsets(Component c, Insets insets) {
       insets.left = insets.top = insets.right = insets.bottom=this.margin;
       return insets;
     }
     public boolean isBorderOpaque() { return true; }
     public static void main(String[] args) {
       JLabel label = new JLabel("A Dashed Border");
       label.setFont(new Font("Georgia", Font.PLAIN, 25));
       //label.setOpaque(true);
       //label.setBackground(Color.orange);
       label.setBorder(new DashBorder(Color.blue, 6));
       JOptionPane.showMessageDialog(null, label); 
     }
   }

If a border uses a thick BasicStroke to paint itself, then half of the width of that stroke is painted outside of the bounding rectangle for the component, and is therefore not visible (or not painted at all). This means that we have to adjust the painting position and size parameters of the paintBorder() method (which by default use the position and size of the component on which the border will be painted.

the algorithm for painting a border with a stroke width 'width'

    public void paintBorder(
      Component c, Graphics g, int x, int y, int width, int height) {
      Graphics2D g2d = (Graphics2D)g;
         ...
      // half of the stoke width is outside of the component (truncated)
      int halfWidth = 1 + this.strokeWidth/2;
      g2d.drawRoundRect(x+halfWidth, y+halfWidth, 
        width-(2*halfWidth), height-(2*halfWidth), 20, 20);
    }

If the component (JLabel) has an odd number of pixels then there will be a 1 pixel row outside of the border.

a nice border with rounded corners, painting problems fixed

   import java.awt.*;
   import javax.swing.*;
   import javax.swing.border.AbstractBorder;
   public class RoundedBorder extends AbstractBorder {
     private int margin;
     private static final long serialVersionUID = 1L;
     private Color color;
     int strokeWidth;  // line stroke thickness
     int cornerRadius; // how much rounding to do
     
     public RoundedBorder(Color color, int width, int radius) { 
       this.color = color;
       this.strokeWidth = width;
       this.cornerRadius = radius;
       this.margin = width + 4;
     }
     public RoundedBorder(Color color, int width) { 
       this(color, width, 20);
     }
     public RoundedBorder() { 
       this(Color.black, 2, 20);
     }

     public void paintBorder(
       Component c, Graphics g, int x, int y, int width, int height) {
       Graphics2D g2d = (Graphics2D)g;
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                            RenderingHints.VALUE_ANTIALIAS_ON);
       g2d.setColor(color);
       g2d.setStroke(new BasicStroke(this.strokeWidth));
       int halfWidth = 1 + this.strokeWidth/2;
       g2d.drawRoundRect(x+halfWidth, y+halfWidth, 
        width-(2*halfWidth), height-(2*halfWidth), 
        this.cornerRadius, this.cornerRadius);
       //System.out.println("halfWidth:" + halfWidth);
     }
   
     public Insets getBorderInsets(Component c) {
       return new Insets(margin, margin, margin, margin);
     }
     public Insets getBorderInsets(Component c, Insets insets) {
       insets.left = insets.top = insets.right = insets.bottom=this.margin; 
       return insets;
     }

     public static void main(String[] args) {
       Font font = new Font("Georgia", Font.PLAIN, 30);
       JLabel l = new JLabel("A rounded corner border");
       l.setFont(font);
       //l.setOpaque(true);
       //l.setBackground(Color.orange);
       l.setBorder(new RoundedBorder(Color.blue, 6));
       JOptionPane.showMessageDialog(null, l);
     }     
   }

Border Interface ‹↑›

It is also possible to create a new type of Border by implementing the Border interface.

create a new type of border by implementing the interface, untested

   public static class GradientBorder implements Border {
     private Insets margin;
     public GradientBorder (int top, int left, int bottom, int right) {
       super ();
       margin = new Insets ( top, left, bottom, right );
     }
   
     public void paintBorder(
       Component c, Graphics g, int x, int y, int width, int height )
     {
       Graphics2D g2d = (Graphics2D) g;
       g2d.setPaint (new GradientPaint(
        x, y, Color.RED, x + width, y, Color.BLUE));
       Area border = new Area ( new Rectangle ( x, y, width, height ) );
       border.subtract ( new Area ( new Rectangle ( x + margin.left, y + margin.top, width - margin.left - margin.right, height - margin.top - margin.bottom ) ) );
       g2d.fill ( border );
     }
   
     public Insets getBorderInsets ( Component c )
     { return margin; }
     public boolean isBorderOpaque ()
     { return true; }
   }

Gotchas For Custom Borders ‹↑›

When we create a custom border by extending AbstractBorder, it is usually used in conjunction with a CompoundBorder and an EmptyBorder- if not, the border is 'truncated' or not drawn properly, because there is not enough space outside of the border. One remedy might be to adjust the x,y,width,height parameters of the paintBorder() method to give the Border more space, but then we may get background painting problems

Titled Borders ‹↑›

putting a title in the border

     TitledBorder titledBorder = BorderFactory.createTitledBorder ("Title");
     //titledBorder = BorderFactory.createTitledBorder (border, "Title");
     titledBorder.setTitleJustification (TitledBorder.CENTER);
     titledBorder.setTitlePosition (TitledBorder.BELOW_TOP);
     component.setBorder (titledBorder);

a panel with a titled, rounded corner border

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    public class RoundedCornerBorder {
      public static void main(String[] args) {
        JFrame f = new JFrame("a simple window");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        Border eb = new LineBorder(Color.gray, 1, true);
        //Border eb = BorderFactory.createLineBorder(Color.gray, 2, true);
        Border tb = BorderFactory.createTitledBorder(eb, "Login");
        p.setBorder(tb);
        p.add(new JLabel("User")); p.add(new JTextField());
        p.add(new JLabel("Password")); p.add(new JPasswordField());
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

a green italic center aligned title border with extra space

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    public class FancyTitleBorder {
      public static void main(String[] args) {
        JFrame f = new JFrame("Green italic titled border");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        Border eb = BorderFactory.createEtchedBorder();
        Border tb = BorderFactory.createTitledBorder(
          eb, "Login", TitledBorder.CENTER, TitledBorder.TOP, 
          new Font("Serif", Font.ITALIC, 10), Color.blue);
        Border sb  = BorderFactory.createEmptyBorder(5,5,5,5);
        Border cb = BorderFactory.createCompoundBorder(tb, sb);
        p.setBorder(cb);
        p.add(new JLabel("User")); p.add(new JTextField());
        p.add(new JLabel("Password")); p.add(new JPasswordField());
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

a green italic center aligned title border

    import javax.swing.*;
    import javax.swing.border.*;
    import java.awt.*;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("a simple window");
        JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
        Border eb = BorderFactory.createEtchedBorder();
        Border tb = BorderFactory.createTitledBorder(
          eb, "Login", TitledBorder.CENTER, TitledBorder.TOP, 
          new Font("Serif", Font.ITALIC, 10), Color.blue);
        p.setBorder(tb);
        p.add(new JLabel("User")); p.add(new JTextField());
        p.add(new JLabel("Password")); p.add(new JPasswordField());
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

Tabbed Panes ‹↑›

Tabbed panes are useful, and represent a modern and simple user interface element. The actual default shape of the tabs is not very attractive. A better style would be the Google chrome curved tabs.

a simple tabbed pane example

    import javax.swing.*;
    public class SimpleTabbedPane {
      public static void main(String[] args) {
        JFrame f = new JFrame("A simple JTabbedPane example");
        JTabbedPane jtp = new JTabbedPane();
        JPanel p1 = new JPanel(); p1.add(new JLabel("The 1st Tab Area"));
        JPanel p2 = new JPanel(); p2.add(new JLabel("The 2nd Tab Area"));
        jtp.addTab("Tab1", p1);
        jtp.addTab("Tab2", p2);
        jtp.addTab("Tab3", 
          new JPanel().add(new JLabel("The 3rd Tab Area")));
        JOptionPane.showMessageDialog(null, jtp);
      }
    }

a tabbed pane with tool tip text for the tabs

    import javax.swing.*;
    import java.awt.event.KeyEvent;
    public class TooltipTabbedPane {
      public static void main(String[] args) {
        JFrame f = new JFrame("Testing Tabs");
        JTabbedPane tp = new JTabbedPane();
        JPanel p1 = new JPanel();
        p1.add(new JLabel("The 1st Tab Area"));
        JPanel p2 = new JPanel();
        p2.add(new JLabel("The 2nd Tab Area"));
        tp.addTab("Tab1", null, p1, "View the first");
        tp.addTab("Tab2", null, p2, "View the second");
        JOptionPane.showMessageDialog(null, tp);
      }
    }

a tabbed pane with tabs at the right of the pane

    import javax.swing.*;
    public class RightTabbedPane {
      public static void main(String[] args) {
        JFrame f = new JFrame("A JTabbedPane- tabs on right");
        JTabbedPane tp = new JTabbedPane();
        tp.setTabPlacement(JTabbedPane.RIGHT);
        tp.setPreferredSize(new java.awt.Dimension(400, 400));
        JPanel p1 = new JPanel();
        p1.add(new JLabel("Information about mimosas"));
        JPanel p2 = new JPanel();
        p2.add(new JLabel("Images of Gardenias"));
        tp.addTab("Mimosa", null, p1);
        tp.addTab("Gardenia", null, p2);
        JOptionPane.showMessageDialog(null, tp);
      }
    }

a tabbed pane with icons for the tabs and short cut keys (alt s/d)

    import javax.swing.*;
    import java.awt.event.KeyEvent;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("Testing Tabs");
        JTabbedPane tp = new JTabbedPane();
        JPanel p1 = new JPanel();
        p1.add(new JLabel("This the screen Tab Area (first)"));
        JPanel p2 = new JPanel();
        p2.add(new JLabel("This is the drive Tab Area (second)"));
        ImageIcon icon1 = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/chardevice.png");
        tp.addTab("Screen", icon1, p1, "View the screen tab");
        tp.setMnemonicAt(0, KeyEvent.VK_S);
        ImageIcon icon2 = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/drive-cdrom.png");
        tp.addTab("Drive", icon2, p2, "View the drive tab");
        tp.setMnemonicAt(1, KeyEvent.VK_D);
        f.getContentPane().add(tp);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

set the shortcut key for first tab on the pane to 'alt' + s

 tp.setMnemonicAt(0, KeyEvent.VK_S);

If the text for the first tab on the tabbed pane contains an 's' then that letter will be automatically underlined.

set the shortcut key for second tab on the pane to 'alt' + D

 tp.setMnemonicAt(0, KeyEvent.VK_D);

a tabbed pane with icons but no text on the tabs

    import javax.swing.*;
    import java.awt.event.KeyEvent;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("Testing Tabs");
        JTabbedPane tp = new JTabbedPane();
        JPanel p1 = new JPanel();
        p1.add(new JLabel("The 1st Tab Area"));
        JPanel p2 = new JPanel();
        p2.add(new JLabel("The 2nd Tab Area"));
        ImageIcon icon1 = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/chardevice.png");
        tp.addTab(null, icon1, p1, "View the screen tab");
        ImageIcon icon2 = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/drive-cdrom.png");
        tp.addTab(null, icon2, p2, "View the drive tab");
        f.getContentPane().add(tp);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

a tabbed pane with icons and grid layout panels

    import javax.swing.*;
    import java.awt.event.KeyEvent;
    import java.awt.GridLayout;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("Testing Tabs");
        JTabbedPane tp = new JTabbedPane();
        JPanel p1 = new JPanel(new GridLayout(0, 1));
        p1.add(new JLabel("The 1st Tab Area"));
        p1.add(new JLabel(" another label"));
        p1.add(new JLabel(" another label"));
        JPanel p2 = new JPanel(new GridLayout(0, 1));
        p2.add(new JLabel("The 2nd Tab Area"));
        p2.add(new JLabel(" another label"));
        p2.add(new JLabel(" another label"));
        ImageIcon icon1 = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/chardevice.png");
        tp.addTab(null, icon1, p1, "View the screen tab");
        ImageIcon icon2 = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/drive-cdrom.png");
        tp.addTab(null, icon2, p2, "View the drive tab");
        f.getContentPane().add(tp);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

notes ==

Translucency And Opacity ‹↑›

Translucency is partial transparency. Computer screens display translucency by 'compositing' (combining or blending) the forground and the background colours to give the illusion of translucency.

The bit field in an image format which determines the tranlucency of a pixel is known as the 'alpha channel' as opposed to the red, green, and blue channels. Not all image formats support translucency or even transparency.

We use the java.awt.AlphaComposite class to blend forground and background colours to create the illusion of translucency. In Java an alpha value of 1.0f is completely opaque and 0.0f completely transparent.

create an AlphaCompositing object

 AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)

useful methods for tabbed panes
insertTab(String Icon, Component, String, int) - insert a tab
removeTabAt(3) - remove the 3rd tab
pane.removeAll() - remove all the tabs
pane.setSelectedIndex(2) - select the 2nd tab
pane.setTitleAt(2 "file") - set the title of the 2nd tab to 'file'
pane.setIconAt(2 icon) - set the icon for the 2nd tab

SRC_OVER places the source color over destination color, blends them based on the transparency of the source. This is the most common compositing rule.

create a half translucent red colour (will get blended with background)

 Color c = new Color(1.0f, 0.0f, 0.0f, 0.5f)

In the example below the red Color is opaque but the AlphaComposite for the graphics2D object is 50% translucent, thereby causing the rectangle to be painting with 50% translucency. Basically the translucent square appears paler because its colour is combined with the white background colour.

draw a half translucent rectangle using an alpha composite

   import javax.swing.*;
   import java.awt.*;
   public class TranslucentPaint extends JPanel {
     public TranslucentPaint() { super(); }
     public void paintComponent(Graphics g) {
       Graphics2D gg = (Graphics2D) g;
       Color c = new Color(1.0f, 0.0f, 0.0f);
       gg.setPaint(c);
       gg.fillRect(0, 0, 100, 100);
       gg.setComposite(
         AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
       gg.fillRect(100, 100, 100, 100);
     }
     public Dimension getPreferredSize() 
       { return new Dimension(300, 300); }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new TranslucentPaint()); 
     }
   }

Translucency And Images ‹↑›

code for making translucent images, and extending a JLabel

   import java.awt.*;
   import java.awt.image.*;
   import javax.swing.*;
   import javax.imageio.ImageIO;
   import java.net.URL;
   
   public class TransparentIcon {
     public static void main(String[] args) throws Exception {
       String imgURL =
       "http://www.gravatar.com/avatar/" +
       "a1ab0af4997654345d7a949877f8037e";
       final BufferedImage image = ImageIO.read(new URL(imgURL));
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           ImageIcon icon = new ImageIcon(image);
           JPanel  p = new JPanel(new GridLayout(2,3));
           for (int ii=0; ii<6; ii++) {
             TransparentLabel tl = new TransparentLabel();
             tl.setOpacity((ii+1)/6f);
             tl.setIcon(icon);
             p.add(tl);
           }
           JOptionPane.showMessageDialog(null, p);
         }
       });
     }
   }
   
   class TransparentLabel extends JLabel {
     float opacity = 1f;
     public void setOpacity(float opacity) {
       this.opacity = opacity;
     }
     private Icon getTranslucentIcon(Icon icon) {
       if (icon!=null) {
         BufferedImage bi = new BufferedImage(
           icon.getIconWidth(),
           icon.getIconHeight(),
           BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = bi.createGraphics();
         AlphaComposite ac = AlphaComposite.getInstance(
                               AlphaComposite.SRC_OVER,
                               opacity);
         g.setComposite(ac);
         icon.paintIcon(this,g,0,0);
         g.dispose();
         return new ImageIcon(bi);
       } else {
         return null;
       }
     }
   
     public void setIcon(Icon icon) {
       super.setIcon( getTranslucentIcon(icon) );
     }
   }

Opacity Translucency Transparency In User Interfaces ‹↑›

A feature of modern user interfaces is the use of semi-transparency or semi-opacity of components to create glass-like effect. This section concentrates on using these effects in user interfaces and should complement the section on translucency in the DRAWING AND JAVA2D section

www: http://java.sun.com/products/jfc/tsc/articles/painting/index.html
An article about painting an opacity
make a button completely transparent except for the text
    button.setOpaque(false);
    button.setContentAreaFilled(false);
    button.setBorderPainted(false);

create a semi (50%) transparent red button

    JButton myButton =new JButton(“press me”);
    myButton.setBackground(new Color(255,0,0,128)); 

another way to make a transparent top level window, w opaque component, but not on linux

    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setBackground(new Color(0f, 0f, 0f, 0.1f));
    f.setUndecorated(true);
    f.add(new JLabel("<html>Testing<br>1, 2, 3</html>"));
    f.pack();

The following is based on a suggestion by camickr. The transparent background for the JTextArea is set when it is instantiated, but I am not sure why this couldnt be in the constructor for the subclass.

The code below is incomplete.

create a semi transparent JTextArea with an image drawn behind it

    public class TransparentText extends JTextArea {
      @Override
      public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setComposite(???
        g.drawImage(...);
        super.paintComponent(g);
      }
    }
    ...
    TransparentText t = new TransparentText();
    t.setBackground(new Color(r, g, b, alpha));

make a button semi-opaque, untested

    @Override
    public void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g;
      g2.setComposite(
        AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0));
      super.paint(g2);
      g2.dispose();
    }

Apparently, it is difficult or impossible to make a semi-transparent cursor in Java (according to Andrew Thompson)

a complete transparent JTextArea example

   import java.awt.*;
   import javax.swing.*;
   import java.awt.Font;
   
   public class TransparentTextArea extends JTextArea {
     int alpha;
     public TransparentTextArea(int alpha) {
       super(4, 16);
       this.alpha = alpha;
       this.setBackground(new Color(0, 0, 0, alpha));
       this.setFont(new Font("Serif", Font.ITALIC, 24));
       this.setEditable(false);
       this.setText("Twas brillig and the slithy toves,\n"
                    + "Did gyre and gimble in the wabe;\n"
                    + "All mimsy were the borogoves,\n"
                    + "And the mome raths outgrabe.");
     }
   
     private static void create() {
       JFrame f = new JFrame();
       f.setLayout(new FlowLayout());
       f.getContentPane().setBackground(new Color(0xffffc0));
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       JPanel panel = new JPanel();
       panel.setBackground(new Color(0xffffc0));
       panel.add(new TransparentTextArea(128));
       f.add(panel); f.pack();
       f.setVisible(true);
     }
   
     public static void main(String[] args) {
       try {
         UIManager.setLookAndFeel(
           "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
       } catch (Exception e) { e.printStackTrace(); }
   
       EventQueue.invokeLater(new Runnable() {
         @Override
         public void run() { create(); }
       });
     }
   }

Transitions ‹↑›

Transitions are a modern (animated) way of moving from one 'screen' or layout to another based on user input. The idea behind transitions is to provide visual clues to the user about the logical flow of the application. See the filthy rich client book...

Layouts And Layout Managers ‹↑›

A layout manager is a way of managing the way the components are arranged in a panel or other container component. The idea is to arrange components (buttons, boxes etc) in a way that is both aesthetically pleasing and reflects the logic of the application.

Dynamic Layouts ‹↑›

A dynamic layout is one in which elements of the layout change according to the state of the application and user input.

In the code below, if no revalidate() method is called after the setVisible() method calls, the JTextField becomes invisible but the JTextArea does not expand to fill the extra space. With revalidate the JTextArea expands itself. If the JTextArea were editable we would probably have to use modifier (control etc) so that the character would not be inserted in the text area.

We could also use an AbstractAction subclass along with the ActionMap and InputMap for the JTextArea, but this is just an example.

hide a textfield on keypress enter and show with '/' keystroke

  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.*;
  public class HideAndShow extends JPanel implements ActionListener {
    JTextField field;
    JTextArea area;
    public HideAndShow() {
      super(new BorderLayout());
      this.field = new JTextField();
      this.field.setFont(new Font("Georgia", Font.ITALIC, 24));
      this.field.addActionListener(this);
      this.area = new JTextArea(20, 60);
      this.area.setEditable(false);
      this.area.addKeyListener(new KeyAdapter() {
        public void keyTyped(KeyEvent e) {
          if (e.getKeyChar() == '/') {
            HideAndShow.this.field.setVisible(true);
            HideAndShow.this.field.requestFocusInWindow();
          }
        }
      });
      this.add(this.field, BorderLayout.NORTH);
      this.add(this.area, BorderLayout.CENTER);
    } 
    public void actionPerformed(ActionEvent e) {
      this.field.setVisible(false);
      this.revalidate();
    }
    public static void main(String[] args) throws Exception { 
       JFrame f = new JFrame("Enter to hide, '/' to show");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.getContentPane().add(new HideAndShow());
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
    }
  }

Gotchas For Layout Managers ‹↑›

Some layout managers do not respect the size (java.awt.Dimension) returned by the getPreferredSize() method. For example the BorderLayout seems to make the BorderLayout.CENTER component as big a possible despite the preferred size.

Flowlayout ‹↑›

The java.awt.FlowLayout, which is the default for JPanels (except for the JFrame contentPane) simply places JComponents flowing across the screen (usually) from left to right, and wrapping to the next 'line' when the end of the screen space is reached.

The FlowLayout doesnt seem to know how to report its dimensions properly. For example if you put lots of JComponents into a panel with a FlowLayout only the first line of components may be displayed

http://tips4java.wordpress.com/2008/11/06/wrap-layout/ extends a FlowLayout to make the container calculate its size

BoxLayouts are said to be similar to FlowLayouts but offer more flexibility (vertical flow, etc)

create a panel with a left-aligned flowlayout (all rows align to left)

 JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));

On my debian-linux Gnome computer (java 1.6), the java application window is only made big enough to display the first line of JButtons. In other words the pack() method doesnt seem to be doing its job properly. This seems to be Gnome, or java bug. Calling revalidate on the panel doesnt help either. Make full screen to avoid the problem.

create a panel with a left aligned FlowLayout

  import javax.swing.*;
  import javax.swing.plaf.FontUIResource;
  import java.awt.*;
  public class FlowPanel extends JPanel {
    public FlowPanel() {
      super(new FlowLayout(FlowLayout.LEFT));
      for (String s: new java.io.File("..").list()) { 
        JButton b = new JButton(s); this.add(b);
      }
    } 
    public static void main(String[] args) throws Exception { 
       UIManager.put("Button.font", 
         new FontUIResource("Georgia", Font.PLAIN, 18));
       JFrame f = new JFrame("");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(new FlowPanel()); f.pack(); 
       f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setVisible(true);
    }
  }

Gotchas For Flowlayout ‹↑›

On a Gnome Linux computer (java 1.6) only the first line of the FlowLayout displays.

Borderlayout ‹↑›

A border layout is a simple design consisting of a centre location and north, south, east, west locations. The component which ocupies the BorderLayout.CENTER position is expanded to fill the available space, even if that component has is preferred size set.

The default layout for a JFrame.getContentFrame is a BorderLayout

a panel with a border layout

    JPanel panel = new JPanel(new BorderLayout());
    panel.add(comp, BorderLayout.CENTER);

The default position for a component added to a BorderLayout is the center.

add a JLabel to the center of a JPanel with a BorderLayout

  JPanel panel = new JPanel(new BorderLayout()); panel.add(jlabel);

a borderlayout with gaps and a title

    JPanel p = new JPanel(new BorderLayout(5,5));
    p.setBorder(new TitledBorder("Main GUI"));

create a panel with a border layout

  import javax.swing.*;
  import javax.swing.plaf.FontUIResource;
  import java.awt.*;
  public class BorderPanel extends JPanel {
    public BorderPanel() {
      super(new BorderLayout());
      JButton b = new JButton("Center");
      this.add(b, BorderLayout.CENTER);
      JButton bn = new JButton("North");
      this.add(bn, BorderLayout.NORTH);
      JButton bw = new JButton("West");
      this.add(bw, BorderLayout.WEST);
    } 
    public static void main(String[] args) throws Exception { 
       try {
        UIManager.setLookAndFeel(
          "javax.swing.plaf.nimbus.NimbusLookAndFeel");
       } catch (ClassNotFoundException e) { }
       UIManager.put(
         "Button.font", new FontUIResource("Georgia", Font.PLAIN, 18));
       JFrame f = new JFrame("");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.getContentPane().add(new BorderPanel());
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
    }
  }

Gotchas With Borderlayout ‹↑›

even if you set the rows and columns for a JTextArea (for example) with something like:

 JTextArea t = new JTextArea(40, 30);
the BorderLayout will ignore this if you place the JTextArea in the CENTER position.

Gridlayout ‹↑›

In a grid layout all elements of the grid are given an equal amout of space. This is often not pretty. Also, when the window is resized components such as text boxes will be large and ungainly.

It's not possible to add a component to a grid layout at a particular cell. One must add all components to the layout sequencially (left to right, top to bottom). Use empty labels to not add anything to a partiular cell.

www: http://leepoint.net/notes-java/GUI/layouts/30gridlayout.html
notes about grid layouts
create a layout with 1 column and unlimited rows
 GridLayout layout = new GridLayout(0, 1);

create a layout with a horizontal gap of 10 and vertical gap of 20

 GridLayout layout = new GridLayout(0, 1, 10, 20);

create a swing panel with a gridlayout and a titled border JPanel p = new JPanel(new GridLayout(0,1)); p.setBorder(new TitledBorder("Main GUI")); ,,,

The example below could be the basis of a different kind of file-browser, with keyboard on-the-fly search, sorting by folder/file, files sorted alphabetically, an action listener to do something when the file or folder is clicked.

a panel with a 4 column GridLayout, 10px spacing with filename buttons

  import javax.swing.*;
  import javax.swing.border.EmptyBorder;
  import javax.swing.plaf.FontUIResource;
  import java.awt.*;
  import java.awt.event.*;
  public class GridPanel extends JPanel implements ActionListener {
    public GridPanel() {
      super(new GridLayout(0,4,10,10));
      this.setBorder(new EmptyBorder(20,20,20,20));
      for (String s: new java.io.File("..").list()) { 
        JButton b = new JButton(s); this.add(b); b.addActionListener(this);
      }
    } 
    public void actionPerformed(ActionEvent e) { /*do something here*/ }
    public static void main(String[] args) throws Exception { 
       UIManager.put("Button.font", 
         new FontUIResource("Georgia", Font.PLAIN, 18));
       JFrame f = new JFrame("A GridLayout Example");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(new JScrollPane(new GridPanel())); f.pack(); 
       f.setLocationRelativeTo(null);
       f.setVisible(true);
    }
  }

a 2 by 2 grid layout with gaps between cells

    import javax.swing.*;
    import java.awt.GridLayout;
    public class TwoByTwoGrid {
      public static void main(String[] args) {
        JFrame f = new JFrame("A 2x2 Grid Layout");
        JPanel content = new JPanel(new GridLayout(2, 2, 5, 5));
        content.add(new JButton("Walnut"));
        content.add(new JButton("Eucalypt"));
        content.add(new JLabel(""));  // for empty cell
        content.add(new JButton("Myoporum"));
        f.getContentPane().add(content);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

create a panel with a 3 by 2 grid layout

 JPanel content = new JPanel(new GridLayout(3, 2, 10, 10));

combine 2 gridlayout panels in a single frame

    import javax.swing.*;
    import java.awt.GridLayout;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("Testing Grid Layouts");
        JPanel content = new JPanel(new GridLayout(2, 1));
        JPanel buttonPane = new JPanel(new GridLayout(3, 3, 5, 5));
        for (int ii = 0; ii < 9; ii++)
          { buttonPane.add(new JButton("" + ii)); }
        JPanel textPane = new JPanel(new GridLayout(3, 1, 5, 5));
        for (int ii = 0; ii < 3; ii++)
          { textPane.add(new JTextField(20)); }
        content.add(buttonPane);
        content.add(textPane);

        f.getContentPane().add(content);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

Gridbaglayout ‹↑›

The GridBagLayout has a bad reputation amongst those who know a great deal about Swing. Excessively complicated and easy to muck up. Maybe use BoxLayouts with nested panels.

The GridBagLayout is possibly the most flexible of the layout managers. See also the 'GroupLayout' or use a graphical tool.

a simple use of GridBayLayout and GridBagConstraints

  
     GridBagConstraints c = new GridBagConstraints ();
     c.gridwidth = GridBagConstraints.REMAINDER;
     c.fill = GridBagConstraints.HORIZONTAL;
     add (textField, c);

     c.fill = GridBagConstraints.BOTH;
     c.weightx = 1.0;
     c.weighty = 1.0;

using a grid bag, its not so hard, just like a table but with spans

     getContentPane().setLayout(new GridBagLayout());
     GridBagConstraints c = new GridBagConstraints();
     c.gridwidth = 2;
     c.gridheight = 1;
     c.anchor = GridBagConstraints.CENTER;
     c.fill = GridBagConstraints.BOTH;
     c.weightx = 1.0;
     c.weighty = 1.0;
     c.gridx = 0;
     c.gridy = 0;
     c.insets = new Insets(2, 2, 2, 2);
     getContentPane().add(new JScrollPane(pane), c);

Boxlayout ‹↑›

The javax.swing.BoxLayout arranges components in either a vertical or horizontal line. It has several ways to customize the arrangement. The BoxLayout does not wrap components unlike the FlowLayout

The BoxLayout is often used in conjuction with the javax.swing.Box which allows the creation of invisible elements such as glue, struts and rigid areas. These elements effect the position of the elements within a BoxLayout.

create a horizontal BoxLayout

 panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));

create a BoxLayout with a vertical orientation

 listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));

what does this do

 listPane.add(Box.createRigidArea(new Dimension(0,5)));

stop a JTextField from expanding in a BoxLayout

 textField.setMaximumSize( textField.getPreferredSize() );

a simple box example


  content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
          content.add(new JLabel("one"));

When the application window is made larger in the example below the extra space is put after the elements. See the 'glue' sections for how to change this behavior.

a vertical BoxLayout example with lots of buttons

   import java.awt.*;
   import javax.swing.*;
   public class BoxPanel extends JPanel {
     public BoxPanel() {
       super();
       this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
       for (String s: new String[]{"yew", "oak", "elm", "walnut"}) 
         this.add(new JButton(s));  
     }
     public static void main(String args[]) {
       EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("A vertical BoxLayout with JButtons");
           f.add(new BoxPanel());
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setVisible(true);
         }
       });
     }
   }

The example below seems to demostrate that the BoxLayout tries to make the components of the same width for a Y_AXIS layout

a simple BoxLayout example

   import javax.swing.*;
   public class BoxPanel extends JPanel {
     JTextField field;
     JTextArea area;
     public BoxPanel() {
       super();
       this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
       this.field = new JTextField(40);
       this.area = new JTextArea(20, 80);
       this.add(this.field);
       this.add(new JScrollPane(this.area));
     }
     public static void main(String args[]) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("A BoxLayout in a JPanel");
           f.add(new BoxPanel());
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

Glue With A Boxlayout ‹↑›

compositing rules used with AlphaComposite
glue determines how the BoxLayout gets resized. 'glue' fills space. Put glue where you want space to be put when the window is made bigger.

In the example below, to see the glue in action make the application window bigger. When the JFrame is enlarged extra space is put between the "oak" and "elm" buttons, not after all the buttons.

a vertical BoxLayout with some 'glue' after the second button

   import javax.swing.*;
   public class BoxPanel extends JPanel {
     public BoxPanel() {
       super();
       this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
       for (String s: new String[]{"yew", "oak", "elm", "walnut"}) {
         this.add(new JButton(s));  
         // java 1.6 bug? have to write javax.swing.Box
         if (s.equals("oak")) this.add(javax.swing.Box.createGlue());
       }
     }
     public static void main(String args[]) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("A vertical BoxLayout with JButtons");
           f.add(new BoxPanel());
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

In the example below, when the window is made larger the extra space is given equally between the 2nd and 3rd buttons.

a vertical BoxLayout with some 'glue' after 2nd and 3rd buttons

   import javax.swing.*;
   public class GlueBoxPanel extends JPanel {
     public GlueBoxPanel() {
       super();
       this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
       for (String s: new String[]{"yew", "oak", "elm", "walnut"}) {
         this.add(new JButton(s));  
         // java 1.6 bug? have to write javax.swing.Box
         if (s.equals("oak") || s.equals("elm"))
           this.add(javax.swing.Box.createGlue());
       }
     }
     public static void main(String args[]) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("A vertical BoxLayout with JButtons");
           f.add(new GlueBoxPanel());
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

Verticalstruts And Horizontalstruts With The Boxlayout ‹↑›

The vertical strut (Box.createVerticalStrut(int)) is used to put space between components in a vertical BoxLayout or to force a horizontal BoxLayout to have a certain height. The horizontal strut does something completely analagous but horizontally

a vertical BoxLayout with 10-pixel vertical struts

   import javax.swing.*;
   public class GlueBoxPanel extends JPanel {
     public GlueBoxPanel() {
       super();
       this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
       for (String s: new String[]{"yew", "oak", "elm", "walnut"}) {
         this.add(new JButton(s));  
         // java 1.6 bug? have to write javax.swing.Box
         this.add(javax.swing.Box.createVerticalStrut(10));
       }
     }
     public static void main(String args[]) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("A vertical BoxLayout with JButtons");
           f.add(new GlueBoxPanel());
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

Rigidareas And Boxlayouts ‹↑›

creates an invisible component which is always the same size. Not quite sure what the purpose of this is.

Gotchas For Boxes ‹↑›

In the code below, java 1.6, I get a "symbol not found" compile error but can fix it by writing javax.swing.Box.createGlue() even though the correct import statement is already present.

is there another 'Box' class?

     import java.awt.*;
     import javax.swing.*;
     ...
     jpanel.add(Box.createGlue());

Cardlayout ‹↑›

A cardlayout consists in a set of panels which sit on top of each other: only one is visible at any one time.

a complete card layout example

   public class CardLayoutDemo {
     private static JFrame createGUI() {
       JFrame testFrame = new JFrame(  );
       testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
       List<String> layoutConstraints = Arrays.asList( "first", "second", "third");
   
       final JPanel contentsPane = new JPanel(  );
       final CardLayout cardLayout = new CardLayout(  );
       contentsPane.setLayout( cardLayout );
   
       ActionListener listener = new ActionListener() {
         public void actionPerformed( ActionEvent aActionEvent ) {
           String constraint = aActionEvent.getActionCommand();
           cardLayout.show( contentsPane, constraint ); }
       };
   
       //add components to card layout with specific constraint
       for ( String constraints : layoutConstraints ) {
         contentsPane.add( new JLabel( constraints ), constraints );
       }
   
       //create buttons allowing to switch between the different layouts
       JPanel buttonPanel = new JPanel();
       for ( int i = 0; i < layoutConstraints.size(); i++ ) {
         String constraint = layoutConstraints.get( i );
         JButton button = new JButton( "Layout " + i);
         button.setActionCommand( constraint );
         button.addActionListener( listener );
         buttonPanel.add( button );
       }
   
       testFrame.add( contentsPane, BorderLayout.CENTER );
       testFrame.add( buttonPanel, BorderLayout.SOUTH );
       return testFrame;
     }

Grouplayout ‹↑›

The GroupLayout is, apparently, designed to be used by 'gui builder' tools. That means applications such as Netbeans or Eclipse which allow the user to create graphical interfaces by clicking and dragging. The disadvantage of the GroupLayout is that it seems necessary to create large amounts of boiler-plate code.

The Swing expert Rob Camick says that he knows nothing about the GroupLayout.

Implementing A Layoutmanager ‹↑›

http://tips4java.wordpress.com/2008/11/06/wrap-layout/ extends a FlowLayout to make the container calculate its size but the code has a strange encoding.

Jscrollpanes ‹↑›

JScrollPanes are a way of viewing components which are 2 big to fit onto the users screen or into the application layout. Scroll-panes can function with or without scrollbars, but alway contain a JViewPort (which is the component which actually displays the scrolled component).

When the scrollpane is scrolling a textcomponent the caret may override the scrollpane scroll operations.

http://tips4java.wordpress.com/2010/05/09/scrolling-a-form/ how to automatically scroll a JScrollPane to the focussed element when the user tabs

If an element is likely to be too big, add a scrollpane to it

 JScrollPane scrollpane = new JScrollPane(jcomponent);

enable mouse wheel scrolling

 JScrollPane.setWheelScrollingEnabled(boolean)

make scrolling faster by setting the increment (arrows, mouse wheel)

 jscrollpane.getVerticalScrollBar().setUnitIncrement(16);

scroll the JScrollPane all the way to the bottom

     JScrollBar v = scroll.getVerticalScrollBar():
     v.setValue(v.getMaximum());

scroll to the end of a panel which has just had something added to it

     panel.add(new JLabel("Label " + ++counter));
     panel.revalidate();
     int height = (int)panel.getPreferredSize().getHeight();
     scroll.getVerticalScrollBar().setValue(height);

an important method for scrolling to make a rectangle visible

 component.scrollRectToVisible(Rectangle r)

scroll all the way to the top of a JScrollPane

 scrollPane.getVerticalScrollBar().setValue(0);

another technique for scrolling to top, untested

 scrollPane.getViewport().setViewPosition(new Point(0,0));

set the height of a scroll pane to 1/3 of what it would be

       Dimension tablePreferred = tableScroll.getPreferredSize();
       tableScroll.setPreferredSize(
        new Dimension(tablePreferred.width, tablePreferred.height/3) );

add a scroll pane to a panel

   import javax.swing.*;
   import java.awt.GridLayout;
   public class ScrollPanel 
   {
     public static void main(String args[]) throws Exception
     {
        JPanel p = new JPanel(new GridLayout(0, 1));
        for (int i = 0; i < 400; i++)
          p.add(new JLabel("Label " + i));
        JFrame f = new JFrame("A panel which can scroll");
        f.add(new JScrollPane(p));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setVisible(true);
     }
   }

Using a scrollpane which a JOptionPane.showMessageDialog doesnt seem to work.

Jviewports And Views ‹↑›

The JViewPort of a JScrollPane is the part of the JComponent which can actually be seen at any given time.

The code oneliner below is very terse- but it should be the basis for the correct answer.

scroll a JEditorPane to some highlighted text

 editorPane.scrollRectToVisible( editorPane.modelToView(...) );

The code below should work with any JTextComponent. Based on a camickr reply.

get the text that is visible in the scrollpane of a JEditorPane

    // use the viewport to get the view position and size.
    JViewport viewport = scrollPane.getViewport();
    Point startPoint = viewport.getViewPosition();
    Dimension size = viewport.getExtentSize();
    Point endPoint = 
      new Point(startPoint.x + size.width, startPoint.y + size.height);

    // convert the start/end points to document indexes 
    int start = editorPane.viewToModel(startPoint);
    int end = editorPane.viewToModel(endPoint);
    // use the document indexes to retrieve the text
    String text = editorPane.getText(start, end - start);

The method textcomponent.modelToView(int) returns a one pixel wide rectangle with the height of the current line height (determined by the size of the font)

The example below is designed to help understand the values returned by methods such as viewport.getPosition() verticalScrollBar.getValue() and textarea.modelToView(10)

The code below demonstrate that the viewport position y value is the same as the verticalScrollBar value. And we can expect the same to be true for horizontal scrolling. Now add modelToView The code is not working perfectly: the scrollbar position doesnt get updated properly.

an example to understand scrollbar and viewport positions

   import java.io.*;
   import java.awt.*;
   import javax.swing.*;
   import javax.swing.event.*;
   import javax.swing.text.BadLocationException;
   public class ScrollBarTest extends JPanel implements CaretListener {
     JLabel label;
     JTextArea area;
     JScrollPane scroll;
     String fileName;
     public ScrollBarTest() {
       super(); 
       this.setLayout(new BorderLayout());
       this.fileName = "java-book.txt";
       this.label = new JLabel("<html>info:");
       this.area = new JTextArea();
       this.area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 22));
       this.area.addCaretListener(this);
       try {
         FileInputStream fis = new FileInputStream(this.fileName); 
         this.area.read(new InputStreamReader(fis, "UTF-8"), null);
       } catch (IOException e) { e.printStackTrace(); }
       this.scroll = new JScrollPane(this.area);
       this.add(this.label, BorderLayout.NORTH);
       this.add(scroll, BorderLayout.CENTER);
     }
     public void caretUpdate(CaretEvent e) { this.info(e); }
     public void info(CaretEvent e) {
       try {
        this.label.setText(String.format(
         "<html><ul><li> Caret Dot: %d<li> Caret Mark: %d" +
         "<li> Caret Rectangle: %s" +
         "<li> Vertical Scroll Bar Value: %d" +
         "<li> Viewport extent size: %s" +
         "<li> Viewport Position: %s</ul></html>",
         e.getDot(), e.getMark(),
         this.area.modelToView(e.getDot()).toString(),
         this.scroll.getVerticalScrollBar().getValue(),
         this.scroll.getViewport().getExtentSize().toString(),   
         this.scroll.getViewport().getViewPosition().toString()));   
       } catch (BadLocationException er) { er.printStackTrace(); }
     }
     public static void main(String args[]) {
       EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Searching Text in JEditorPane");
           f.add(new ScrollBarTest());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
           f.setVisible(true);
         }
       });
     }
   }

scroll the scrollpane to maintain the caret always in the center

    textarea.addCaretListener(new CaretListener {
      public void caretUpdate(CaretEvent e) { 
        try {
          Dimension view = scrollpane.getViewport().getExtentSize(); 
          JScrollBar bar = scrollpane.getVerticalScrollBar();
          bar.setValue(textarea.modelToView(e.getDot()).y - view.height/2);
        } catch (BadLocationException err) { err.printStackTrace(); }
      }
    });

the same as above but maintain the caret about 1/3 down the scrollpane

 bar.setValue(textarea.modelToView(e.getDot()).y - view.height/3);

scroll to maintain the caret always in the center of a jtextarea

   import java.io.*;
   import java.awt.*;
   import javax.swing.*;
   import javax.swing.event.*;
   import javax.swing.text.BadLocationException;
   public class CaretScroll extends JPanel implements CaretListener {
     JTextArea area;
     JScrollPane scroll;
     public CaretScroll() {
       super(new BorderLayout());
       this.area = new JTextArea();
       this.area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 22));
       this.area.addCaretListener(this);
       try {
         FileInputStream fis = new FileInputStream("java-book.txt"); 
         this.area.read(new InputStreamReader(fis, "UTF-8"), null);
       } catch (IOException e) { e.printStackTrace(); }
       this.scroll = new JScrollPane(this.area);
       this.add(scroll, BorderLayout.CENTER);
     }
     public void caretUpdate(CaretEvent e) { 
       try {
         Dimension view = this.scroll.getViewport().getExtentSize(); 
         JScrollBar bar = this.scroll.getVerticalScrollBar();
         bar.setValue(this.area.modelToView(e.getDot()).y - view.height/2);
       } catch (BadLocationException err) { err.printStackTrace(); }
     }
     public static void main(String args[]) {
       EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Scrolling with the caret");
           f.add(new CaretScroll());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
           f.setVisible(true);
         }
       });
     }
   }

Keyboard Scrolling And Jscrollpanes ‹↑›

By default a JScrollPane component cannot be scrolled using the keyboard up or down arrow keys. That is somewhat inconvenient. The technique below uses key-bindings and default swing actions to provide the simplest way to implement arrow key scrolling. See the keybindings section for more detailed information.

make up/down arrow keys scroll a JScrollPane (JScrollBar)

    JScrollBar vertical = scrollPane.getVerticalScrollBar();
    InputMap im = vertical.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
    im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
    im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
    }

It seems that for JScrollBars it is necessary to use the WHEN_IN_FOCUSED_WINDOW input map in order to do anything because the JScrollBar never receives focus, and probably shouldnt

add arrow key scrolling to a panel in a scroll pane

   import javax.swing.*;
   import java.awt.*;
   public class KeyScroll {
     public static void main(String args[]) throws Exception {
        JPanel p = new JPanel(new GridLayout(0, 1));
        Font font = new Font("Georgia", Font.ITALIC, 40);
        JLabel l;
        for (int i = 0; i < 200; i++) 
          { l = new JLabel("Label " + i); l.setFont(font); p.add(l); }
        JFrame f = new JFrame("Scrolling with the up/down arrow keys");
        JScrollPane scroll = new JScrollPane(p);
        JScrollBar vertical = scroll.getVerticalScrollBar();
        InputMap im = vertical.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
        im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
        f.add(scroll);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setVisible(true);
     }
   }

when the user presses 'G' scroll to the end of the JScrollPane

   JScrollBar vertical = this.getVerticalScrollBar();
   InputMap im = vertical.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
   im.put(KeyStroke.getKeyStroke("shift G"), "maxScroll");

The code below may represent a useful component for those who like using the keyboard to move around. The following supports the keystrokes (j: down, J: page down, k: up, K: page up, g: top, G: bottom, arrow keys up and down)

extend JScrollPane to support keyboard scrolling (j-down, k-up etc)

   import javax.swing.*;
   import java.awt.*;
   public class KeyScrollPane extends JScrollPane
   {
     public KeyScrollPane(JComponent c) {
       super(c);
       JScrollBar vertical = this.getVerticalScrollBar();
       InputMap im = vertical.getInputMap(
         JComponent.WHEN_IN_FOCUSED_WINDOW);
       im.put(KeyStroke.getKeyStroke("G"), "minScroll");
       im.put(KeyStroke.getKeyStroke("shift G"), "maxScroll");
       im.put(KeyStroke.getKeyStroke("J"), "positiveUnitIncrement");
       im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
       im.put(KeyStroke.getKeyStroke("shift J"), "positiveBlockIncrement");
       im.put(KeyStroke.getKeyStroke("K"), "negativeUnitIncrement");
       im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
       im.put(KeyStroke.getKeyStroke("shift K"), "negativeBlockIncrement");
     }
     public static void main(String args[]) throws Exception {
        JPanel p = new JPanel(new GridLayout(0, 1));
        Font font = new Font("Georgia", Font.ITALIC, 40);
        JLabel l;
        for (int i = 0; i < 200; i++) 
          { l = new JLabel("Label " + i); l.setFont(font); p.add(l); }
        JFrame f = new JFrame("Scrolling with the up/down arrow keys");
        KeyScrollPane scroll = new KeyScrollPane(p);
        scroll.getVerticalScrollBar().setUnitIncrement(10);
        f.add(scroll);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
     }
   }

Scrolling Jtextcomponents ‹↑›

It is often useful to scroll a JTextComponent such as a JTextArea JEditorPane or JTextPane to the place in the component where are particular piece of text occurs.

another technique seems to be just to set the Caret position

 jtextarea.setCaretPosition(index);

which actually seems alot easier. The scrollRectToVisible may be useful for non textcomponents.

The code below finds the first instance of a text string in a JTextArea and scrolls the JScrollPane so that the text is visible. The code also adds a highlight to the text using a DefaultHighlightPainter

The important methods in the code below are jtextarea.modelToView(int) and jtextarea.scrollRectToVisible(rect) The modelToView() method converts a document index to a pixel coordinates rectangle for the JTextArea.

This could be the beginning of a useful document search application. We need to add a DocumentListener to the JTextField to do 'on the fly' searching and highlighting, and we need to highlight all instances of the search text. Also it would be nice to display the found item in the middle of the JScrollPane and not at the beginning or the end.

Also the code use setSelectionEnd/Start to select all text in the field this is useful.

scroll a JTextArea to a specific text string and highlight it

   import java.io.*;
   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.swing.text.*;
   public class TextScroll extends JPanel implements ActionListener {
     JTextField field;
     JTextArea area;
     public TextScroll() {
       super();
       this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
       this.field = new JTextField(40);
       this.field.addActionListener(this);
       this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
       this.area = new JTextArea(20, 80);
       this.area.setFont(new Font("Monospaced", Font.PLAIN, 20));
       try {
         FileInputStream fis = new FileInputStream("java-book.txt");
         InputStreamReader in = new InputStreamReader(fis, "UTF-8");
         this.area.read(in, null);
       } catch (IOException e) {
         e.printStackTrace();
       }
       this.add(this.field);
       this.add(new JScrollPane(this.area));
     }
     public void actionPerformed(ActionEvent evt) {
       String search = this.field.getText();
       String docText = this.area.getText();
       int index = docText.indexOf(search);
       if (index < 0) {
         this.field.setText(String.format(
           "The text '%s' was not found", search));
         this.field.setSelectionStart(0);
         this.field.setSelectionEnd(this.field.getText().length());
         return;
       }
       try {
         Rectangle rect = this.area.modelToView(index);
         this.area.scrollRectToVisible(rect);
         // the method below is probably simpler and better!!
         // this.area.setCaretPosition(index);
         this.area.getHighlighter().removeAllHighlights();
         this.area.getHighlighter().addHighlight(
           index, index + search.length(), 
           new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
       } catch (BadLocationException e) {
         e.printStackTrace();
       }
     }
     public static void main(String args[]) {
       EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("TextScroll");
           f.add(new TextScroll());
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setVisible(true);
         }
       });
     }
   }

Jspinner ‹↑›

A JSpinner element is a small box which allows a user to select a value by clicking the increment or decrement arrows

connect a JSpinner and a JSlider


  import java.awt.*;
  import javax.swing.*;
  import javax.swing.SpinnerNumberModel;
  import javax.swing.event.ChangeEvent;
  import javax.swing.event.ChangeListener;

  /** @see http://stackoverflow.com/questions/6067898 */
  public class SpinSlider extends JPanel {
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame("SpinSlider!");
                f.add(new SpinSlider());
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setVisible(true);
            }
        });
    }

    public SpinSlider() {
        this.setLayout(new FlowLayout());
        final JSpinner spinner = new JSpinner();
        final JSlider slider = new JSlider();
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                JSlider s = (JSlider) e.getSource();
                spinner.setValue(s.getValue());
            }
        });
        this.add(slider);
        spinner.setModel(new SpinnerNumberModel(50, 0, 100, 1));
        spinner.setEditor(new JSpinner.NumberEditor(spinner, "0'%'"));
        spinner.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                JSpinner s = (JSpinner) e.getSource();
                slider.setValue((Integer) s.getValue());
            }
        });
        this.add(spinner);
    }
  }

Events For Jspinner ‹↑›

addChangeLister()

Jslider ‹↑›

how to use sliders

 http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html

a JSlider example

   JSlider slider= new JSlider(JSlider.HORIZONTAL,0,100,50); 
   //min value 0, max value 100, initial value 50
   slider.addChangeListener(this)
   JTextFox text = new JTextFox("50");
   //...
   public void stateChanged(ChangeEvent e)
   {
      JSlider source = (JSlider)e.getSource();
      int value = (int)source.getValue();
      text.setText(Integer.toString(value));
   }

create a JSlider and set some of its properties

     gui = new JPanel(new BorderLayout(3,4));
     quality = new JSlider(JSlider.VERTICAL, 0, 100, 75);
     quality.setSnapToTicks(true);
     quality.setPaintTicks(true);
     quality.setPaintLabels(true);
     quality.setMajorTickSpacing(10);
     quality.setMinorTickSpacing(5);
     quality.addChangeListener( new ChangeListener(){
         public void stateChanged(ChangeEvent ce) {
            // do something when the slider slides 
         }
     } );
     gui.add(quality, BorderLayout.WEST);

Jprogressbar ‹↑›

The JProgressBar is a swing JComponent which shows the progress for some activity which takes a noticeable amount of time, such as downloading a file.

box concepts

ways to update a JProgressBar
use a PropertyChangeListener
use a Timer
use a SwingWorker process() method

jargon
determinate progress bar - shows work done with a percentage
indeterminate - shows that work is happening but not how much

how to use progress bars

 http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html

create a new progress bar with a percentage displayed on it

    progressBar = new JProgressBar(0, 100);
    progressBar.setValue(0);
    progressBar.setStringPainted(true);

Indeterminate Jprogressbars ‹↑›

An 'indeterminate' progress bar just shows that something is happening but doesnt attempt to say how much. The way this bar is displayed depends on the look-and-feel of the application.

an indeterminate jprogress bar

   import java.awt.event.*;
   import javax.swing.*;
   import java.awt.*;
   public class BorderProgressBar extends JPanel 
   implements ActionListener {
     JProgressBar bar; JButton button; 
     BorderProgressBar() {
       super(new FlowLayout());
       Font f = new Font("Georgia", Font.ITALIC, 20);
       this.bar = new JProgressBar();
       this.bar.setStringPainted(true);
       this.bar.setFont(f);
       this.button = new JButton("start");
       this.button.addActionListener(this);
       this.button.setFont(f);
       this.add(this.button); this.add(this.bar);
     }
     public void actionPerformed(ActionEvent e) {
       if (e.getSource() == this.button) {
         this.bar.setString("working ...");
         this.bar.setIndeterminate(true);
       } 
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new BorderProgressBar());
         }
       });
     }
   }

Swingworkers With Jprogressbars ‹↑›

Often a JProgressBar is updated based on the amount of progress done for a task which is running in the background (a thread). One way to create this task is to use the SwingWorker class.

A PropertyChangeListener listens for changes in any one of the fields of a class

listen for changes in the fields of the 'task' class

 task.addPropertyChangeListener(this);

In the example below the setProgress() method sets a value for a bound variable, which can be listened to with a PropertyChangeListener Another way to achieve the result below would be to use the publish() and process() methods of the SwingWorker class. This would eliminate the need for a PropertyChangeListener.

a progress bar used with a propertychangelistener and swingworker

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import java.beans.*;
   import java.util.Random;
   public class ProgressBarDemo extends JPanel
       implements ActionListener, PropertyChangeListener {
     private JProgressBar progressBar;
     private JButton startButton;
     private JTextArea taskOutput;
     private Task task;
   
     class Task extends SwingWorker<Void, Void> {
       @Override
       public Void doInBackground() {
         Random random = new Random();
         int totalProgress = 0;
         this.setProgress(0);
         while (totalProgress < 100) {
           try {
             Thread.sleep(random.nextInt(1000));
           } catch (InterruptedException ignore) {}
           //Make random progress.
           totalProgress += random.nextInt(10);
           this.setProgress(Math.min(totalProgress, 100));
         }
         return null;
       }
       @Override
       public void done() {
         startButton.setEnabled(true);
         setCursor(null); //turn off the wait cursor
         taskOutput.append("Done!\n");
       }
     }
     public ProgressBarDemo() {
       super(new BorderLayout());
       startButton = new JButton("Start");
       startButton.addActionListener(this);
       progressBar = new JProgressBar(0, 100);
       progressBar.setValue(0);
       progressBar.setStringPainted(true);
   
       taskOutput = new JTextArea(5, 20);
       taskOutput.setMargin(new Insets(5,5,5,5));
       taskOutput.setEditable(false);
   
       JPanel panel = new JPanel();
       panel.add(startButton);
       panel.add(progressBar);
   
       this.add(panel, BorderLayout.PAGE_START);
       this.add(new JScrollPane(taskOutput), BorderLayout.CENTER);
       this.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
     }
  
     public void actionPerformed(ActionEvent evt) {
       startButton.setEnabled(false);
       setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
       this.task = new Task();
       this.task.addPropertyChangeListener(this);
       this.task.execute();
     }
   
     // Invoked when task's progress property changes.
     public void propertyChange(PropertyChangeEvent evt) {
       if ("progress" == evt.getPropertyName()) {
         int progress = (Integer) evt.getNewValue();
         progressBar.setValue(progress);
         taskOutput.append(String.format(
            "Completed %d%% of task.\n", this.task.getProgress()));
       }
     }
   
     public static void main(String[] args) {
       javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new ProgressBarDemo());
         }
       });
     }
   }

In the example below, the progress bar gets updated when it is set directly from the task thread with progressBar.setValue((int)percentageDone). In other words the PropertyChangeListener doesnt seem to be strictly necessary, but this is a tricky situation involving the event dispatch thread. I could be overlooking some important detail. The swing tutorial uses the property change listener to link the progress bar and the worker thread progress.

an image load with progress bar and swingworker, example working

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import java.beans.*;
   import java.io.*;
   import java.net.*;
   import java.util.Iterator;
   import javax.imageio.*;
   import javax.imageio.event.IIOReadProgressListener;
   import javax.imageio.stream.*;
   //import java.util.concurrent.ExecutionException;

   public class ImageProgress extends JPanel implements ActionListener {
     private JProgressBar progressBar;
     private JButton startButton;
     private Task task;
   
     class Task extends SwingWorker<Void, Void> {
       @Override
       public Void doInBackground() {
         ImageProgress.this.load();
         return null;
       }
       @Override
       public void done() {
         startButton.setEnabled(true);
         progressBar.setString("Download Completed");
         setCursor(null); //turn off the wait cursor
       }
     }
   
     public ImageProgress() {
       super(new BorderLayout());
       startButton = new JButton("Load");
       startButton.addActionListener(this);
       this.progressBar = new JProgressBar(0, 100);
       this.progressBar.setValue(0); progressBar.setStringPainted(true);

       JPanel panel = new JPanel();
       panel.add(startButton); panel.add(progressBar);
       this.add(panel, BorderLayout.PAGE_START);
     }
  
     private void load() { 
       //URL imgUrl = 
         // new URL("http://bumble.sourceforge.net/doc/cv/mjb-inchair.jpg");
       try {
       URL imgUrl = new URL("file:big.jpg");
       InputStream is = imgUrl.openStream();
       ImageInputStream iis = ImageIO.createImageInputStream(is);
       Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
       ImageReader reader = it.next();
       reader.setInput(iis);
       reader.addIIOReadProgressListener(new IIOReadProgressListener() {
         public void sequenceStarted(ImageReader source, int minIndex) {}
         public void sequenceComplete(ImageReader r) {}
         public void imageStarted(ImageReader r, int imageIndex) {}
         public void imageProgress(ImageReader r, float percentageDone) {
           System.out.format("Percent Downloaded: %f\n", percentageDone);
           ImageProgress.this.progressBar.setValue((int)percentageDone);
         }
         public void imageComplete(ImageReader source) {
           //ImageProgress.this.progressBar.setString("Download Completed");
         }
         public void thumbnailStarted(ImageReader r, int imageIndex, int thumbnailIndex) { }
         public void thumbnailProgress(ImageReader r, float percentDone) {}
         public void thumbnailComplete(ImageReader source) {}
         public void readAborted(ImageReader source) {}
       });
       Image image = reader.read(0);
       //Icon icon = new ImageIcon(image);
       } 
       catch (MalformedURLException e) {}
       catch (IOException e) {}
     }

     public void actionPerformed(ActionEvent evt) {
       startButton.setEnabled(false);
       setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
       this.task = new Task();
       //this.task.addPropertyChangeListener(this);
       this.task.execute();
     }
   
     public static void main(String[] args) {
       javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new ImageProgress());
         }
       });
     }
   }

The example above may be difficult to understand. The PropertyChangeListener updates the value of the progress bar. This listener fires whenever the 'progress' property of the SwingWorker task object changes.

Timers And Jprogressbars ‹↑›

a simple jprogress bar used with a timer

   import java.awt.event.*;
   import javax.swing.*;
   import java.awt.Font;
   public class SimpleProgressBar implements ActionListener {
     Timer timer;
     JProgressBar bar;
     int counter;
     SimpleProgressBar() {
       this.bar = new JProgressBar(0, 50);
       this.bar.setValue(0); this.bar.setStringPainted(true);
       this.bar.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.counter = 0;
       this.timer = new Timer(80, this); this.timer.start();
       JOptionPane.showMessageDialog(null, bar);
     }
     public void actionPerformed(ActionEvent e) {
       this.counter++;
       this.bar.setValue(this.counter);
       if (this.counter > 49) {
         this.bar.setString("finished"); timer.stop();
       }
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           SimpleProgressBar bar = new SimpleProgressBar();
         }
       });
     }
   }

a vertical jprogress bar used with a timer

   import java.awt.event.*;
   import javax.swing.*;
   public class CountDownProgressBar {
     Timer timer;
     JProgressBar progressBar;
     CountDownProgressBar() {
       progressBar = new JProgressBar(JProgressBar.VERTICAL, 0, 10);
       progressBar.setValue(10);
       ActionListener listener = new ActionListener() {
         int counter = 10;
         public void actionPerformed(ActionEvent ae) {
           counter--;
           progressBar.setValue(counter);
           if (counter<1) {
             JOptionPane.showMessageDialog(null, "Kaboom!");
             timer.stop();
           }
         }
       };
       timer = new Timer(1000, listener);
       timer.start();
       JOptionPane.showMessageDialog(null, progressBar);
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           CountDownProgressBar cdpb = new CountDownProgressBar();
         }
       });
     }
   }

Appearance Of The Jprogressbar ‹↑›

The progress bar seems to paint some kind of a border itself, which is doesnt look very good with a custom border.

a jprogress bar with a custom border

   import java.awt.event.*;
   import javax.swing.*;
   import java.awt.*;
   public class BorderProgressBar extends JPanel 
   implements ActionListener {
     Timer timer;
     JProgressBar bar;
     JButton button;
     int counter;
     BorderProgressBar() {
       super(new FlowLayout());
       Font f = new Font("Georgia", Font.ITALIC, 20);
       this.bar = new JProgressBar(0, 50);
       this.bar.setValue(0); this.bar.setStringPainted(true);
       this.bar.setFont(f);
       this.bar.setBorder(new RoundedBorder());
       this.button = new JButton("start");
       this.button.addActionListener(this);
       this.button.setFont(f);
       this.add(this.button); this.add(this.bar);
     }
     public void actionPerformed(ActionEvent e) {
       if (e.getSource() == this.button) {
         this.bar.setString(null);
         this.counter = 0;
         this.timer = new Timer(80, this); this.timer.start();
       } 
       else {
         this.counter++;
         this.bar.setValue(this.counter);
         if (this.counter > 49) {
           this.bar.setString("finished"); this.timer.stop();
         }
       }
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new BorderProgressBar());
         }
       });
     }
   }

Gotchas For Jprogressbar ‹↑›

If the setStringPainted() method is not set to true then the setString() method will do nothing, which is logical but maybe surprising.

Once you use setString() on a JProgressBar, it wont display values until you call bar.setString(null)

Jcheckbox ‹↑›

A check box is a small box in which the user can place a 'tick' or 'check' by clicking with the mouse. These elements are usually used in order to select more than one item in a list.

create a simple checkbox which is initially selected

   import javax.swing.*;
   public class SimpleCheckBox {
     public static void main(String[] args) {
        JFrame f = new JFrame("A JCheckBox example");
        JCheckBox b = new JCheckBox("Shopping"); b.setSelected(true);
        f.add(b); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
     }
   }

a check box with a short-cut (mnemonic) alt 's' and a tool tip

   import javax.swing.*;
   import java.awt.event.KeyEvent;
   public class ShortCutCheckBox {
     public static void main(String[] args) {
        JCheckBox b = new JCheckBox("Grow Trees");
        b.setSelected(true); b.setMnemonic(KeyEvent.VK_G); 
        b.setToolTipText(
           "<html><big><big>Use 'alt g' to toggle the checkbox ");
        JPanel p = new JPanel(); p.add(b);
        JFrame f = new JFrame("JCheckBox with a Mnemonic Key");
        f.add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
     }
   }

a check box with a large font

   import javax.swing.*;
   import java.awt.Font;
   public class FontCheckBox {
     public static void main(String[] args) {
        JFrame f = new JFrame("A JCheckBox with a large Font");
        JCheckBox b = new JCheckBox("Big Text");
        b.setFont(new Font("Serif", Font.PLAIN, 20));
        JPanel p = new JPanel(); p.add(b);
        f.add(p); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
     }
   }

a check box with html text for the tool tip and the display text

   import javax.swing.*;
   public class HtmlCheckBox {
     public static void main(String[] args) {
        JFrame f = new JFrame("Html in JCheckBoxes");
        JCheckBox b = new JCheckBox("<html>Vi<u>m</u></html>");
        b.setToolTipText("<html><em>Click</em> to go shopping</html>");
        JPanel p = new JPanel(); p.add(b);
        f.add(p); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
     }
   }

a list of files with check boxes in the current folder

   import java.io.File;
   import javax.swing.*;
   import java.awt.GridLayout;
   public class FileListCheckBox {
     public static void main(String[] args) {
        JFrame f = new JFrame("Check Boxes with a List of Files");
        JPanel p = new JPanel(new GridLayout(0,1));
        for (File file: new File(".").listFiles()) {
          p.add(new JCheckBox(file.getName()));
        }
        f.add(new JScrollPane(p));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
     }
   }

create a checkbox and do something when it is checked

     JCheckBox box = new JCheckBox("Anti-aliasing", false);
     ItemListener listener = new ItemListener() {
       public void itemStateChanged(ItemEvent e) {
         // do something
       }
     };
     box.addItemListener(listener);

Jradiobutton ‹↑›

Radio Buttons are similar to check boxes but may be configured to only allow one to be 'checked' at once. Only one button within a group may be selected.

a list of files with radio buttons

   import java.io.File;
   import javax.swing.*;
   import java.awt.GridLayout;
   public class Test {
     public static void main(String[] args)
     {
        JFrame f = new JFrame("one button");
        JPanel p = new JPanel(new GridLayout(0,1));
        ButtonGroup group = new ButtonGroup();
        JRadioButton r;
        File[] ff = (new File(".")).listFiles();
        for (int ii = 0; ii < ff.length; ii++)
        {
          p.add(r = new JRadioButton(ff[ii].getName()));
          group.add(r);
        }
        f.getContentPane().add(new JScrollPane(p));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
     }
   }

Jbuttons ‹↑›

A button is a graphical component which can be 'clicked' with the users mouse device in order to carry out some action. In java buttons are implemented with the swing JButton class.

add an 'access key' to a button (pressing the key, 'clicks' the button)

 jbutton.setMnemonic(KeyEvent.VK_I);

create a button with 2 lines of text

 JButton b = new JButton("<html><b><u>T</u>wo</b><br>lines</html>");

create a button with underlined 20 point text and a tool tip

   import javax.swing.*;
   import java.awt.Font;
   public class Test {
     public static void main(String[] args) {
        JFrame f = new JFrame("one button");
        JButton button = new JButton("<html><u>Click</u></html>");
        button.setToolTipText("click to start the game");
        button.setFont(new Font("Serif", Font.PLAIN, 20));
        JPanel p = new JPanel();
        p.add(button);
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
     }
   }

The BasicArrowButton cant display text

create a button with a right pointing arrow or triangle in it

   import javax.swing.*;
   import javax.swing.plaf.basic.BasicArrowButton;
   import java.awt.Font;
   public class ArrowButton {
     public static void main(String[] args) {
        JButton button = new BasicArrowButton(SwingConstants.EAST);
        JOptionPane.showMessageDialog(null, button);
     }
   }

put a button in a JFrame window

   import javax.swing.*;
   public class Test {
     public static void main(String[] args) {
        JFrame f = new JFrame("one button");
        JButton button = new JButton("hello");
        JPanel p = new JPanel();
        p.add(button); f.add(p);
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
     }
   }

set the font and colour for the JButton text

   import javax.swing.*;
   import java.awt.*;
   public class ButtonFont {
     public static void main(String[] args) {
        JButton button = new JButton("hello");
        button.setFont(new Font("Serif", Font.ITALIC, 20));
        button.setForeground(Color.green);
        JOptionPane.showMessageDialog(null, button);
     }
   }

extend the jframe class and place a button in it

   import javax.swing.*;
   public class FrameButton extends JFrame {
     public FrameButton () {
        super();
        this.add(new JButton("A Button in a JFrame"));
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack(); this.setLocationRelativeTo(null);
        this.setVisible(true);
     }
     public static void main(String[] args) { new FrameButton(); }
   }

a jframe class which contains a button and listens for clicks

   import javax.swing.*;
   import java.awt.event.*;
   public class Test extends JFrame implements ActionListener {
     JButton button;
     public Test () {
        this.button = new JButton("hello");
        this.button.addActionListener(this);
        this.getContentPane().add(this.button);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack(); this.setLocationRelativeTo(null);
        this.setVisible(true);
     }
     public void actionPerformed(ActionEvent e) {
       JOptionPane.showMessageDialog(
         this, "clicked " + e.getActionCommand());
     }
     public static void main(String[] args) { Test t = new Test(); }
   }

change a label when a button is clicked

   import java.awt.event.*;
   import javax.swing.*;
   public class Test {
     public static void main(String[] args)
     {
        JFrame f = new JFrame("one button");
        JButton button = new JButton("click");
        final JLabel label = new JLabel("hello");
        button.addActionListener(new ActionListener(){
          public void actionPerformed(ActionEvent e)
            { label.setText("bye"); }});
        JPanel p = new JPanel();
        p.add(button); p.add(label);
        f.add(p);
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack(); f.setVisible(true);
     }
   }

make a click event handler for the button

      final JButton b = new JButton("click");
      b.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e)
        {
          b.setText("click");
        }
      });

make an action which is executed when a button is pushed

    Action showMessage = new AbstractAction() {
      { putValue(Action.NAME, "Message"); }
      public void actionPerformed(ActionEvent e) { }
    };
    
    JButton loadButton = new JButton(loadAction);
    panel.add(loadButton);

set the gap between the text and the icon in a button

 button.setIconTextGap(8);

the position of the icon and text in the button.

     button.setVerticalAlignment(SwingConstants.TOP);
     button.setHorizontalAlignment(SwingConstants.LEFT);

position the text relative to the icon in the button

 http://www.exampledepot.com/egs/javax.swing/button_MoveIcon.html?l=rel

Jlabels ‹↑›

Swing labels or JLabels are used to display a small amount of text and/or an ImageIcon. They are also used as the element in JLists and JComboBoxes

declare a new JLabel

 JLabel testLabel;

create a new JLabel with some initial text

 testLabel = new JLabel("A new label");

change the text for the JLabel

 testLabel.setText("new file");

create a label with a mnemonic and associate with a comboBox

     JLabel label = new JLabel("Select Component:");
     label.setDisplayedMnemonic('S');
     label.setLabelFor( comboBox );

create a label with an icon

 Icon icon = new Icon(...); JLabel l = new JLabel(icon);

 label.setIcon(...);

change the size of a label after setVisible()

    JLabel label;
    label.setPreferredSize(new Dimension(100, 100) );
    label.revalidate();

create a JLabel with the standard information icon

   import java.awt.*;
   import javax.swing.*;
   public class IconLabel {
     public static void main(String args[]) {
       JFrame f = new JFrame("Icon in a JLabel");
       JLabel label = new JLabel("JLabel with Information icon");
       label.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
       f.add(label, BorderLayout.NORTH);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null); 
       f.setVisible(true);
     }
   }

add a label to a window

   import javax.swing.*;
   public class LabelTest {
     public static void main(String[] args) {
       JFrame f = new JFrame("a simple window");
       JLabel label = new JLabel("Just A Label");
       f.getContentPane().add(label);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setLocationRelativeTo(null); f.pack();
       f.setVisible(true);
     }
   }

add a label and text field to a window frame

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("Testing Labels");
        JLabel label = new JLabel("Enter Name");
        JTextField box = new JTextField(10);
        JPanel pl = new JPanel();
        pl.add(label);
        pl.add(box);
        f.getContentPane().add(pl);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

The rounded corners below dont seem to work, or the arc is so small that it is invisible.

set the preferred size of a label

 jlabel.setPreferredSize(100, 100);

Html With Jlabels ‹↑›

The text of a JLabel can be html and include css directives. For the text to be interpreted as html it must start with '<html>'

make text in a JLabel wrap to a particular pixel width

  import javax.swing.*;
  class FixedWidthLabel {
    public static void main(String[] srgs) {
      String s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu nulla urna. Donec sit amet risus nisl, a porta enim. Quisque luctus, ligula eu scelerisque gravida, tellus quam vestibulum urna, ut aliquet sapien purus sed erat. Pellentesque consequat vehicula magna, eu aliquam magna interdum porttitor...";
        String html1 = "<html><body style='width: ";
        String html2 = "px'>";
        JOptionPane.showMessageDialog(null, new JLabel(html1+"200"+html2+s));
        JOptionPane.showMessageDialog(null, new JLabel(html1+"300"+html2+s));
    }

Borders With Jlabels ‹↑›

For a rounded corner border for a JLabel you have to write your own border class, because the LineBorder rounded corner option doesnt seem to work.

set the border for a label

 jlabel.setBorder(BorderFactory.createLineBorder(Color.black));

Images In Jlabels ‹↑›

put an image in a label

 jlabel.setIcon(new ImageIcon("imagefilename");

display a label with text and an image

    import javax.swing.*;
    public class TextImageLabel {
      public static void main(String[] args) {
        JFrame f = new JFrame("a simple window");
        ImageIcon icon = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/chardevice.png");
        JLabel label = new JLabel("Image and Text", icon, JLabel.CENTER);
        f.getContentPane().add(label);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

create a label with just an icon image and no text

    import javax.swing.*;
    public class Test {
      public static void main(String[] args) {
        JFrame f = new JFrame("a simple window");
        ImageIcon icon = new ImageIcon(
          "/usr/share/icons/gnome/24x24/devices/chardevice.png");
        JLabel label = new JLabel(icon);
        f.getContentPane().add(label);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.pack();
        f.setVisible(true);
      }
    }

Colors In Jlabels ‹↑›

set the background colour of a JLabel to orange

 jlabel.setBackground(Color.orange); jlabel.setOpaque(true);

Aligning Text And Images In Jlabels ‹↑›

a label with text and an image

 l = new JLabel("Image and Text", icon, JLabel.CENTER);

create a label with right aligned text

 JLabel label = new JLabel("label text", SwingConstants.RIGHT);

align the text of a label underneath its image icon

    JLabel l = new JLabel("text underneath image");
    l.setHorizontalTextPosition(JLabel.CENTER);
    l.setVerticalTextPosition(JLabel.BOTTOM);

display a 48pt centre aligned label in the logical serifed font

   import javax.swing.*;
   import java.awt.Font;
   public class Test {
     public static void main(String[] args) {
       JLabel title = new JLabel("A Big Label", JLabel.CENTER);
       title.setFont(new Font("Serif", Font.BOLD, 48));
       JOptionPane.showMessageDialog(null, title);
     }
   }

Css Html And Jlabels ‹↑›

The text of a swing JLabel can be html and can include some subset of cascading style sheets (css). The provides a way to style the text which is displayed in the label. Any label text which begins with the tag <html> will be treated as html.

set the font size for a JLabel using a css style attribute

   import javax.swing.*;
   import java.awt.Font;
   public class CssLabel {
     public static void main(String[] args) {
       JLabel l = new JLabel(
         "<html><body style='font-size: 30px'>A Big Label", JLabel.CENTER);
       JOptionPane.showMessageDialog(null, l);
     }
   }

The css property seems to override and Font which is applied to the JLabel with the setFont() method.

set the font size for a JLabel using a css style attribute

   import javax.swing.*;
   import java.awt.Font;
   public class CssLabel {
     public static void main(String[] args) {
       JLabel l = new JLabel(
         "<html><body style='font-size: 30px'>A Big Label", JLabel.CENTER);
       l.setFont(new Font("Serif", Font.BOLD, 10));
       JOptionPane.showMessageDialog(null, l);
     }
   }

In the code below the <style> tag must be within the <head> tag and before the body tag.

use the html <style> tag to add css to a JLabel html

   StringBuffer sb = new StringBuffer();
   sb.append("<html><head><style type='text/css'>");
   sb.append("li { font-style: italic; font-size: 30pt; }");
   sb.append("li { font-family: serif; color: #ff5555; }");
   sb.append("ul { border-width: 4px; border-style: solid;
             border-color: #ff0000; } ");
   sb.append("ul { background-color: #ffeeee; }");
   sb.append("</style></head>");
   sb.append("<h3>H3 Header</h3>");
   sb.append("<ul><li>large serifed text</li><li>as list items</li>");
   sb.append("</html>");
   
   JLabel l3 = new JLabel(sb.toString());

Paintcomponent Method For Jlabel ‹↑›

One way to customise the appearance of a JLabel component (especially its background) is to override the paintComponent() method of the class. Within the paintComponent() method one should call the super.paintComponent() method otherwise you are pretty much writing a swing component from scratch.

Ideas: Include examples for translucent colors for the JLabel background and place stuff behind the JLabel (text, images ...) to see how it looks. Use translucent gradient paints. Use a custom paint with the paintComponent method- draw lots dingbats etc.

The example below creates a JLabel subclass which is identical to a JLabel except that it only has one constructor (instead of several). But the example provides a template for overriding the paintComponent method of a JLabel (or any other JComponent)

a skeleton example of overriding the paintComponent() method

    import javax.swing.*;
    import java.awt.Graphics;
    public class PaintLabel extends JLabel {
      public PaintLabel(String text) {
        super(text);
      }
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
      }
    }

The example below shows that if the super.paintComponent() method is called first within the paintComponent method, then whatever is painted will be painted on top of the JLabel text. This is usually not what is wanted.

example the JLabel text get covered by the painting code

    import javax.swing.*;
    import java.awt.*;
    public class PaintLabel extends JLabel {
      public PaintLabel(String text) {
        super(text);
      }
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.green);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
          }
        });
      }
    }

call super.paintComponent() last to draw the label text on top

    import javax.swing.*;
    import java.awt.*;
    public class PaintLabel extends JLabel {
      public PaintLabel(String text) {
        super(text);
      }
      public void paintComponent(Graphics g) {
        g.setColor(Color.green);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
          }
        });
      }
    }

painting with a background, the background is red, not green

    import javax.swing.*;
    import java.awt.*;
    public class PaintLabel extends JLabel {
      public PaintLabel(String text) {
        super(text);
        this.setOpaque(true); this.setBackground(Color.red);
      }
      public void paintComponent(Graphics g) {
        g.setColor(Color.green);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
          }
        });
      }
    }

In the example below, it is necessary to subtract one from the width and height properties in order for all sides of the rectangle to be visible.

draw a 1 pixel rectangle around a JLabel

    g2d.draw(new Rectangle2D.Double(
          0, 0, this.getWidth()-1, this.getHeight()-1));

Note that if you would like to use a rounded corner Border on a JComponent with a background color, then you will need to use a technique such as the one below.

The example below gets the background color from the JLabel but does not honor the JLabel behaviour of being transparent by default.

paint a rounded corner background on a JLabel

    import javax.swing.*;
    import java.awt.*;
    import java.awt.geom.RoundRectangle2D;
    public class CornerLabel extends JLabel {
      int cornerRadius;
      public CornerLabel(String text) {
        super(text);
        this.cornerRadius = 12;
      }
      public CornerLabel(String text, int cornerRadius) {
        super(text);
        this.cornerRadius = cornerRadius;
      }
      public void paintComponent(Graphics g) {
        Graphics2D gg = (Graphics2D) g;
        int r = this.cornerRadius;
        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                            RenderingHints.VALUE_ANTIALIAS_ON);
        gg.setColor(this.getBackground());
        gg.fill(new RoundRectangle2D.Double(
          0, 0, this.getWidth()-1, this.getHeight()-1, r, r));
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JLabel l = new CornerLabel("Rounded Corner Background", 20);
            l.setBackground(Color.blue);
            l.setFont(new Font("Georgia", Font.PLAIN, 40));
            JOptionPane.showMessageDialog(null, l);
          }
        });
      }
    }

In order to honor the JLabel behaviour of transparent by default we need to include code such

 if (this.isOpaque()) { /* painting code */ }

rounded corners background with a gradient paint

    import javax.swing.*;
    import java.awt.*;
    import java.awt.geom.RoundRectangle2D;
    public class RoundCornerLabel extends JLabel {
      int cornerRadius;
      public RoundCornerLabel(String text) {
        super(text);
        this.cornerRadius = 12;
      }
      public void paintComponent(Graphics g) {
        Graphics2D gg = (Graphics2D) g;
        int w = this.getWidth(); int h = this.getHeight();
        int r = this.cornerRadius;
        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                            RenderingHints.VALUE_ANTIALIAS_ON);
        Color startColor = this.getBackground().brighter().brighter();
        Color endColor = this.getBackground().darker().darker();
        GradientPaint gp = 
          new GradientPaint(0, 0, startColor, 0, h, endColor, true);
        gg.setPaint(gp);
        gg.fill(new RoundRectangle2D.Double(0, 0, w-1, h-1, r, r));
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JLabel l = new RoundCornerLabel("Rounded Corners & Gradient");
            l.setFont(new Font("Georgia", Font.PLAIN, 40));
            l.setBackground(Color.blue.darker());
            JOptionPane.showMessageDialog(null, l);
          }
        });
      }
    }

The example below attempts to decorate a JLabel with fleur-de-lyses painted in the background, but it doesnt calculate the fontmetrics properly. Also the background image is distracting rather than attractive. Could use the FontHelp.getGlyphFonts() method to make sure that a glyph exists.

paint a glyph repeatedly on the background of a jlabel

    import javax.swing.*;
    import java.awt.*;
    import java.awt.geom.RoundRectangle2D;
    public class GlyphLabel extends JLabel {
      public GlyphLabel(String text) {
        super(text);
      }
      public void paintComponent(Graphics g) {
        Graphics2D gg = (Graphics2D) g;
        char c = '\u269c';        
        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                            RenderingHints.VALUE_ANTIALIAS_ON);
        gg.setColor(this.getBackground());
        gg.setFont(new Font("FreeSerif", Font.PLAIN, 30));
        for (int ii = 0; ii < this.getWidth(); ii=ii+20) {
          gg.drawString("" + c, ii, 40);
        }
        super.paintComponent(g);
      }
      public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            JLabel l = new GlyphLabel("A fleur-de-lys background");
            l.setBackground(Color.lightGray);
            l.setFont(new Font("Georgia", Font.PLAIN, 60));
            JOptionPane.showMessageDialog(null, l);
          }
        });
      }
    }

Gotchas For Jlabels ‹↑›

If you add an empty (with no text) JLabel to a BorderLayout.NORTH then you cant see the JLabel at all (at least until you set its text to something)

Jtextcomponents ‹↑›

Text components are those components which allow the editing of text, including JTextField, JTextArea, JEditorPane .... These components can be divided into 2 categories: Those which allow the text to be 'styled' (have a variety of fonts, colours etc) and those which dont. The 'styled' components are considerably more complex.

http://stackoverflow.com/questions/6913983/jtextpane-removing-first-line remove first line of a document, using elements

www: http://es.scribd.com/doc/89923641/31/JTextComponent-features
very good summary of JTextComponent features.
.createPosition in a text component is like creating a bookmark. The bookmark doesnt change even when its offset from the start of the document changes

useful methods
setStringPainted(true); - display text in the bar indicated % done
setValue(49); - set the value to 49
setString("finished") - sets the string displayed in the bar
setIndeterminate(true) - displays progress without values

Modeltoview ‹↑›

The method modelToView is important for obtaining the pixel position (actually a java.awt.Rectangle) within a JTextComponent of a particular index in a document. Note that this pixel position is relative to the JTextComponent and not to any scrollpane/viewport nor to the panel.

The method textcomponent.modelToView(int) returns a one pixel wide rectangle with the height of the current line height (determined by the size of the font). For example for a 22 point/pixel Font the line height (and the height of the rectangle will be 28 pixels). This height is the same as the default vertical scroll increment for a JVerticalScrollBar.

The top of the rectangle is positioned at the top of the line corresponding to the document index, between characters. See ScrollBarTest to experiment with caret positions and modelToView co-ordinates.

Documents ‹↑›

All of the swing components which allow the editing of text (descendants of JTextComponent) have an associated Document which is javax.swing.text.Document. The document can have a structure which is represented by a heirarchy (or several heirarchies) of javax.swing.text.Element objects.

If you want to listen to all changes to a document and modify the document depending on some condition you probably need to subclass the Document and override the insertString() method. See below for an example of this.

add a property to the document for a JTextComponent

 tc.getDocument().putProperty("filename", "index.txt");

These properties can be used for any purpose that occurs to the programmer.

useful methods for JTextComponent
modelToView() - convert document offsets (characters) into pixels
viewToModel() - convert pixel location to document offset

an efficient scan of a large document using getText(int, int, segment)

   int nleft = doc.getDocumentLength();
   Segment text = new Segment();
   int offs = 0;
   text.setPartialReturn(true);
   while (nleft > 0) {
     doc.getText(offs, nleft, text);
     nleft -= text.count;
     offs += text.count;
   }

The code above is considered efficient because it doesnt involve copying the text from the document. The text is made accessible in the javax.swing.text.Segment object. The partialReturn(true) ensures that the text is not copied.

remove something from the end of a JTextArea

    PlainDocument doc = (PlainDocument) textArea.getDocument();
    doc.remove(doc.getLength() - 1, 1);

remove 4 characters near the text component caret position

   PlainDocument doc = (PlainDocument) area.getDocument();
   try { doc.remove(area.getCaretPosition() - 4, 4); }
   catch (BadLocationException ex) { ex.printStackTrace(); }

2 text fields with the same document

make typing '>' in a textcomponent do something special

   JFrame f = new JFrame();
   StyledDocument d = new DefaultStyledDocument() {
     @Override
     public void insertString(int offs, String str, AttributeSet a) 
       throws BadLocationException {
       if (">".equals(str)) {
         // Do some action
         System.out.println("Run action corresponding to '" + str + "'");
       } else {
         super.insertString(offs, str, a);
       }
     }
   };
   JTextPane t = new JTextPane(d);
   f.add(t);

Selections In Jtextcomponents ‹↑›

All JTextComponent can have a part of the text 'selected' (which is different from 'highlighted'). Selected text is painted in a different colour and is replaced as soon as the user types something. Which is handy. Selections are actually maintained in the Caret class but convenience methods are available to all JComponents

useful methods of the Document class
getLength() - the number of characters in the document
getText(03) - get the 1st three letters of the document
createPosition(3) - create a 'bookmark' just after the 3rd character
insertString(2 "hi", null) - insert 'hi' after 2nd char, no attribs
remove(5 2) - delete 2 characters just after the 5th character

make all the text in a JTextField selected

    textfield.setSelectionStart(0);
    textfield.setSelectionEnd(this.field.getText().length());

Positions In The Document ‹↑›

In the swing Document interface, Positions occur *between* characters. For example, position 3 is just after the 3rd character and just before the 4th. etc.

Document Structure ‹↑›

The Document associated with a swing text component may have a heirarchical structure. For example, a set of paragraphs will make up a chapter, which in turn will form a book. The Document provides a mechanism to specify this structure through the Element interface. Each Element object represents one node of this structure (one chapter, one paragraph etc), and attributes associated with the Element specify which type of node.

In practice it seems uncommon to implement custom Document structures. If the programmer implements a new document structure she must listen to document changes (insert, remove) with a DocumentListener and use the documentEvent.getChange(Element elem) to update the structure when text is inserted or removed. This may be tricky.

We can traverse the Document structure by calling methods of the Element interface.

www: http://java.sun.com/products/jfc/tsc/articles/text/element_interface/
An article about the Element interface and document structures
Idea: create a JTree component with a Document structure, each node on the tree an Element.

selection methods
setSelectionStart(int)
setSelectionEnd(int)

In theory the Document can have several parallel structures which are retrieved with getRootElements().

The AttributeSet obtainable from an Element with getAttributes() is often used for markup attributes (color, font etc)

Plaindocument ‹↑›

JTextComponents which do not display styled text use a PlainDocument as their model. This Document has a very simple document structure: a root element, and a set of child Elements which represent lines in the document.

When a newline character '\n' is inserted into a PlainDocument the document needs to update its structure. A new child element (line) is created and the position offsets for the existing child Elements are updated. This is done through a DocumentListener

Defaultstyleddocument ‹↑›

The DefaultStyledDocument represents text of which regions have certain styles associated with them (for example, italic, green etc) The Document structure has 3 levels: root, paragraph, style. The single root contains a set of paragraphs which in turn contain a set of styled regions (called 'styles').

http://www.exampledepot.com/egs/javax.swing.text/tp_StyledText.html a good simple example of inserting styled text

http://stackoverflow.com/questions/10193550/appending-richtext-to-jtextpane-using-styleddocument-insertstring-doesnt-preser inserting rich text in a jtextpane

http://www.exampledepot.com/egs/javax.swing.text/ListTextKeys.html words of wisdom about keybindings and keymaps, read carefully

more attribute magic for textcomponents

  You can get EditorKit from your JEditorPane. It's StyledEditorKit instance. So you can get InputAtributes from the kit and remove all the attributes. Thus all the typing will use the empty AttributeSet.
  stanislav

  The code below is a skeleton for inserting styled text in a styled
  document for example with a JTextPane. The insertString method takes a
  position param a string and a set of attributes

  * create some attributes to style text in a Styled document, then insert at end of doc
   StyledDocument doc = textPane.getStyledDocument();
   // do we have to cast to AbstractDocument?? 
   // they do in java tutorial but why
   attrs[0] = new SimpleAttributeSet();
   StyleConstants.setFontFamily(attrs[0], "SansSerif");
   StyleConstants.setFontSize(attrs[0], 16);
   doc.insertString(doc.getLength(), "hello styles",
                    attrs[0]);

add lots of style actions to a menu (works for a component with styled doc)

   protected JMenu createStyleMenu() {
     JMenu menu = new JMenu("Style");
   
     Action action = new StyledEditorKit.BoldAction();
     action.putValue(Action.NAME, "Bold");
     menu.add(action);
     action = new StyledEditorKit.ItalicAction();
     action.putValue(Action.NAME, "Italic");
     menu.add(action);
   
     action = new StyledEditorKit.UnderlineAction();
     action.putValue(Action.NAME, "Underline");
     menu.add(action);
     menu.addSeparator();
   
     menu.add(new StyledEditorKit.FontSizeAction("12", 12));
     menu.add(new StyledEditorKit.FontSizeAction("14", 14));
     menu.add(new StyledEditorKit.FontSizeAction("18", 18));
   
     menu.addSeparator();
     menu.add(new StyledEditorKit.FontFamilyAction("Serif",
              "Serif"));
     menu.add(new StyledEditorKit.FontFamilyAction("SansSerif",
              "SansSerif"));
   
     menu.addSeparator();
     menu.add(new StyledEditorKit.ForegroundAction("Red", Color.red));
     menu.add(new StyledEditorKit.ForegroundAction("Green", Color.green));
     menu.add(new StyledEditorKit.ForegroundAction("Blue", Color.blue));
     menu.add(new StyledEditorKit.ForegroundAction("Black", Color.black));
     return menu;
   }

http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java an example implementation of undo redo on a text component. Also controlkey bindings and also installing a document filter on a document.

Documentfilters ‹↑›

DocumentFilters allow the programmer to specify what kind of text or how much text can be entered in a JTextComponent.

a complete example of a document filter which only allows numbers

   import javax.swing.*;
   import javax.swing.text.*;
   import java.util.regex.*;
   public class NumberOnlyFilter extends DocumentFilter {
     public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
       StringBuilder sb = new StringBuilder();
       sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
       sb.insert(offset, text);
       if (!containsOnlyNumbers(sb.toString())) return;
       fb.insertString(offset, text, attr);
     }
     public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attr) throws BadLocationException {
       StringBuilder sb = new StringBuilder();
       sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
       sb.replace(offset, offset + length, text);
       if (!containsOnlyNumbers(sb.toString())) return;
       fb.replace(offset, length, text, attr);
     }
     public boolean containsOnlyNumbers(String text) {
       Pattern pattern = Pattern.compile("[\\d]");
       Matcher matcher = pattern.matcher(text);
       boolean isMatch = matcher.matches();
       return isMatch;
     }
   }
   // use this with
   // ((AbstractDocument)jtextfield.getDocument()).setDocumentFilter(new NumberOnlyFilter());

Documentlisteners ‹↑›

A DocumentListener allows us to react to changes to the text in a JTextComponent. The DocumentListener is registered with the Document associated with the JTextComponent. The Document fires javax.swing.event.DocumentEvents

UndoableEditEvents are used for undoing changes.

add a subclass of DocumentListener to the Document of a text component

 tc.getDocument().addDocumentListener(new DocListener());

document structure methods
getDefaultRootElement() - the root (top-level) Element (eg: Book)
getRootElements() - get all roots (if the doc has several structures)

However the changedUpdate() method in practice is not implemented for JTextComponent with a PlainDocument model (for example, JTextField, or JTextArea components but only for text components with a StyledDocument model such as JEditorPane

retrieve the Document from the event

   public void insertUpdate(DocumentEvent e) {
     Document doc = (Document)e.getDocument();
   }

retrieve the length of the change and the document offset of the event

   public void insertUpdate(DocumentEvent e) {
     Document doc = (Document)e.getDocument();
     int changeLength = e.getLength();
     int offset = e.getOffset();
   }

determine the type of change to the document (insert, remove, change)

   public void insertUpdate(DocumentEvent e) {
     String type = e.getType().toString();
   }

The above code will always return 'insert' because it is called in the insertUpdate() method.

The DocumentEvent.toString() method doesnt produce anything particularly readable.

display info about DocumentEvents fired by a JTextField -------- import javax.swing.*; import javax.swing.event.*; import java.awt.*; public class ListenPanel extends JPanel implements DocumentListener { JTextField field; JTextArea area; public ListenPanel() { super(new BorderLayout()); this.field = new JTextField(60); this.field.getDocument().addDocumentListener(this); this.field.setFont(new Font("Georgia", Font.PLAIN, 18)); this.area = new JTextArea("Action", 60, 10); this.area.setFont(new Font("Georgia", Font.PLAIN, 18)); this.add(field, BorderLayout.NORTH); this.add(area, BorderLayout.CENTER); }

private String eventInfo(DocumentEvent e) { return String.format( "Action type: %s, Doc Offset: %d, Change Length: %d \n", e.getType().toString(), e.getOffset(), e.getLength()); }

public void insertUpdate(DocumentEvent e) { this.area.append(this.eventInfo(e)); } public void removeUpdate(DocumentEvent e) { this.area.append(this.eventInfo(e)); } public void changedUpdate(DocumentEvent e) { //JTextFields dont fire these events }

public static void main(String[] args) throws Exception { ListenPanel p = new ListenPanel(); JOptionPane.showMessageDialog(null, p); } } ,,,

Document Gotchas ‹↑›

Notes: On a Linux computer, when you select text with the mouse all the way to the end of the textfield, an exception java.lang.ArrayIndexOutOfBoundsException is sometimes thrown from the Caret moving code. This seems like some kind of bug in the swing caret painting or selection code.

If you select text in a JTextComponent with the mouse or caret, and then type one letter, all the selected text will be replaced with the one letter, and 2 events will be fired rapidly in succession, one 'remove' event with length of the selected text, and one 'insert' event with length 1. This is logical but your code needs to handle both events.

Carets ‹↑›

The caret is the usually vertical blinking line or box which indicates the 'insertion point' in a text component. The insertion point is the position in the document where text will be inserted when the user types something or performs a 'paste' operation. The caret is often also called a 'cursor' but in Java this word is reserved for the mouse position indicator.

If you change the background colour for a text component, you may also need to change the caret colour so that it can be seen.

DocumentListener interface methods
public void insertUpdate(DocumentEvent e) {}
public void removeUpdate(DocumentEvent e) {}
public void changedUpdate(DocumentEvent e) {}

make sure the caret is visible

    textArea.getCaret().setVisible(true); /* or */
    textArea.getCaret().setSelectionVisible(true);

The code below can be useful for stopping a JTextArea from automatically scrolling to the end of the document when text is appended.

stop the caret position from being updated on insertion deletion etc

    JTextArea textArea = new JTextArea();
    DefaultCaret caret = (DefaultCaret)textArea.getCaret();
    caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);

http://tips4java.wordpress.com/2008/10/22/text-area-scrolling/ about caret and scrolling and text area

Caretlisteners And Caretevents ‹↑›

We can add a CaretListener to a text component in order to be notified whenever the caret changes position or state. The listener fires a CaretEvent

useful caret methods
tf.setCaretPosition(0) - set the caret to the beginning of a textfield

create an inner class CaretListener and add it to a JTextArea

   CaretListener listener = new CaretListener() {
     public void caretUpdate(CaretEvent caretEvent) {
       System.out.println("Dot:" + caretEvent.getDot());
       System.out.println("Mark:" + caretEvent.getMark());
     }
   };
   jtextarea.addCaretListener(listener);

Highlighters ‹↑›

Highlighters are used in java text components to highlight some piece of text. For example when the user searches for some text in a JTextArea, the matched text may be highlighted by the application. Also the user may be able to manually select text with the mouse, and this text is also highlighted

code adapted from http://tips4java.wordpress.com/2008/10/28/rectangle-painter/

The second parameter to addHighlight() is an integer which is Not a length but a character position in the document, somewhat surprisingly.

highlight from position 3 to position 6

    this.area.getHighlighter().addHighlight(3, 6, 
      new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));

add a highlight from position 3 to 6 in a textarea

    import javax.swing.text.*;
    import javax.swing.*;
    import java.awt.*;
    public class HighlightPanel extends JPanel {
      JTextArea area;
      public HighlightPanel() {
        super(new BorderLayout());
        this.area = new JTextArea(
          "Testing Highlights\nAnd and character\nPositions", 20, 70);
        this.area.setFont(new Font("Georgia", Font.ITALIC, 24));
        this.add(this.area);
        this.highlight();
      }
      public void highlight() {
        try {
          this.area.getHighlighter().addHighlight(3, 6, 
            new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
        }
        catch (BadLocationException e) {
          this.area.setText("Invalid Location:\n" + e);
        }
      }
      public static void main(String[] args) {
        System.setProperty("awt.useSystemAAFontSettings","on");
        JFrame f = new JFrame();
        f.add(new HighlightPanel());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);  
        f.setVisible(true);
      }
    }

Changing Existing Highlights ‹↑›

It does not seem possible to just paint a new highlight on top of any old one- you need to actually change or remove the existing highlight.

change a highlight for a highlighter

    Highlighter.Highlight myHighlight = null;
    Highlighter.Highlight[] highlights = 
      textPane.getHighlighter().getHighlights();
    myHighlight = highlights[0]; //assuming there is one only
    try {
      hl.changeHighlight(myHighlight, myHighlight.getStartOffset() + 1, 
        myHighlight.getEndOffset());
    }
    catch (BadLocationException e) { e.printStackTrace(); }

move a highlight right when the user presses 'm'

   import javax.swing.text.*;
   import javax.swing.*;
   import java.awt.*;
   import java.awt.event.*;
   public class MoveHighlight extends JPanel implements KeyListener {
     JTextArea area;
     public MoveHighlight() {
       super(new BorderLayout());
       this.area = new JTextArea(
         "Testing Highlights\nAnd and character\nPositions", 20, 70);
       this.area.setFont(new Font("Georgia", Font.ITALIC, 24));
       this.area.setEditable(false);
       this.add(this.area);
       this.highlight();
       this.area.addKeyListener(this);
     }
     public void keyTyped(KeyEvent e) {
       char key = e.getKeyChar();
       switch (key) {
         case 'm': this.moveHighlight(); break;
         default: break;
       }
     }
     public void keyPressed(KeyEvent e) {}
     public void keyReleased(KeyEvent e) {}
     public void moveHighlight() {
       Highlighter hl = this.area.getHighlighter();
       Highlighter.Highlight first = hl.getHighlights()[0];
       try {
         hl.changeHighlight(
           first, first.getStartOffset() + 1, first.getEndOffset() + 1);
       }
       catch (BadLocationException e) { e.printStackTrace(); }
     }
   
     public void highlight() {
       try {
         this.area.getHighlighter().addHighlight(3, 6,
            new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
       }
       catch (BadLocationException e) {
         this.area.setText("Invalid Location:\n" + e);
       }
     }
     public static void main(String[] args) {
       System.setProperty("awt.useSystemAAFontSettings","on");
       JFrame f = new JFrame();
       f.add(new MoveHighlight());
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack();
       f.setLocationRelativeTo(null);
       f.setVisible(true);
     }
   }

Custom Highlighters ‹↑›

add some highlights to a JTextArea using a custom highlight painter

    RectanglePainter red = new RectanglePainter( Color.RED );
    RectanglePainter cyan = new RectanglePainter( Color.CYAN );
    textArea.getHighlighter().addHighlight(5, 9, red);
    textArea.getHighlighter().addHighlight(61, 69, cyan);
    textArea.getHighlighter().addHighlight(106, 110, red);

The example below is a simple modification of the DefaultHighlighter.DefaultHighLightPainter java swing code. This shows the value of looking at the java source code. We use Graphic2D object instead of normal graphics, with antialiasing and a rounded corner highlight

The Code is the same as the DefaultHighlightPainter except we use Graphics2D and a RoundRectangle2D to paint the highlight

make a custom text highlighter (can be used with any text component)

   import java.awt.*;
   import java.awt.geom.*;
   import javax.swing.text.*;
   import javax.swing.*;
   public class RectanglePainter extends DefaultHighlighter.DefaultHighlightPainter
   {
     public RectanglePainter(Color color) { super(color); }
     /**
      * Paints a portion of a highlight.
      *
      * @param  g the graphics context
      * @param  offs0 the starting model offset >= 0
      * @param  offs1 the ending model offset >= offs1
      * @param  bounds the bounding box of the view, which is not
      *	       necessarily the region to paint.
      * @param  c the editor
      * @param  view View painting for
      * @return region drawing occured in
      */
     public Shape paintLayer(Graphics gg, int offs0, int offs1, Shape bounds, JTextComponent c, View view)
     {
       Graphics2D g = (Graphics2D) gg;
       g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                          RenderingHints.VALUE_ANTIALIAS_ON);
       Rectangle r = getDrawingArea(offs0, offs1, bounds, view);
       if (r == null) return null;
       //  Do your custom painting
       Color color = getColor();
       g.setColor(color == null ? c.getSelectionColor() : color);
       //g.fillRect(r.x, r.y, r.width, r.height);
       //g.drawRect(r.x, r.y, r.width - 1, r.height - 1);
       g.draw(new RoundRectangle2D.Double(r.x, r.y, r.width, r.height, 10, 10));
       return r;
     }
   
     private Rectangle getDrawingArea(int offs0, int offs1, Shape bounds, View view) {
       // Contained in view, can just use bounds.
       if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
         Rectangle alloc;
   
         if (bounds instanceof Rectangle)
          { alloc = (Rectangle)bounds; }
         else
          { alloc = bounds.getBounds(); }
         return alloc;
       }
       else {
         // Should only render part of View.
         try {
           // --- determine locations ---
           Shape shape = view.modelToView(offs0, Position.Bias.Forward, offs1,Position.Bias.Backward, bounds);
           Rectangle r = (shape instanceof Rectangle) ? (Rectangle)shape : shape.getBounds();
           return r;
         }
         catch (BadLocationException e) { }
       }
       // Can't render
       return null;
     }

     public static void main(String[] args) throws Exception {
        JTextArea textArea = new JTextArea(
          "Testing a custom highlighter with RoundRectangle2D", 30, 5);
        textArea.setFont(new Font("Georgia", Font.PLAIN, 30));
        RectanglePainter red = new RectanglePainter( Color.RED );
        RectanglePainter cyan = new RectanglePainter( Color.CYAN );
        textArea.getHighlighter().addHighlight(5, 9, red);
        textArea.getHighlighter().addHighlight(11, 14, cyan);
        JOptionPane.showMessageDialog(null, textArea);
     }
   }

A cyclic GradientPaint is used below which is probably not ideal but at least it stops the lines > 1 being solid colour (as opposed to a gradient colour).

The code makes the caret use the same HighlightPainter. I dont really understand the code that gets the area to paint, mainly because I dont know what the 'view' is in this context.

custom text highlighter using a gradient paint and same caret painter

   import java.awt.*;
   import java.awt.geom.*;
   import javax.swing.text.*;
   import javax.swing.*;
   public class GradientHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter
   {
     public GradientHighlightPainter(Color color) { 
       super(color); 
     }

     /**
      * Paints a portion of a highlight.
      *
      * @param  g the graphics context
      * @param  offs0 the starting model offset >= 0
      * @param  offs1 the ending model offset >= offs1
      * @param  bounds the bounding box of the view, which is not
      *	        necessarily the region to paint.
      * @param  c the editor
      * @param  view View painting for
      * @return region drawing occured in
      */

     public Shape paintLayer(Graphics gg, int offs0, int offs1, Shape bounds, JTextComponent c, View view) {
       Graphics2D g = (Graphics2D) gg;
       g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                          RenderingHints.VALUE_ANTIALIAS_ON);
       Rectangle r = getDrawingArea(offs0, offs1, bounds, view);
       if (r == null) return null;
       Color color = getColor();
       color = (color == null ? c.getSelectionColor() : color);
       GradientPaint gp = new GradientPaint(0, 0,
             color.brighter().brighter(), 0, r.height,
             color.darker().darker(), true);
       g.setPaint(gp);
       g.fill(new RoundRectangle2D.Double(r.x, r.y, r.width, r.height, 10, 10));
       return r;
     }
   
     private Rectangle getDrawingArea(int offs0, int offs1, Shape bounds, View view) {
       // Contained in view, just use bounds.
       if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
         Rectangle alloc;
         if (bounds instanceof Rectangle)
          { alloc = (Rectangle)bounds; }
         else
          { alloc = bounds.getBounds(); }
         return alloc;
       }
       else {
         // only render part of View.
         try {
           Shape shape = view.modelToView(
             offs0, Position.Bias.Forward, 
             offs1, Position.Bias.Backward, bounds);
           Rectangle r = 
              (shape instanceof Rectangle) ? 
              (Rectangle)shape : shape.getBounds();
           return r;
         }
         catch (BadLocationException e) { }
       }
       // Can't render
       return null;
     }

     public static void main(String[] args) throws Exception {
        JTextArea textArea = new JTextArea(
          "Testing custom text highlighters \n" +
          "We can use gradient paints rounded corners and \n" +
          "Any thing else that java2D allows us to use", 30, 5);
        textArea.setFont(new Font("Georgia", Font.PLAIN, 30));
        GradientHighlightPainter red = 
          new GradientHighlightPainter(Color.RED);
        GradientHighlightPainter cyan = 
          new GradientHighlightPainter(Color.CYAN);
        textArea.getHighlighter().addHighlight(1, 4, red);
        textArea.getHighlighter().addHighlight(11, 16, cyan);
        textArea.getHighlighter().addHighlight(30, 37, cyan);
        Caret caretPainter = new DefaultCaret() {
         private Highlighter.HighlightPainter rp = 
            new GradientHighlightPainter(Color.CYAN);
         protected Highlighter.HighlightPainter getSelectionPainter() {
           return rp;
         }
        };
        textArea.setCaret(caretPainter);
        //area.setLineWrap(true);
        //area.setWrapStyleWord(true);
        JOptionPane.showMessageDialog(null, textArea);
     }
   }

make the caret use the custom highlighter

   JTextArea area = new JTextArea("hello")
   Caret caretPainter = new DefaultCaret() {
     private Highlighter.HighlightPainter lhp = new LineHighlightPainter();
     protected Highlighter.HighlightPainter getSelectionPainter() {
       return lhp;
     }
   };
   area.setCaret(caretPainter);

implement a custom highlighter by implementing the interface

   import javax.swing.*;
   import javax.swing.text.*;
   import java.awt.*;
   public class LineHighlightPainter implements Highlighter.HighlightPainter {
     // paint a thick line under one line of text, from r extending rightward to x2
     private void paintLine(Graphics g, Rectangle r, int x2) {
       int ytop = r.y + r.height - 3;
       g.fillRect(r.x, ytop, x2 - r.x, 3);
     }
   
     // paint thick lines under a block of text
     public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) {
       Rectangle r0 = null, r1 = null, rbounds = bounds.getBounds();
       int xmax = rbounds.x + rbounds.width; // x coordinate of right edge
       try {  // convert positions to pixel coordinates
         r0 = c.modelToView(p0);
         r1 = c.modelToView(p1);
       } catch (BadLocationException ex) {
         return;
       }
       if ((r0 == null) || (r1 == null)) return;
   
       g.setColor( c.getSelectionColor() );
       // special case if p0 and p1 are on the same line
       if (r0.y == r1.y) {
         paintLine(g, r0, r1.x);
         return;
       }
   
       // first line, from p1 to end-of-line
       paintLine(g, r0, xmax);
   
       // all the full lines in between, if any (assumes that all lines have
       // the same height--not a good assumption with JEditorPane/JTextPane)
       r0.y += r0.height; // move r0 to next line
       r0.x = rbounds.x; // move r0 to left edge
       while (r0.y < r1.y) {
         paintLine(g, r0, xmax);
         r0.y += r0.height; // move r0 to next line
       }
   
       // last line, from beginning-of-line to p1
       paintLine(g, r0, r1.x);
     }

Gotchas For Highlights ‹↑›

If the highlight includes the newline character "\n" in the text component (that is, it spans more than one line) your highlight will appear one character shorter than you expected.

You can paint a new highlight on top of an old one: you need to remove or change the existing highlight.

Styled Text ‹↑›

Attributedstring ‹↑›

The class java.text.AttributedString provides a way of specifying styles to apply to all or part of a string. It uses the java.awt.font.TextAttribute class to specify the attributes to apply.

create a new attributed string, but without any attributes

 AttributedString as = new AttributedString("Text which can be styled");

create some styled text, make characters 3 to 9 bold and blue

   AttributedString as = new AttributedString("Text which can be styled");
   as.addAttribute(
     TextAttribute.FONT, new Font("Courier New", Font.BOLD, 12), 3, 9);
   as.addAttribute(
     TextAttribute.FOREGROUND, Color.BLUE, 3, 9);

draw an styled string with graphics2D object

 g2d.drawString(ss.getIterator(), 30, 30);

An iterator is used to draw the styled text because the actual storage class of the text is not known, and can be changed by the programmer.

Without antialiasing, the text displayed below is very jaggedy. With antialiasing it is much, much nicer.

a full example

   import javax.swing.*;
   import java.awt.*;
   import java.text.AttributedString;
   import java.awt.font.TextAttribute;
   import java.util.*;
   public class TextStylePanel extends JPanel {
     public TextStylePanel() { super(); }
     @Override
     public void paintComponent(Graphics gg) {
       Graphics2D g = (Graphics2D) gg;
       super.paintComponent(g);
       g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                          RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
       Font font = new Font("Georgia", Font.PLAIN, 60);
       g.setFont(font);
       String text = "Not Antialiased Text";
       AttributedString as = new AttributedString("Text which can be styled");
       as.addAttribute(
         TextAttribute.FONT, new Font("Georgia", Font.BOLD, 60), 3, 12);
       as.addAttribute(
         TextAttribute.FOREGROUND, Color.BLUE, 3, 12);
       g.drawString(as.getIterator(), 50, 50);
     }
     public Dimension getPreferredSize() {
       return new Dimension(500, 300);
     }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new TextStylePanel());
     }
   }

Textattributes ‹↑›

Text attributes are way to apply different styles (or Attributes) to some text. Specifically we can use the java.awt.font.TextAttribute class. Text attributes are stored in pairs of keys and values, in a java.util.Map collection and can be applied to an existing Font with font.deriveFont(map). The TextAttribute class contains a large number of predefined attribute keys and values. For example there are 7 different underline styles supported by the TextAttribute class.

www: http://docs.oracle.com/javase/tutorial/2d/text/textattributes.html
The java tutorial about text attributes
the 2 CaretEvent methods
getDot() - fetches the location of the caret.
getMark() - fetches the location of other end of a logical selection

The example below produces some very unpleasant, un-antialiased text.

display text with kerning, underline and strikethrough

   import javax.swing.*;
   import java.awt.*;
   import java.awt.font.TextAttribute;
   import java.util.*;
   public class TextStylePanel extends JPanel {
     public TextStylePanel() {
       super();
     }
     @Override
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Font font = new Font(Font.SERIF, Font.PLAIN, 24);
       String text = "Not Antialiased Text";
       Hashtable<TextAttribute, Object> map =
         new Hashtable<TextAttribute, Object>();
       map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
       map.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
       map.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
       font = font.deriveFont(map);
       g.setFont(font);
       g.drawString(text, 50, 50);
     }
     public Dimension getPreferredSize() { return new Dimension(500, 300); }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new TextStylePanel());
     }
   }

create a Map of text attributes and apply it to a font

   import javax.swing.*;
   import java.awt.*;
   import java.awt.font.*;
   import java.util.*;
   public class TextStylePanel extends JPanel {
     public TextStylePanel() {
       super();
     }
     @Override
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Map<TextAttribute, Object> map =
         new Hashtable<TextAttribute, Object>();
       map.put(TextAttribute.KERNING,
               TextAttribute.KERNING_ON);
       Font font = new Font("Georgia", Font.PLAIN, 18);
       font = font.deriveFont(map);
       g.setFont(font);
       g.drawString("BLAH", 20, 20);
       g.drawRect(200, 200, 200, 200);
     }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new TextStylePanel());
     }
   }

Jtextfield Text Box ‹↑›

A JTextField is a one line box in which the user can type and edit some text. The JTextField is a JTextComponent and has a Document model just like all JTextComponents. All of the text in the box has to have the same font, but you can highlight a portion of the text.

www: http://javagraphics.blogspot.com/2009/12/text-prompts-and-search-fields.html
making a round corner bog with an icon and grey text
examples of text attributes
underline - a line that is drawn underneath text
strikethrough - a horizontal line that is drawn through the text
superscript or subscript - a text or a letter that appears above or below a line
kerning – makes the spacing between characters more natural

display a JTextField in a message dialog box

   import javax.swing.*;
   public class TextBox {
     public static void main(String[] args)
     {
        JOptionPane.showMessageDialog(null, new JTextField("hello"));
     }
   }

right justify the text 'hello' in a JTextField

   import javax.swing.*;
   public class TextBox {
     public static void main(String[] args)
     {
        JTextField t = new JTextField("hello");
        t.setHorizontalAlignment(JTextField.RIGHT);
        JOptionPane.showMessageDialog(null, t);
     }
   }

right justify the text 'hello' in a JTextField

   import javax.swing.*;
   public class TextBox {
     public static void main(String[] args)
     {
        JFrame f = new JFrame();
        JTextField t = new JTextField("hello");
        t.setHorizontalAlignment(JTextField.RIGHT);
        f.getContentPane().add(t);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);  
        f.setVisible(true);
     }
   }

create a text field with 30 columns which does something when [enter] is pressed.

     JTextField textfield = new JTextField ("Initial Text", 30);
     textfield.addActionListener (new MyActionListener ());
     class MyActionListener implements ActionListener
     {
       public void actionPerformed(ActionEvent e)
       {
         JTextField textfield = (JTextField) e.getSource ();
         process (textfield.getText ());
       }
     }

right justify the text in the JTextField

 textfield.setHorizontalAlignment(JTextField.RIGHT);

The example below adapted from the java tutorial for JTextFields

a text field with searching, and highlighting

   import java.awt.Color;
   import java.awt.event.ActionEvent;
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.InputStreamReader;
   import javax.swing.*;
   import javax.swing.text.*;
   import javax.swing.event.*;
   import javax.swing.GroupLayout.*;
   
   public class TextFieldDemo extends JFrame
         implements DocumentListener {
   
     private JTextField entry;
     private JLabel jLabel1;
     private JScrollPane jScrollPane1;
     private JLabel status;
     private JTextArea textArea;
   
     final static Color  HILIT_COLOR = Color.LIGHT_GRAY;
     final static Color  ERROR_COLOR = Color.PINK;
     final static String CANCEL_ACTION = "cancel-search";
   
     final Color entryBg;
     final Highlighter hilit;
     final Highlighter.HighlightPainter painter;
   
     public TextFieldDemo() {
       initComponents();
       InputStream in = getClass().getResourceAsStream("content.txt");
       try {
         textArea.read(new InputStreamReader(in), null);
       } catch (IOException e) {
         e.printStackTrace();
       }
   
       hilit = new DefaultHighlighter();
       painter = new DefaultHighlighter.DefaultHighlightPainter(HILIT_COLOR);
       textArea.setHighlighter(hilit);
       entryBg = entry.getBackground();
       entry.getDocument().addDocumentListener(this);
       InputMap im = entry.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
       ActionMap am = entry.getActionMap();
       im.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel-search");
       am.put("cancel-search", new CancelAction());
     }
   
     private void initComponents() {
       entry = new JTextField();
       textArea = new JTextArea();
       status = new JLabel();
       jLabel1 = new JLabel();
   
       setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
       setTitle("TextFieldDemo");
       textArea.setColumns(20);
       textArea.setRows(5);
       textArea.setLineWrap(true);
       textArea.setWrapStyleWord(true);
       textArea.setEditable(false);
       jScrollPane1 = new JScrollPane(textArea);
       jLabel1.setText("Enter text to search:");
       getContentPane().setLayout(layout);
       pack(); 
     }
   
     public void search() {
       hilit.removeAllHighlights();
       String s = entry.getText();
       if (s.length() <= 0) {
         message("Nothing to search");
         return;
       }
   
       String content = textArea.getText();
       int index = content.indexOf(s, 0);
       if (index >= 0) {   // match found
         try {
           int end = index + s.length();
           hilit.addHighlight(index, end, painter);
           textArea.setCaretPosition(end);
           entry.setBackground(entryBg);
           message("'" + s + "' found. Press ESC to end search");
         } catch (BadLocationException e) {
           e.printStackTrace();
         }
       } else {
         entry.setBackground(ERROR_COLOR);
         message("'" + s + "' not found. Press ESC to start a new search");
       }
     }
   
     void message(String msg) { status.setText(msg); }
     public void insertUpdate(DocumentEvent ev) { search(); }
     public void removeUpdate(DocumentEvent ev) { search(); }
     public void changedUpdate(DocumentEvent ev) { }

     class CancelAction extends AbstractAction {
       public void actionPerformed(ActionEvent ev) {
         hilit.removeAllHighlights();
         entry.setText("");
         entry.setBackground(entryBg);
       }
     }
   
     public static void main(String args[]) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           //Turn off metal's use of bold fonts
           UIManager.put("swing.boldMetal", Boolean.FALSE);
           new TextFieldDemo().setVisible(true);
         }
       });
     }
   }

Documentmodel For Jtextfield ‹↑›

The following example, taken from the java api docs for JTextField demonstrates how to override the insertString method for a JTextComponent to add new functionality. This is simple and elegant. One cannot change a Document model from within a DocumentListener so the method below is very useful.

something wrong with ,jc below

extend the PlainDocument model to only allow upper case letters

import javax.swing.*;  public class UpperCaseField extends JTextField {   public UpperCaseField(int cols) {   super(cols);   }   protected Document createDefaultModel() {   return new UpperCaseDocument();   }   static class UpperCaseDocument extends PlainDocument {   public void insertString(int offs, String str, AttributeSet a)   throws BadLocationException {

useful JTextField methods
setHorizontalAlignment(JTextField.CENTER) - center align text
  char[] upper = str.toCharArray();   for (int i = 0; i < upper.length; i++) {   upper[i] = Character.toUpperCase(upper[i]);   }   super.insertString(offs, new String(upper), a);   }   }  }

,,,

Jformattedtextfield ‹↑›

The JFormattedTextField is a one line text editing box which prevents the user from entering certain values. An alternative is to use a javax.swing.text.DocumentFilter on the underlying Document for the JTextField

Password Boxes ‹↑›

A password box, or field is a field with one line of text which does not display the text which is typed.

a simple password box

   import javax.swing.*;
   public class Text {
     public static void main(String[] args)
     {
        JFrame f = new JFrame();
        JPasswordField t = new JPasswordField("hello");
        f.getContentPane().add(t);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);  
        f.pack();
        f.setVisible(true);
     }
   }

make a password field which listens to the [enter] key

      JPasswordField textfield = new JPasswordField("Initial Text");
      textfield.setEchoChar('#');
      textfield.addActionListener(actionListener);

Jtextareas ‹↑›

A JTextArea is a box with several lines in which text can be entered. The text in a JTextArea is 'plain', that is, all the text is the box is the same font, font style and size. The only styling of text possible is through using a highlighter. For 'rich text' (in which different segments of the text have different styles, such as italic, bold etc) use a JEditorPane or a JTextPane

The JTextArea seems to have good performance even with large documents.

www: http://www.exampledepot.com/egs/javax.swing.text/ta_EnumLines.html
how to get the document, paragraphs and lines from a jtextarea
  if (str == null) { return; }

create a text area with 20 rows and 30 columns

     JTextArea textarea = new JTextArea ("Initial Text");
     textarea = new JTextArea ("Initial Text", 20, 30);

set the background colour of a JTextArea

    JTextArea t = new JTextArea("hi");
    t.setBackground (Color.green);

set the font, forground and background colours of a jtextarea

   import java.awt.*;
   import javax.swing.*;
   public class TextAreaExample {
     public static void main(String[] args) throws Exception {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           final JTextArea ta = new JTextArea("edit", 2, 60);
           Font font = new Font("Courier", Font.PLAIN, 20);
           ta.setFont(font);
           ta.setForeground(Color.green);
           ta.setBackground(Color.black);
           JOptionPane.showMessageDialog(null, ta);
         }
       });
     }
   }

We also need to set the caret (cursor) color to something other (than black, so that we can see it.

Reading Content Into A Jtextarea ‹↑›

The JTextArea has a convenient read() method to load content into the area.

read a webpage encoded as utf8 into a JTextArea

 jtextarea.read(new InputStreamReader(url.openStream(), "UTF-8"), null);

use the read() method to load the text from a file into a JTextArea

    import java.awt.*;
    import javax.swing.*;
    import java.io.*;
    public class TextRead {
      public static void main(String[] args) throws Exception {
        JTextArea ta = new JTextArea("edit", 20, 80);
        ta.setFont(new Font("courier", Font.PLAIN, 20));
        FileInputStream fis = new FileInputStream("java-book.txt"); 
        InputStreamReader in = new InputStreamReader(fis, "UTF-8");
        ta.read(in, null);
        JFrame frame = new JFrame("Reading a File into a JTextArea");
        frame.add(new JScrollPane(ta));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack(); frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    }

use the read() method to load the text from a url into a JTextArea

    import java.awt.*;
    import javax.swing.*;
    import java.io.*;
    import java.net.*;
    public class WebTextArea extends JTextArea {
      URL url;
      public WebTextArea(String sUrl) {
        super(30, 80);
        try {
          this.url = new URL(sUrl);
          this.setFont(new Font("courier", Font.PLAIN, 20));
          this.read(new InputStreamReader(url.openStream()), null);
          this.setEditable(false);
        } catch (IOException e) { e.printStackTrace(); }
      }
      public static void main(String[] args) throws Exception {
        WebTextArea area = 
          new WebTextArea("http://bumble.sf.net/books/vim/vim-book.txt");
        JFrame frame = new JFrame("The WebTextArea");
        frame.add(new JScrollPane(area));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack(); frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    }

Scrolling Jtextareas ‹↑›

To scroll to a particular piece of text in a JTextArea one can just set the caret position to that piece of text. Or you could use the c.scrollRectToVisible(Rectangle r) method but I cant see any reason to do that for a JTextComponent.

set the caret to the end of the textarea (and scroll to the end)

    textArea.append(...);
    textArea.setCaretPosition(textArea.getDocument().getLength());

make a JTextArea always show last appended text (scroll to end) java1.5+

    JTextArea textArea = new JTextArea();
    DefaultCaret caret = (DefaultCaret)textArea.getCaret();
    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

The code below uses the KeyScrollPane class which uses key-bindings to link key-strokes to scrolling actions. The JTextArea must be non-editable for this to work. If the text area is editable then the typed key gets inserted in the document- then the keybinding fires which scrolls the viewport, but then the caret seems to force the JTextArea to scroll back to where-ever the caret happens to be. Interesting.

scrolling a non editable JTextArea using keystrokes

    import java.awt.*;
    import javax.swing.*;
    import java.io.*;
    import java.net.*;
    public class KeyTextArea extends JTextArea {
      URL url;
      public KeyTextArea(String sUrl) {
        super(30, 80);
        try {
          this.url = new URL(sUrl);
          this.setFont(new Font("courier", Font.PLAIN, 20));
          this.read(new InputStreamReader(url.openStream()), null);
          this.setEditable(false);
        } catch (IOException e) { e.printStackTrace(); }
      }
      public static void main(String[] args) throws Exception {
        KeyTextArea area = 
          new KeyTextArea("http://bumble.sf.net/books/vim/vim-book.txt");
        JFrame frame = new JFrame("The WebTextArea");
        frame.add(new KeyScrollPane(area));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack(); frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    }

an example of using scrollRectToVisible()

   import java.awt.BorderLayout;
   import java.awt.Rectangle;
   import javax.swing.*;
   import javax.swing.event.ListSelectionEvent;
   import javax.swing.event.ListSelectionListener;
   import javax.swing.text.BadLocationException;
   public class TestScrollRectToVisible extends JPanel {
     private static final int MAX_LOOP = 10000;
     private DefaultListModel listModel = new DefaultListModel();
     private JTextArea textarea = new JTextArea(20, 30);
     private JList jList = new JList(listModel);
     JScrollPane textareaScrollPane = new JScrollPane(textarea);
     public TestScrollRectToVisible() {
       jList.addListSelectionListener(new ListSelectionListener() {
         public void valueChanged(ListSelectionEvent e) {
           if (!e.getValueIsAdjusting()) {
             String text = jList.getSelectedValue().toString();
             text += ": ";
             String docText = textarea.getText();
             int index = docText.indexOf(text);
             if (index < 0) {
               return;
             }
             try {
               Rectangle rect = textarea.modelToView(index);
               textarea.scrollRectToVisible(rect);
             } catch (BadLocationException e1) {
               e1.printStackTrace();
             }

           }
         }
       });
   
       jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
       StringBuilder strBuilder = new StringBuilder();
       for (int i = 0; i < MAX_LOOP; i++) {
         String text = String.valueOf(i);
        listModel.addElement(text);
         strBuilder.append(text + ": abcdefghijklmnopqrstuvwxyz" + "\n");
       }
       textarea.setText(strBuilder.toString());
   
       setLayout(new BorderLayout());
       add(textareaScrollPane, BorderLayout.CENTER);
       add(new JScrollPane(jList), BorderLayout.EAST);
     }
   
     private static void createAndShowUI() {
       JFrame frame = new JFrame("TestScrollRectToVisible");
       frame.getContentPane().add(new TestScrollRectToVisible());
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.pack();
       frame.setLocationRelativeTo(null);
       frame.setVisible(true);
     }
   
     public static void main(String[] args) {
       java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
           createAndShowUI();
         }
       });
     }
   }

Vi Style Jtextarea ‹↑›

A problem in the code below is that the events to not 'consume' the keystrokes which generate them. So the 'i' key puts the JTextArea into edit mode, but an 'i' is inserted into the textarea. The 'i' gets inserted after the ActionEvent is fired, so its difficult to stop it being inserted.

It is necessary to change the actions for different modes.

Attempt to implement a 2 mode vi style JTextArea

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.swing.text.*;
   import java.io.*;
   import java.net.*;
   public class ViTextArea extends JTextArea {
     URL url;
     public ViTextArea(String sUrl) {
       super(30, 80);
       this.setFont(new Font("courier", Font.PLAIN, 20));
       this.setEditable(false);
       this.getCaret().setVisible(true); /* or */
       this.getCaret().setSelectionVisible(true);
       this.setActionKeys();
       try {
         this.url = new URL(sUrl);
         this.read(new InputStreamReader(url.openStream()), null);
       } catch (IOException e) {
         e.printStackTrace();
       }
     }

     private void setActionKeys() {
       ActionMap actionMap = this.getActionMap();
       InputMap inputMap = this.getInputMap(JComponent.WHEN_FOCUSED);
       inputMap.put(KeyStroke.getKeyStroke("I"), "insert-mode");
       actionMap.put("insert-mode", new InsertModeAction());
       inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "normal-mode");
       actionMap.put("normal-mode", new NormalModeAction());
       inputMap.put(KeyStroke.getKeyStroke("shift J"), "page-down");
       inputMap.put(KeyStroke.getKeyStroke("shift K"), "page-up");
       inputMap.put(KeyStroke.getKeyStroke("shift D"), "delete-next-word");
       inputMap.put(KeyStroke.getKeyStroke("shift S"), "select-paragraph");
       inputMap.put(KeyStroke.getKeyStroke("X"), "exit");
       actionMap.put("exit", new ExitAction());
     }
   
     public static void main(String[] args) throws Exception {
       ViTextArea area =
       new ViTextArea("file:java-book.txt");
       JFrame frame = new JFrame("The WebTextArea");
       //frame.add(new KeyScrollPane(area));
       frame.add(new JScrollPane(area));
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.pack(); frame.setLocationRelativeTo(null);
       frame.setVisible(true);
     }
   }
   
   class ExitAction extends AbstractAction {
     public ExitAction() {
       putValue(Action.NAME, "Exit");
       putValue(Action.SHORT_DESCRIPTION, "Exits the application");
       //putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
     }
     public void actionPerformed(ActionEvent e) {
       System.exit(0);
     }
   }

   class NormalModeAction extends AbstractAction {
     public NormalModeAction() {
       putValue(Action.NAME, "Normal Mode");
       putValue(Action.SHORT_DESCRIPTION, 
         "Places the text area into vi style 'normal mode'");
     }
     public void actionPerformed(ActionEvent e) {
       JTextArea area = (JTextArea) e.getSource();
       area.setEditable(false);
       area.setBackground(Color.GRAY);
     }
   }

   class InsertModeAction extends AbstractAction {
     public InsertModeAction() {
       putValue(Action.NAME, "Enter Insert Mode");
       putValue(Action.SHORT_DESCRIPTION, 
         "Places the text area into vi style 'insert mode'");
     }
     public void actionPerformed(ActionEvent e) {
       JTextArea area = (JTextArea) e.getSource();
       area.setEditable(true);
       area.setBackground(Color.WHITE);
       PlainDocument doc = (PlainDocument) area.getDocument();
       try {
         doc.remove(area.getCaretPosition() -2, 6);
       }
       catch (BadLocationException ex) { ex.printStackTrace(); }
     }
   }

Jtextpanes ‹↑›

A JTextPane has a reputation for being complicated to use. This swing component can display embedded components such as images and other JComponents. The JTextPane is a subclass of the JEditorPane

JTextPane is similar JEditorPane but with the additional ability to edit styles and character attributes.

get plain text content from a html JTextPane (from its Document)

 textPane.getDocument().getText(0, textPane.getDocument().getLength()));

add some text to the end of a JTextPane

    StyledDocument doc = textPane.getStyledDocument();
    doc.insertString("text", doc.getLength(), attributes);

show an html page in a JTextPane ----- import javax.swing.*; import java.net.*; public class WebPane { public static void main(String args[]) throws Exception { JFrame f = new JFrame(); JScrollPane scroll = new JScrollPane(); JTextPane tp = new JTextPane(); tp.setText("loading..."); scroll.getViewport().add(tp); f.getContentPane().add(scroll); //jf.pack(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //jf.setSize(400,500); f.setVisible(true);

URL url = new URL("http://bumble.sf.net"); tp.setPage(url); } } ,,,

get the default font for a text pane

 System.out.println(UIManager.get("TextPane.font"));

get the pixel position of the cursor (caret) in jtextpane

    Rectangle caretCoords = textpane.modelToView(caretposition);
    y = (int) caretCoords.getY();

loop through a textpanes different styles

    JTextPane jtp = new JTextPane();
    ...
    HTMLDocument doc = (HTMLDocument) jtp.getDocument();
    StyleSheet styles = doc.getStyleSheet();
    Enumeration rules = styles.getStyleNames();
    while (rules.hasMoreElements()) {
        String name = (String) rules.nextElement();
        Style rule = styles.getStyle(name);
        System.out.println(rule.toString());
    }

Jeditorpane ‹↑›

The JEditorPane is the base swing component for displaying styled (or formatted) text. JTextPane is a subclass of JEditorPane. JEditorPane can display images but only when 'embedded' in HTML.

http://www.artima.com/forums/flat.jsp?forum=1&thread=1276 how to edit html in an JEditorPane

Loading Content Into The Jeditor Pane ‹↑›

setText(String s) the current editor kit is used (and therefore the content type of that editor kit) read(Reader r, HTMLDocument object) text read from a reader, the content type of the current EditorKit is used. Set the Base property on the HTMLDocument to allow relative image references to be resolved. This technique could be useful when initialising from a zipped file. setPage(URL url) content is read from a (local or remote) URL. The content type and EditorKit is determined automatically.

force a JEditorPane to reload a document

    Document doc = jEditorPane.getDocument();
    doc.putProperty(Document.StreamDescriptionProperty, null);
    jEditorPane.setPage(this.page);

can we specify the character set??

 editor.setContentType("text/html; charset=UTF-8");

load content into an editor pane from a File object

    File f = new File("index.html");
    JEditorPane jep = new JEditorPane(f.toURI().toURL());

display a local text file in a JEditorPane

   import javax.swing.*;
   import java.awt.Font;
   import java.net.*;
   public class FileEditorPane {
     public static void main(String[] args) throws Exception {
       JEditorPane ed = new JEditorPane("file:java-book.txt");
       ed.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 20));
       JFrame f = new JFrame("displaying file");
       f.add(new JScrollPane(ed));
       f.pack(); f.setExtendedState(JFrame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
     }
   }

Read To Load A Jeditorpane ‹↑›

initialize a JEditorPane with the read() method

    FileReader reader = new FileReader("form.html");
    JEditorPane editor = new JEditorPane();
    editor.setContentType("text/html");
    editor.setEditable(false);
    editor.read(reader, null);

The example below is similar to that above, except that it allows the developer to set the 'documentBase' property which allows the editor pane to resolve (and display) relative links, including embedded images.

load a stream into a JEditorPane with the read() method

    FileReader reader = new FileReader("form.html");
    JEditorPane editor = new JEditorPane();
    HTMLDocument doc = new HTMLDocument();
    doc.setBase(...);
    //editor.setContentType("text/html");
    editor.setEditable(false);
    editor.read(reader, doc);

The example below works but images are not displayed because the 'base' property is not set on the htmldocument and also because the images are are within the zip file and therefor not available.

read the file JList.html from zipped api docs into a JEditorPane

   import java.util.zip.*;
   import java.util.Enumeration;
   import java.io.*;
   import javax.swing.*;
   import java.awt.*;
   public class EditorPaneZip extends JPanel {
     JEditorPane area;
     public EditorPaneZip() {
       super(new BorderLayout());
       this.area = new JEditorPane();
       this.area.setContentType("text/html");
       this.area.setEditable(false);
       this.area.setFont(new Font("courier", Font.PLAIN, 20));
       this.loadPageFromZip();
       this.add(new JScrollPane(this.area), BorderLayout.CENTER);
     }
     public void loadPageFromZip() {
       try {
         ZipFile zf = new ZipFile("jdk-6-doc.zip");
         ZipEntry ze = 
           zf.getEntry("docs/api/javax/swing/JList.html");
         InputStream in = zf.getInputStream(ze);
         BufferedReader reader =  
           new BufferedReader(new InputStreamReader(in));
         this.area.read(reader, "zip entry");
         zf.close();
       }
       catch (IOException e) { e.printStackTrace(); }
     }
     public static void main(String[] args) {
       JFrame f = new JFrame("....");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(new EditorPaneZip());
       f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setVisible(true); 
     }
   }

Editorkits ‹↑›

The EditorKit for the JEditor pane determines the content type of the document.

display an html document as plain text in a JEditorPane

    String text = this.ed.getText();
    this.ed.setContentType("text/plain");
    this.ed.setText(text);

Searching In A Jeditorpane ‹↑›

How can we search the text in a jeditor pane? We need to search the text of the editor pane's document. We can do this with document.getText() which returns a plain text representaton of the Document contents. This should be fast in the case where there are no matches, but indexes into the Document are slightly wrong. So we have to use an iterator as pointed out by elliott hughes.

 String docText = this.area.getDocument().getText();
 int index = docText.indexOf(search);

The code below searches the 'visible' text of an html document in JEditorPane and highlights matches. It also moves the scroll window of the JEditorPane down to the first match. I probably need to store the matches in a List so that we can go to the next one with 'n' like in 'less'.

An alternative to setCaretPosition() in the code below is to use //Rectangle rect = this.area.modelToView(index); //this.area.scrollRectToVisible(rect); but I cant see much difference

If the search string is not a regular expression we can use search.length() to determine the end of the highlight.

do 'on the fly' searching for some text in an html JEditorPane

   import java.io.*;
   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.swing.text.*;
   import javax.swing.event.*;
   import javax.swing.text.html.*;
   import java.util.regex.*;
   public class SearchEditor extends JPanel implements DocumentListener {
     JTextField field;
     JEditorPane area;
     String page;
     public SearchEditor() {
       super(); 
       this.setLayout(new BorderLayout());
       this.page = "file:/usr/lib/jvm/java-6-sun-1.6.0.15/docs/api/" +
                   "javax/swing/JTree.html";
       this.field = new JTextField(40);
       this.field.getDocument().addDocumentListener(this);
       this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
       try {
         this.area = new JEditorPane(page);
         this.area.setEditable(false);
       } catch (IOException e) { e.printStackTrace(); }
       this.add(this.field, BorderLayout.NORTH);
       this.add(new JScrollPane(this.area), BorderLayout.CENTER);
     }
     public void insertUpdate(DocumentEvent e) { this.search(); }
     public void removeUpdate(DocumentEvent e) { this.search(); }
     public void changedUpdate(DocumentEvent e) { }

     /** searches for a pattern in the editor pane and highlights matches */
     public void search() {
       String search = this.field.getText();
       if (search.length() < 2) return;
       int matchCount = 0; int matchStart = 0; int matchEnd = 0;
       Pattern pattern = Pattern.compile(search);
       Highlighter highlighter = this.area.getHighlighter();
       DefaultHighlighter.DefaultHighlightPainter painter = 
         new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
       HTMLDocument document = (HTMLDocument) this.area.getDocument();
       for (HTMLDocument.Iterator it = 
         document.getIterator(HTML.Tag.CONTENT); it.isValid(); 
               it.next()) {
         try {
           String fragment = document.getText(
             it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
           Matcher matcher = pattern.matcher(fragment);
           while (matcher.find()) {
             if (matchCount == 0) {
               highlighter.removeAllHighlights();
               this.field.setBackground(Color.WHITE);
             }
             matchStart = it.getStartOffset() + matcher.start();
             matchEnd =  it.getStartOffset() + matcher.end();
             highlighter.addHighlight(matchStart, matchEnd, painter);
             System.out.format("start: %d, end: %d \n",matchStart, matchEnd);
             if (matchCount == 0) {
               this.area.setCaretPosition(it.getStartOffset());
             }
             matchCount++;
           }
         } catch (BadLocationException ex) { 
           System.out.println("bad location:");
         }
       }
       if (matchCount == 0) {
         // error! cant modify the document from within a 
         // documentlistener
         //this.field.setText(String.format(
         // "The text '%s' was not found", search));
         highlighter.removeAllHighlights();
         this.field.setBackground(Color.PINK);
         //this.field.setSelectionStart(0);
         //this.field.setSelectionEnd(this.field.getText().length());
         return;
       }
     }
     public void actionPerformed(ActionEvent evt) { this.search(); }
     public static void main(String args[]) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Searching Text in JEditorPane");
           f.add(new SearchEditor());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
           f.setVisible(true);
         }
       });
     }
   }

The version below of searching a JEditorPane with HTML content has some enhancements: The 1st or Nth match will be displayed about 1/3 of the way down the JScrollPane (see the CaretScroll example for this technique). case insensitive - is this a good idea. The 'n' key will be bound with a keybinding to go to the display the next match. added currentmatch in a different colour. todo: The enter key will hide the search box. The '/' key will show and focus the search box.

I added a class to hold the matches. Also I need to paint the highlight for the current match differently to the other matches. Shouldnt be too difficult.

Bug: this is throwing an exception from scrollToMatch when deleting items. This is probably trying to retrieve matches.get(0) when there are no matches.

enhanced 'on the fly' searching for some text in an html JEditorPane

   import java.io.*;
   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.swing.text.*;
   import javax.swing.event.*;
   import javax.swing.text.html.*;
   import java.util.regex.*;
   import java.util.*;
   public class SearchHtmlPane extends JPanel implements DocumentListener {
     JTextField field;
     JEditorPane area;
     JScrollPane scroll;
     String page;
     java.util.List<Match> matches;
     int currentMatch;
     Action nextMatch = new AbstractAction() {
       public void actionPerformed(ActionEvent e) {
         if (matches.isEmpty()) return;
         currentMatch++;
         currentMatch = currentMatch % matches.size();
         System.out.println(
           String.format("currentMatch: %d\nmatches.size:%d\n", 
           currentMatch, matches.size()));
         SearchHtmlPane.this.goToMatch();
       }
     };
     public SearchHtmlPane() {
       super(); 
       this.setLayout(new BorderLayout());
       this.currentMatch = 0;
       this.matches = new ArrayList<Match>();
       this.page = "file:/usr/lib/jvm/java-6-sun-1.6.0.15/docs/api/" +
                   "javax/swing/JTree.html";
       this.field = new JTextField(40);
       this.field.getDocument().addDocumentListener(this);
       this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
       try {
         this.area = new JEditorPane(page);
         this.area.setEditable(false);
       } catch (IOException e) { e.printStackTrace(); }

       KeyStroke keyStroke = KeyStroke.getKeyStroke("N");
       this.area.getInputMap(WHEN_FOCUSED).put(keyStroke, "next-match");
       this.area.getActionMap().put("next-match", nextMatch);

       this.scroll = new JScrollPane(this.area);
       this.add(this.field, BorderLayout.NORTH);
       this.add(this.scroll, BorderLayout.CENTER);
     }
     public void insertUpdate(DocumentEvent e) { this.search(); }
     public void removeUpdate(DocumentEvent e) { this.search(); }
     public void changedUpdate(DocumentEvent e) { }
     public void search() {
       String search = this.field.getText();
       if (search.length() < 2) return;
       int matchCount = 0; int matchStart = 0; int matchEnd = 0;
       Pattern pattern = Pattern.compile("(?i)" + search);
       HTMLDocument document = (HTMLDocument) this.area.getDocument();
       HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
       while (it.isValid()) {
         try {
           String fragment = document.getText(
             it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
           Matcher matcher = pattern.matcher(fragment);
           while (matcher.find()) {
             if (matchCount == 0) {
               this.matches.clear();
               this.currentMatch = 0;
               this.field.setBackground(Color.WHITE);
             }
             matchStart = it.getStartOffset() + matcher.start();
             matchEnd =  it.getStartOffset() + matcher.end();
             this.matches.add(new Match(matchStart, matchEnd));
             if (matchCount == 0) {
               this.goToMatch();
             }
             matchCount++;
           }
         } catch (BadLocationException ex) { 
           System.out.println("bad location:");
         }
         it.next();
       }
       this.highlight();
       if (matchCount == 0) {
         this.area.getHighlighter().removeAllHighlights();
         this.field.setBackground(Color.PINK);
         return;
       }
     }

     public void highlight() {
       int ii = 0;
       DefaultHighlighter.DefaultHighlightPainter bluepainter = 
         new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE);
       DefaultHighlighter.DefaultHighlightPainter painter = 
         new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
       this.area.getHighlighter().removeAllHighlights();
       try {
         for (Match m: this.matches) {
           if (ii == this.currentMatch) {
             this.area.getHighlighter().addHighlight(
               m.start, m.end, bluepainter);
           }
           else {
             this.area.getHighlighter().addHighlight(
               m.start, m.end, painter);
           }
           ii++;
         }
       }
       catch (BadLocationException e) {}
     }

     public void goToMatch() {
       if (this.matches.isEmpty()) return;
       this.area.setCaretPosition(
         this.matches.get(this.currentMatch).start);
       this.highlight();
       try {
         Dimension view = this.scroll.getViewport().getExtentSize(); 
         JScrollBar bar = this.scroll.getVerticalScrollBar();
         bar.setValue(this.area.modelToView(
           this.area.getCaretPosition()).y - view.height/3);
       } catch (BadLocationException ex) { 
         System.out.println("bad location:");
       }
     }

     public void actionPerformed(ActionEvent evt) { this.search(); }
     public static void main(String args[]) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Searching Text in JEditorPane");
           f.add(new SearchHtmlPane());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
           f.setVisible(true);
         }
       });
     }
   }

   /** just hold the start and end indexes of a match */
   class Match {
     public int start;
     public int end;
     public Match(int start, int end) {
       this.start = start; this.end = end;
     }
   }

I will try to use the code below to test that everything is working and also to see the values for the fragment indexes. Things like <br> seem to generate elements which dont appear in the 'content' iterator but which add to the indexes. An idea: create a character array initialized to space and then insert the content

testing searching for some text in an html JEditorPane

   import java.io.*;
   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.swing.text.*;
   import javax.swing.event.*;
   import javax.swing.text.html.*;
   import java.util.regex.*;
   public class SearchHtmlPane extends JPanel implements DocumentListener {
     JTextField field;
     JEditorPane area;
     JScrollPane scroll;
     int currentMatch;
     public SearchHtmlPane() {
       super(); 
       this.setLayout(new BorderLayout());
       this.currentMatch = 0;
       this.field = new JTextField(40);
       this.field.getDocument().addDocumentListener(this);
       this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
       this.area = new JEditorPane(
           "text/html", 
           "<html><font>is</font> tree<br><br><br>is<big>here<tt></html>");
       this.area.setEditable(false);
       this.scroll = new JScrollPane(this.area);
       this.add(this.field, BorderLayout.NORTH);
       this.add(this.scroll, BorderLayout.CENTER);
     }
     public void insertUpdate(DocumentEvent e) { this.search(); }
     public void removeUpdate(DocumentEvent e) { this.search(); }
     public void changedUpdate(DocumentEvent e) { }

     public void search() {
       String search = this.field.getText();
       if (search.length() < 2) return;
       int matchCount = 0; int matchStart = 0; int matchEnd = 0;
       Pattern pattern = Pattern.compile("(?i)" + search);
       Highlighter highlighter = this.area.getHighlighter();
       DefaultHighlighter.DefaultHighlightPainter painter = 
         new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);

       HTMLDocument document = (HTMLDocument) this.area.getDocument();
       HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
       while (it.isValid()) {
         try {
           String fragment = document.getText(
             it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
           System.out.println(String.format(
             "fragment:%s\nStartOffset:%d\nEndOffset:%d\n", 
             fragment, it.getStartOffset(), it.getEndOffset()));
           Matcher matcher = pattern.matcher(fragment);
           while (matcher.find()) {
             if (matchCount == 0) {
               highlighter.removeAllHighlights();
               this.field.setBackground(Color.WHITE);
             }
             matchStart = it.getStartOffset() + matcher.start();
             matchEnd =  it.getStartOffset() + matcher.end();
             highlighter.addHighlight(matchStart, matchEnd, painter);
             //System.out.format(
             //  "start: %d, end: %d \n",matchStart, matchEnd);
             if (matchCount == 0) {
               this.area.setCaretPosition(it.getStartOffset());
               Dimension view = this.scroll.getViewport().getExtentSize(); 
               JScrollBar bar = this.scroll.getVerticalScrollBar();
               bar.setValue(this.area.modelToView(
                 this.area.getCaretPosition()).y - view.height/3);
             }
             matchCount++;
           }
         } catch (BadLocationException ex) { 
           System.out.println("bad location:");
         }
         it.next();
       }
       if (matchCount == 0) {
         highlighter.removeAllHighlights();
         this.field.setBackground(Color.PINK);
         return;
       }
     }
     public void actionPerformed(ActionEvent evt) { this.search(); }
     public static void main(String args[]) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Searching Text in JEditorPane");
           f.add(new SearchHtmlPane());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
           f.setVisible(true);
         }
       });
     }
   }

Html In Jeditorpane ‹↑›

"JEditorPane has inherent problems with specifying size using %. Few developers consider JEditorPane to be suitable for anything beyond carefully controlled and very limited HTML/CSS." (Andrew Thompson)

Interestingly, the content of a JEditorPane (and JTextPane) which has content type "text/html" is actually stored in a javax.swing.text.Document in plain text format (no html tags) but with an associated set of attributes (which correspond to the html tags). When you call the getText() method, html text is returned (generated from the Document) but the html may not be the same html that you put in to the JEditorPane.

When a JEditorPane has content type "text/html" then its associated document is a HTMLDocument which you can retrieve with something like

 doc = (HTMLDocument)editorpane.getDocument();

Then you can iterate over all the tags, if you so desire.

create and load html text into a new JEditorPane from a local file

 JEditorPane ed = new JEditorPane("file:a.html");

instantiate a JEditorPane to display html content from a String 'text'

 JEditorPane ed = new JEditorPane("text/html", text);

get plain text content from a html JEditorPane (from its Document)

 textPane.getDocument().getText(0, textPane.getDocument().getLength()));

The setPage() method is not really necessary, nor is a URL in the constructor since you can just use a String

http://www.gutenberg.org/files/2600/2600-h/2600-h.htm The url for 'War and Peace' in html format

Gutenberg doesnt seem to allow programmatic access and I dont know how to set the 'user-agent' for a JEditorPane. The book takes about a minute to load and render. But the scrolling performance seems ok once the book is loaded.

The method below for creating an HTMLDocument (which can be used with the editorpane.setDocument() method?) is verbose and is only necessary if you have some special requirement. Untested code.

create an HTMLDocument from a string containing html

    JEditorPane p; ...
    Reader stringReader = new StringReader(string);
    HTMLEditorKit htmlKit = new HTMLEditorKit();
    HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument();
    htmlKit.read(stringReader, htmlDoc, 0);
    p.setDocument(htmlDoc);
  ,,,,

  The example below shows how the html returned from editor.getText() is
  not the same html text as was used to initialise the editor pane.
  The html printed has been 'fixed' (end tags inserted etc). Also
  the method editor.getDocument().getText() returns plain text, not
  html.

  * load some html content and extract the plain text from the document
   import javax.swing.*;
   public class HtmlEdPane {
     public static void main(String[] args) throws Exception {
       JEditorPane ed = new JEditorPane("text/html", 
         "<html>hi<br><big>sky</big><br>trees");
       ed.setEditable(true);
       JOptionPane.showMessageDialog(null, ed);
       System.out.println(
         ed.getDocument().getText(0, ed.getDocument().getLength()));
       System.out.println("Text is: " + ed.getText());
     }
   }

try to display War and Peace in a JEditorPane (3.1 megabytes)

   import javax.swing.*;
   import java.awt.Frame;
   import java.net.*;
   public class BigBookPane {
     public static void main(String[] args) throws Exception {
       long startTime = System.currentTimeMillis();
       JEditorPane ed = new JEditorPane("file:eg/war.and.peace.html");
       ed.setEditable(false);
       JFrame f = new JFrame("Project Gutenberg in a JEditorPane");
       f.getContentPane().add(new KeyScrollPane(ed));
       f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
       long loadTime = System.currentTimeMillis() - startTime;
       f.setTitle(String.format("Book loaded in %d miliseconds", loadTime));
     }
   }

display the java api web documentation for JTree using JEditorPane

   import javax.swing.*;
   import java.awt.Frame;
   import java.net.*;
   public class WebPane {
     public static void main(String[] args) throws Exception {
       JEditorPane ed = new JEditorPane(
     "http://docs.oracle.com/javase/1.5.0/docs/api/javax/swing/JTree.html");
       ed.setEditable(false);
       JFrame f = new JFrame();
       f.getContentPane().add(new JScrollPane(ed));
       f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
     }
   }

The code below is a way of getting only html content (without the actual tags). We can then use those indexes to highlight content in the JEditorPane. This can form the basic of searching a JEditorPane which contains html text. This is working.

The highlights need to be put at indexes reflecting the underlying document text (not the html that was loaded). This is because the JEditor/TextPane does not store the text as html, but rather as a document with attributes.

We cant just use ed.getDocument.getText(0, ...); and iterate over that for matches because the document seems to store newline characters or something strange for <br> and these are not returned by e.getDocument.getText(...).

iterate over the html tags in HTMLDocument from a JEditor/TextPane

   import javax.swing.*;
   import javax.swing.text.*;
   import javax.swing.text.html.*;
   import java.util.regex.*;
   import java.awt.Color;
   public class SearchEditorPane {
     public static void main(String[] args) throws Exception {
       JEditorPane ed = new JEditorPane("text/html",
       "<html><br><br>hitre<br><big>sky</big><br>trees");
       ed.setEditable(true);

       Pattern pattern = Pattern.compile("tre");
       Highlighter highlighter = ed.getHighlighter();
       HTMLDocument document = (HTMLDocument) ed.getDocument();
       for (HTMLDocument.Iterator it = 
              document.getIterator(HTML.Tag.CONTENT); it.isValid(); 
               it.next()) {
         try {
           String fragment = document.getText(
             it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
           Matcher matcher = pattern.matcher(fragment);
           while (matcher.find()) {
             highlighter.addHighlight(
               it.getStartOffset() + matcher.start(),
               it.getStartOffset() + matcher.end(),
                new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
             System.out.format("start: %d, end: %d \n", 
               it.getStartOffset() + matcher.start(),
               it.getStartOffset() + matcher.end());
             //++matchCount;
           }
         } catch (BadLocationException ex) { 
           System.out.println("bad location:");
         }
       }
   
       JOptionPane.showMessageDialog(null, ed);
       System.out.println(ed.getDocument().getText(
           0, ed.getDocument().getLength()));
       System.out.println("Text is: " + ed.getText());
     }
   }

use a while loop to iterate over an HTMLDocument

    HTMLDocument document = (HTMLDocument) this.area.getDocument();
    HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
    while (it.isValid()) {
      try {
        String fragment = document.getText(
          it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
        System.out.println(fragment);
      } catch (BadLocationException ex) { 
        System.out.println("bad location:");
      }
      it.next();
    }

Hyperlinks And The Jeditorpane ‹↑›

To make the hyperlinks work in a JEditorPane with the content type set to "text/html" it is necessary to implement the HyperlinkListener interface.

The JEditorPane only generates hyperlink events in a non editable pane. Also, if there is no reference then the method scrollToReference() does nothing (it doesnt scroll to the top of the page)

display an html file with activated (local only) link references

   import javax.swing.*;
   import javax.swing.event.*;
   import java.net.*;
   public class JavaDocPane {
     public static void main(String[] args) throws Exception {
       String docHome = new String("/usr/lib/jvm/java-6-sun/docs/api/");
       final URL url = 
         new URL("file:" + docHome + "javax/swing/JTree.html");
       final JEditorPane ed = new JEditorPane(url);
       ed.setEditable(false);
       ed.addHyperlinkListener(new HyperlinkListener() {
         public void hyperlinkUpdate(HyperlinkEvent e) {
           if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
             if (e.getURL().sameFile(url)) {
               ed.scrollToReference(e.getURL().getRef());
             }
           }
         }
       });
       JFrame f = new JFrame(); f.add(new JScrollPane(ed));
       f.pack(); f.setExtendedState(JFrame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
     }
   }

a hyperlink listener that loads a new html page in the JEditorPane

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   import java.net.*;
   import javax.swing.event.*;
   import java.io.IOException;
   import java.util.logging.*;
   public class BrowsePanel extends JPanel implements HyperlinkListener {
     JEditorPane ed;
     JLabel info;
     URL page;
     public BrowsePanel(URL page) throws IOException {
       this.ed = new JEditorPane(page);
       this.ed.addHyperlinkListener(this);
       this.ed.setEditable(false);
       this.info = new JLabel("info:");
       this.page = page;
       this.add(this.info, BorderLayout.NORTH);
       // not displaying well
       //this.add(new JScrollPane(this.ed), BorderLayout.CENTER);
     }
     public void hyperlinkUpdate(HyperlinkEvent ev) {
       if (ev.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
         try {
           if (ev.getURL().sameFile(this.page)) {
             ed.scrollToReference(ev.getURL().getRef());
           }
           else ed.setPage(ev.getURL());
           this.info.setText(ev.getURL().toExternalForm());
           this.page = ev.getURL();
         } catch (IOException ex) {
           Logger.getLogger(
             BrowsePanel.class.getName()).log(Level.SEVERE, null, ex);
         }
       }
     }
     public static void main(String[] args) throws Exception {
       BrowsePanel p = new BrowsePanel(new URL(
         "file:/usr/lib/jvm/java-6-sun/docs/api/javax/swing/JTree.html"));
       JFrame f = new JFrame();
       f.getContentPane().add(p);
       f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
     }
   }

In the code below, I think the scrollToReference does not actually throw any Exceptions, hence you could dispense with try/catch

a hyperlinklistener that scrolls the JEditorPane to link reference

   htmlPane.addHyperlinkListener(new HyperlinkListener() {
     public void hyperlinkUpdate(HyperlinkEvent e) {
       if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
         if (e.getURL().sameFile(url)) {
           try {
             htmlPane.scrollToReference(e.getURL().getRef());
           } catch (Throwable t) {
             t.printStackTrace();
           }
         }
       }
     }
   });

In the code below creating the EditorKit is not actually necessary: we can just use the setPage(URL page) method of the JEditorPane

activate the default browser when a hyperlink is clicked, untested

   final JEditorPane editor = new JEditorPane();
   editor.setEditorKit(JEditorPane.createEditorKitForContentType("text/html"));
   editor.setEditable(false);
   editor.setText("<a href=\"http://www.google.com/finance?q=NYSE:C\">C</a>, <a href=\"http://www.google.com/finance?q=NASDAQ:MSFT\">MSFT</a>");
   editor.addHyperlinkListener(new HyperlinkListener() {
     public void hyperlinkUpdate(HyperlinkEvent e) {
       if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
         // java 1.6+
         if (Desktop.isDesktopSupported()) {
           Desktop.getDesktop().browse(e.getURL().toURI());
         }
       }
     }
   });

Hyperlink Events ‹↑›

To implement functionality for hovering over a link (rather than actually clicking on it) check the HyperlinkEvent.EventType

check if a link was hovered over (not clicked)

 if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {...}

Modifying Html In The Jeditorpane ‹↑›

The code below requires that we know the structure of the html document (the order and nesting of the tags).

change the value of an html table cell in a JEditorPane document

   Document doc = editorpane.getDocument();
   Element html = doc.getRootElements()[0];
   Element body = html.getElement(1);
   Element table = body.getElement(1);
   try {
     Element tr2 = table.getElement(1);
     Element tr2td1 = tr2.getElement(0);
     doc.insertString(tr2td1.getStartOffset(), "1: 123,456",
                      SimpleAttributeSet.EMPTY);
   
     Element tr3 = table.getElement(2);
     Element tr3td1 = tr3.getElement(0);
     doc.insertString(tr3td1.getStartOffset(), "2: 765.123",
                      SimpleAttributeSet.EMPTY);
   } catch (BadLocationException e) {
     e.printStackTrace();
   }

Css With Jeditorpane ‹↑›

To see a list of supported css attributes see the api docs for the class javax.swing.text.html.css

The JEditorPane claims to support css style sheets to style html documents displayed in the pane.

add some css styling to an editor pane

    JEditorPane ed = new JEditorPane(new URL("file:test.html"));
    ed.setEditable(false);
    StyleSheet styles = ((HTMLEditorKit)ed.getEditorKit()).getStyleSheet();
    styles.addRule("body {font-size: xx-large; color:#000; font-family:times; margin: 4px; }");

add css styles to a JEditorPane html document

   import javax.swing.*;
   import javax.swing.text.html.*;
   import javax.swing.text.*;
   public class CssPane {
     public static void main(String[] args) {
       JEditorPane ed = new JEditorPane();
       ed.setEditable(false);
       HTMLEditorKit kit = new HTMLEditorKit();
       ed.setEditorKit(kit);
       JScrollPane scrollPane = new JScrollPane(ed);
       // add some styles to the html
       StyleSheet styleSheet = kit.getStyleSheet();
       styleSheet.addRule(
         "body {font-size: xx-large; font-family:times; margin: 4px; }");
       styleSheet.addRule("h1 {color: blue;}");
       styleSheet.addRule("h2 {color: #ff0000;}");
       styleSheet.addRule("pre {font: 10px monaco; color: black; background-color: #fafafa; }");
       Document doc = kit.createDefaultDocument();
       ed.setDocument(doc);
       String s = "<body><h1>hello</h1>Big font<pre>code text</pre></body>";
       ed.setText(s);
       JOptionPane.showMessageDialog(null, ed);
     }
   }

The <body> css font setting in the example below is not percolating down to the <code> font attribute. So it must be set seperately font-size: x-large produces a nice sized font for reading (for me at least)

See the apps section for a simple javadoc browser based on JEditorPane

add css styles (big font) to an existing page and show html source code

   import javax.swing.*;
   import javax.swing.event.*;
   import javax.swing.text.html.*;
   import java.net.*;
   import java.awt.*;
   import java.awt.event.*;
   public class HtmlSourcePanel extends JPanel 
     implements ActionListener, HyperlinkListener {
     JEditorPane ed;
     JToggleButton button;
     String className;
     URL page;
     final static String docHome = "/usr/lib/jvm/java-6-sun/docs/api";

     public HtmlSourcePanel(String className) {
       super(new BorderLayout());
       this.className = className;
       try {
         this.page = new URL(String.format(
           "file:%s/%s.html", this.docHome, className.replace(".", "/")));
         this.ed = new JEditorPane(page);
         this.ed.setEditable(false);
         this.ed.addHyperlinkListener(this);

         StyleSheet styles = 
           ((HTMLEditorKit)ed.getEditorKit()).getStyleSheet();
         styles.addRule("body {font-size: x-large; color:#000; font-family:Georgia; margin: 20px; }");
         styles.addRule("code {font-size: large; }");

         this.button = new JToggleButton("Toggle Source View");
         this.button.addActionListener(this);
         this.add(this.button, BorderLayout.NORTH);
         this.add(new JScrollPane(this.ed), BorderLayout.CENTER);
       }
       catch (java.net.MalformedURLException e) {}
       catch (java.io.IOException e) {}
     }
     public void hyperlinkUpdate(HyperlinkEvent e) {
       if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
         if (e.getURL().sameFile(this.page)) {
           try {
             this.ed.scrollToReference(e.getURL().getRef());
           } catch (Throwable t) { t.printStackTrace(); }
         }
         else if (!e.getURL().sameFile(this.page)) {
           try {
           this.ed.setPage(e.getURL());
           } catch (Throwable t) { t.printStackTrace(); }
         }
       }
     }
     public void actionPerformed(ActionEvent e) {
       if (this.button.isSelected()) {
         String text = this.ed.getText();
         this.ed.setContentType("text/plain");
         this.ed.setFont(new Font("Monospaced", Font.PLAIN, 16));
         this.ed.setText(text);
       } else {
         String text = this.ed.getText();
         this.ed.setContentType("text/html"); 
         this.ed.setText(text);
       }
     }
     public static void main(String[] args) throws Exception
     {
       HtmlSourcePanel j = new HtmlSourcePanel("java.lang.String");
       JFrame f = new JFrame(); f.add(j);
       f.pack(); f.setExtendedState(JFrame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
     }
   }

The code below works but is slow, since the html page has to rerender each time the font size is changed, and the rendering process is slow. The java css renderer has problems with relative font sizes and doesnt inherit the body font size to some elements (eg <code>). This means that some of the elements dont display at the size asked for.

change the css font size for a JEditorPane

   import javax.swing.*;
   import javax.swing.event.*;
   import javax.swing.text.html.*;
   import javax.swing.text.*;
   import java.net.*;
   import java.io.*;
   import java.awt.*;
   import java.awt.event.*;
   public class FontSizeEditorPane extends JPanel 
      implements ActionListener {
     URL page;
     JEditorPane ed;
     JButton smallerButton;
     JButton biggerButton;
     int fontSize;

     final static String docHome = "file:/usr/lib/jvm/java-6-sun/docs/api";
     public FontSizeEditorPane() {
       super(new BorderLayout());
       this.fontSize = 18;
       this.smallerButton = new JButton("--Font");
       this.smallerButton.addActionListener(this);
       this.biggerButton = new JButton("++Font");
       this.biggerButton.addActionListener(this);
       try {
         this.page = new URL(docHome + "/java/lang/String.html");
         this.ed = new JEditorPane(); this.ed.setPage(this.page);
         this.ed.setEditable(false);
         this.setFontSize(this.fontSize);

         this.add(new JScrollPane(this.ed), BorderLayout.CENTER);
         JPanel buttonPanel = new JPanel();
         buttonPanel.add(this.smallerButton);
         buttonPanel.add(this.biggerButton);
         this.add(buttonPanel, BorderLayout.NORTH);
       }
       catch (java.net.MalformedURLException e) { e.printStackTrace(); }
       catch (java.io.IOException e) { e.printStackTrace(); }
     }
     public void setFontSize(int size) {
       this.fontSize = size;
       StyleSheet styles = 
         ((HTMLEditorKit) this.ed.getEditorKit()).getStyleSheet();
       styles.addRule(String.format(
         "body {font-size: %dpx; color:#000; " +
         " font-family:Georgia; margin: 20px; }", this.fontSize));
       styles.addRule(String.format(
         "code {font-size: %dpx; }", this.fontSize-1));
       styles.addRule(String.format(
         "font {font-size: %dpx; }", this.fontSize-1));
       this.reloadPage();
     }
     /** clears the stream to force the page to be reloaded */
     public void reloadPage() {
       try {
         Document doc = this.ed.getDocument();
         doc.putProperty(Document.StreamDescriptionProperty, null);
         this.ed.setPage(this.page);
       } catch (IOException err) { err.printStackTrace(); }
     }
     public void actionPerformed(ActionEvent e) {
       if (e.getSource() == this.biggerButton) {
         this.setFontSize(this.fontSize+2);
       }
       else if (e.getSource() == this.smallerButton) {
         this.setFontSize(this.fontSize-2);
       }
     }
     public static void main(String[] args) throws Exception {
       FontSizeEditorPane p = new FontSizeEditorPane();
       JFrame f = new JFrame("Css and Editor Panes"); f.add(p);
       f.pack(); f.setExtendedState(JFrame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
     }
   }

The code below doesnt seem to work for me, where as the stylesheet.addRule(...) does work.

attempt to make html text in a JEditorPane larger using css, untested

   private void makeItBig()
   {
     HTMLDocument doc = (HTMLDocument) pane.getDocument();
     MutableAttributeSet attr = new SimpleAttributeSet();
     doc.getStyleSheet().addCSSAttribute(
       attr, CSS.Attribute.FONT_SIZE, "xx-large");
     doc.setCharacterAttributes(
       0, pane.getDocument().getLength(), attr, false);
   }

Plain Text With Jeditorpane ‹↑›

make the JEditorPane fixed pitch font, plain text

    pane.setContentType("text/plain");
    pane.setFont(new Font("Monospaced", Font.PLAIN, 16));
    pane.setText(text);

Listeners And Events For The Jeditorpane ‹↑›

do something when a new page is loaded in the JEditorPane

    ed.setPage(getClass().getResource("htmlFormatTable.html"));
    ed.addPropertyChangeListener(new PropertyChangeListener() {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
        if ("page".equals(evt.getPropertyName())) {
          //do something here
        }
      }
    });

The setPage() method is asynchronous, that is it returns immediately even if the page takes a while to load, parse and render. Once the page finishes loading the PropertyChangeEvent for 'page' will fire.

do something when the first page finishes loading

    ed.setPage("file:test.html");
    ed.addPropertyChangeListener(new PropertyChangeListener() {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
        if ("page".equals(evt.getPropertyName())) {
          //do something here
        }
        ed.removePropertyChangeListener(this);
      }
    });

Gotchas For The Jeditorpane ‹↑›

- if you dont setEditable(false) for html content the content does not render properly, lots of html artifacts. - It seems that you have to call pane.getText() after the JEditorPane is visible or at least a while after pane.setPage() otherwise truncated text is returned. - The JEditorPane has a limited html and css rendering capability

Jtree Tree Component ‹↑›

Like most other swing components the swing tree component uses a "model" interface to supply data to the tree component. To the new-comer to interface or object oriented programming this may seem daunting, but its not. There arrangement is simple: The model has a series of methods which allow the tree component to display each node or leaf on the tree. But the tree doesnt mind where that data comes from. This gives a great deal of flexibility to the programmer, who can use any kind of data to create a tree.

Linux notes: The JTree looks much nicer with a largish georgia font.

show a JTree component with some example values

   import javax.swing.*;
   public class DefaultTree {
     public static void main(String[] args)
     {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame();
           JTree t = new JTree();
           f.getContentPane().add(t);
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
   }

exand all nodes in a JTree

   import javax.swing.*;
   import java.awt.Dimension;
   public class ExpandTree extends JPanel {
     JTree tree;
     public ExpandTree() {
       tree = new JTree();
       for (int i = 0; i < tree.getRowCount(); i++) {
         tree.expandRow(i);
       }
       this.add(this.tree);
       this.setPreferredSize(new Dimension(300, 600));
     }
     public static void main(String[] args)
     {
       ExpandTree p = new ExpandTree();
       JOptionPane.showMessageDialog(null, p);
     }
   }

collapse all nodes in a JTree

 tree.collapsePath(tree.getPathForRow(0));

collapse all nodes in a JTree component

     JTree jtree;
     for (int i = 0; i < jTree.getRowCount(); i++) {
       jTree.collapseRow(i);
     }

Configure Jtrees ‹↑›

Create a tree that allows one selection at a time.

     tree = new JTree();
     tree.getSelectionModel().setSelectionMode
       (TreeSelectionModel.SINGLE_TREE_SELECTION);

create JTree with a horizontal lineStyle

 tree.putClientProperty("JTree.lineStyle", "Horizontal");

The possible values are: "Angled" (the default), "Horizontal", and "None".

Nodes Of Trees ‹↑›

Nodes are either branch (which can contain child nodes) or leaf (which cant). Nodes can be identified either by their path (TreePath) or my their display row.

The JTree must be instantiated with the root node after all the nodes have been added to the tree.

useful methods of JTextArea
setMargin(new Insets(55,5,5)) - create a margin inside the area

add nodes to a tree with DefaultMutableTreeNode

   import javax.swing.*;
   import javax.swing.tree.*;
   import java.awt.*;
   public class NodeTree {
     public static void main(String[] args)
     {
       System.setProperty("awt.useSystemAAFontSettings","on");
       DefaultMutableTreeNode top, category, node;
       top = new DefaultMutableTreeNode("A JTree Example");
       category = new DefaultMutableTreeNode("Trees");
       top.add(category);
       for (String s: new String[]{"oak", "yew", "elder", "acacia"}) {
         node = new DefaultMutableTreeNode(s);
         category.add(node);
       }
       JTree tree = new JTree(top);
       tree.setFont(new Font(Font.SERIF, Font.PLAIN, 22));
       tree.setPreferredSize(new Dimension(300, 600));
       //tree.putClientProperty("JTree.lineStyle", "None");
       JOptionPane.showMessageDialog(null, tree);
     }
   }

Tree Models ‹↑›

The TreeModel supplies the data for JTree component (which is also know as a 'view' of the data). We basically have to implement a handfull of methods relating to parent and child nodes in the TreeModel.

a file and directory TreeModel for use with a JTree element --------- import javax.swing.*; import java.awt.Font; import javax.swing.plaf.FontUIResource; import javax.swing.tree.*; import javax.swing.event.*; import java.io.*;

public class FileSystemModel implements TreeModel { String root; public FileSystemModel() { this( System.getProperty("user.home")); } public FileSystemModel( String startPath ) { root = startPath; } public Object getRoot() { return new File( root ); } public Object getChild( Object parent, int index ) { File directory = (File)parent; String[] children = directory.list(); return new File( directory, children[index] ); } public int getChildCount( Object parent ) { File file = (File)parent; if ( file.isDirectory() ) { String[] children = file.list();

JTree useful node methods
node.getUserObject() - returns the object of a node (should be cast)
node.isLeaf() - check if this is a leaf node
return children.length; } return 0; } public boolean isLeaf(Object node) { return ((File)node).isFile(); } public void valueForPathChanged( TreePath path, Object newValue ) {} public void removeTreeModelListener(TreeModelListener l) {} public void addTreeModelListener(TreeModelListener l) {} public int getIndexOfChild( Object parent, Object child ) { File directory = (File)parent; File fileSysEntity = (File)child; String[] children = directory.list(); int result = -1; for ( int i = 0; i < children.length; ++i ) { if ( fileSysEntity.getName().equals( children[i] )) result = i; break; } return result; } public static void main(String[] args) throws Exception { //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); JFrame f = new JFrame("A File System Tree"); JTree t = new JTree(new FileSystemModel()); t.setFont(new Font("Georgia", Font.PLAIN, 18)); f.getContentPane().add(new JScrollPane(t)); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } } ,,,

Jtree Events And Listeners ‹↑›

Listen for when the selected node changes

 tree.addTreeSelectionListener(this);

a tree with a SelectionChangeListener

   import javax.swing.*;
   import javax.swing.tree.*;
   import javax.swing.event.*;
   import java.awt.*;
   public class ListenTree extends JPanel
         implements TreeSelectionListener {
     JTree tree;
     JTextArea area;
     public ListenTree() {
       super(new GridLayout(0, 1));
       this.tree = new JTree();
       this.tree.addTreeSelectionListener(this);
       this.tree.setFont(new Font(Font.SERIF, Font.PLAIN, 22));
       this.area = new JTextArea("Listening for Events \n");
       this.area.setFont(new Font(Font.SERIF, Font.PLAIN, 12));
       this.area.setLineWrap(true);
       this.add(new JScrollPane(this.tree));
       this.add(new JScrollPane(this.area));
       this.setPreferredSize(new Dimension(400, 600));
     }
   
     public void valueChanged(TreeSelectionEvent e) {
       DefaultMutableTreeNode node =
         (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
       this.area.append("Selection Event! " + e + "\n");
       if (node == null) return;
       Object nodeInfo = node.getUserObject();
       if (node.isLeaf()) { }
     }
     public static void main(String[] args) throws Exception {
       JOptionPane.showMessageDialog(null, new ListenTree()); 
     }
   }
,,,

Jtable Swing Table Component ‹↑›

If you do not add a swing table to a scrollpane, then it is necessary to add the table header seperately to the container component.

using tables and cell renderers

 http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender

create a swing table using a default table model

    DefaultTableModel tm = new DefaultTableModel();
    tm.addColumn("Column 0");
    tm.addColumn("Column 1");
    tm.addColumn("Column 2");
    tm.addRow(new String[]{"Table 00", "Table 01", "Table 02"});
    tm.addRow(new String[]{"Table 10", "Table 11", "Table 12"});
    tm.addRow(new String[]{"Table 20", "Table 21", "Table 22"});
    tm.addRow(new String[]{"Table 30", "Table 31", "Table 32"});
    table = new JTable(tm);  

create a table using the DefaultTableModel

  import javax.swing.*;
  import javax.swing.table.*;
  import javax.swing.plaf.FontUIResource;
  import java.awt.Font;
  public class TableTest extends JPanel {
    JTable table;
    public TableTest() {
      super();
      DefaultTableModel m = new DefaultTableModel();
      m.addColumn("Tree");
      m.addColumn("Origin");
      m.addRow(new String[]{"Eucalypt", "Australia"});
      m.addRow(new String[]{"Cork Oak", "Europe"});
      m.addRow(new String[]{"Siete Cueros", "Colombia"});
      m.addRow(new String[]{"Walnut", "Europe"});
      table = new JTable(m);  
      this.table = new JTable(m);
      this.add(new JScrollPane(this.table));
    } 
    public static void main(String[] args) throws Exception { 
       UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
       UIManager.put("Table.font", new FontUIResource("Georgia", Font.PLAIN, 18));
       JFrame f = new JFrame("A Table with the default table model");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.getContentPane().add(new TableTest());
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
    }
  }

create a table using the AbstractTableModel

  import javax.swing.*;
  import javax.swing.table.*;
  import javax.swing.plaf.FontUIResource;
  import java.awt.Font;
  public class TableTest extends JPanel {
    JTable table;
    TableModel model = new AbstractTableModel() {
      public int getColumnCount() { return 10; }
      public int getRowCount() { return 10;}
      public Object getValueAt(int row, int col) { 
        return new Integer(row*col); 
        //return "row 
      }
    };
    public TableTest() {
      super();
      this.table = new JTable(this.model);
      this.add(new JScrollPane(this.table));
    } 

    public static void main(String[] args) throws Exception { 
       UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
       UIManager.put("Table.font", new FontUIResource("Georgia", Font.PLAIN, 18));
       JFrame f = new JFrame("A Table with an AbstractTableModel");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.getContentPane().add(new TableTest());
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
    }
  }

a swing table with java properties values in it, sortable

   import javax.swing.*;
   import javax.swing.border.*;
   import javax.swing.table.*;
   import javax.swing.plaf.FontUIResource;
   import java.awt.*;
   public class PropertiesTable extends JPanel {
     public PropertiesTable() {
       super();
       this.setBorder(new TitledBorder("Properties Table"));
       String[] header = {"Name", "Value"};
       String[] a = new String[0];
       String[] names =
         System.getProperties().stringPropertyNames().toArray(a);
       String[][] data = new String[names.length][2];
       for (int ii=0; ii<names.length; ii++) {
         data[ii][0] = names[ii];
         data[ii][1] = System.getProperty(names[ii]);
       }
       DefaultTableModel model = new DefaultTableModel(data, header);
       JTable table = new JTable(model);
       try { // java version 1.6+
         table.setAutoCreateRowSorter(true);
       } catch (Exception continuewithNoSort) { }
       this.add(new JScrollPane(table));
     }
   
     public static void main(String[] args) throws Exception {
       UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new PropertiesTable());
         }
       });
     }
   }

Images In Tables ‹↑›

put image icons into jtable cells

   import java.awt.*;
   import javax.swing.*;
   import javax.swing.table.*;
   public class TableIcon extends JFrame {
     public TableIcon() {
       ImageIcon aboutIcon = new ImageIcon("about16.gif");
       ImageIcon addIcon = new ImageIcon("add16.gif");
       ImageIcon copyIcon = new ImageIcon("copy16.gif");
   
       String[] columnNames = {"Picture", "Description"};
       Object[][] data = {
         {aboutIcon, "About"},
         {addIcon, "Add"},
         {copyIcon, "Copy"},
       };
   
       DefaultTableModel model = new DefaultTableModel(data, columnNames);
       JTable table = new JTable( model ) {
         //  Returning the Class of each column will allow different
         //  renderers to be used based on Class
         public Class getColumnClass(int column) {
           return getValueAt(0, column).getClass();
         }
       };
       table.setPreferredScrollableViewportSize(table.getPreferredSize());
       JScrollPane scrollPane = new JScrollPane( table );
       getContentPane().add( scrollPane );
     }
   
     public static void main(String[] args) {
       TableIcon frame = new TableIcon();
       frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
       frame.pack();
       frame.setVisible(true);
     }
   }

Menus Jmenubars And Jmenus And Jmenuitems ‹↑›

Menus in general are annoying but maybe the popup menu in java could be put to good use. The popup menu can contain any swing component.

build menus with JMenuBar, JMenu, JMenuItem

add a JMenuBar to a Window (JFrame)

 JMenuBar menubar = new JMenuBar(); frame.setJMenuBar(menubar);

remove the icon from a menu item

    menuItem = new JMenuItem();
    menuItem.setIcon(null); 

create a menu with control 0 shortcut key and an action listener

    JMenuItem screenshot = new JMenuItem("Screenshot");
    screenshot.setAccelerator(KeyStroke.getKeyStroke(
        KeyEvent.VK_0, InputEvent.CTRL_DOWN_MASK));
    screenshot.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
      }};
    JMenu menu = new JMenu("Other");
    menu.add(screenshot);
    JMenuBar mb = new JMenuBar();
    mb.add(menu);
    jframe.setJMenuBar(mb);

make a menu creating objects within method calls

    Menu vm = mkMenu(b, "page");
      vm.add(mi = mkMenuItem(b, "page", "first"));
      mi.addActionListener(firster);
      vm.add(mi = mkMenuItem(b, "page", "prev"));
      mi.addActionListener(previouser);
      vm.add(mi = mkMenuItem(b, "page", "next"));
      mi.addActionListener(nexter);
      vm.add(mi = mkMenuItem(b, "page", "last"));
      mi.addActionListener(laster);
      vm.add(mi = mkMenuItem(b, "page", "goto"));
      mi.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          Unicode.this.gotoPageUI.setVisible(true);
        }
      });
      mb.add(vm);COLLECTIONS

Jpopupmenu ‹↑›

The JPopupMenu can contain any Component or JComponent not just a list of JMenuItems. The popup menu is usually used in conjunction with a MouseListener or a MouseAdapter which shows the menu when the user clicks on a particular part of the interface.

The 'popupTrigger' refers to the mouse action (which button, and whether clicked or pressed etc) which displays a popup menu on the operating system on which the java application is running. This property can be checked to maintain consistency with the operating system.

add a new item to a menu (the JMenuItem is created implicitly)

 jpopupmenu.add("oak")

check whether the mousebutton is the operating system popup trigger

 mouseevent.isPopTrigger()

set the horizontal alignment

 menuitem.setHorizontalTextPosition(JMenuItem.RIGHT);

a simple example using a JPopupMenu

   import java.awt.event.*;
   import java.awt.*;
   import javax.swing.*;
   import javax.swing.event.*;
   
   public class SimplePopupMenu extends JPanel 
   implements ActionListener, MouseListener {
     JPopupMenu popup;
     JLabel label;

     public SimplePopupMenu() {
       super(new BorderLayout());
       this.label = new JLabel("info");
       this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.popup = new JPopupMenu();
       JMenuItem item;
       for (String s: new String[]{"oak", "yew", "elm", "tree"}) {
         popup.add(item = new JMenuItem(s));
         item.addActionListener(this);
         item.setFont(new Font("Georgia", Font.ITALIC, 20));
       }
       popup.setLabel("Justification");
       this.addMouseListener(this);
       this.add(this.label, BorderLayout.NORTH);
     }
     public void actionPerformed(ActionEvent event) {
       this.label.setText(String.format(
         "menu item '%s' was clicked", event.getActionCommand()));
     }
   
     public void mouseExited(MouseEvent e) { }
     public void mouseEntered(MouseEvent e) { }
     public void mousePressed(MouseEvent e) { checkPopup(e); }
     public void mouseClicked(MouseEvent e) { checkPopup(e); }
     public void mouseReleased(MouseEvent e) { checkPopup(e); }
     private void checkPopup(MouseEvent e) {
       if (e.isPopupTrigger()) {
         popup.show(this, e.getX(), e.getY());
       }
     }
     
     public static void main(String s[]) {
       JFrame f = new JFrame("JPopupMenu example");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setContentPane(new SimplePopupMenu()); f.pack();
       //f.setLocationRelativeTo(null);
       f.setSize(300, 300); f.setVisible(true);
     }
   }

In the code below the popup menu shows displaced vertically because the MouseEvent returns coordinates relative to the JTextArea, not the panel. With a small amount of code a lot of functionality is added.

add a JPopupMenu to a JTextArea with all default actions

   import java.awt.event.*;
   import java.awt.*;
   import javax.swing.*;
   import javax.swing.plaf.*;
   import javax.swing.event.*;
   
   public class TextAreaPopup extends JPanel implements MouseListener {
     JPopupMenu popup;
     JTextArea area;
     JLabel label;
     public TextAreaPopup() {
       super(new BorderLayout());
       this.area = new JTextArea("right click for actions", 20, 60);
       this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.area.addMouseListener(this);
       this.label = new JLabel("info");
       this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.popup = new JPopupMenu();
       this.popup.setLayout(new GridLayout(0,4));
       JMenuItem item;
       for (Action a: this.area.getActions()) {
         this.popup.add(a);
         this.popup.getComponent(this.popup.getComponentCount()-1)
           .setFont(new Font("Georgia", Font.ITALIC, 20));
       }
       popup.setLabel("JTextArea actions");
       this.add(this.label, BorderLayout.NORTH);
       this.add(this.area, BorderLayout.CENTER);
     }
     public void mouseExited(MouseEvent e) { }
     public void mouseEntered(MouseEvent e) { }
     public void mousePressed(MouseEvent e) { checkPopup(e); }
     public void mouseClicked(MouseEvent e) { checkPopup(e); }
     public void mouseReleased(MouseEvent e) { checkPopup(e); }
     private void checkPopup(MouseEvent e) {
       if (e.isPopupTrigger()) { 
         this.label.setText(String.format(
           "Click Position(x, y) = (%d, %d)", e.getX(), e.getY()));
         popup.show(this, e.getX(), e.getY());
       }
     }
     public static void main(String s[]) {
       JFrame f = new JFrame("JTextArea Action popup menu example");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(new TextAreaPopup()); f.pack();
       f.setLocationRelativeTo(null); f.setVisible(true);
     }
   }

The example below may become a prototype for retrieving the files in a certain folder, and allowing the user to choose which folder.

add a JPopupMenu to a JTextArea with directories containing jpegs

   import java.awt.event.*;
   import java.awt.*;
   import java.io.File;
   import javax.swing.*;
   //import javax.swing.plaf.*;
   import javax.swing.event.*;
   
   public class FolderPopup extends JPanel implements MouseListener {
     JPopupMenu popup;
     JTextArea area;
     JLabel label;
     public FolderPopup() {
       super(new BorderLayout());
       this.area = new JTextArea("right click to insert files", 20, 60);
       this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.area.addMouseListener(this);
       this.label = new JLabel("info");
       this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.popup = new JPopupMenu();
       this.popup.setLayout(new GridLayout(0,4));
       JMenuItem item;
       /*
       for (Action a: this.area.getActions()) {
         this.popup.add(a);
         this.popup.getComponent(this.popup.getComponentCount()-1)
           .setFont(new Font("Georgia", Font.ITALIC, 20));
       }
       */
       Action a = new InsertFileListAction(new File("."));
       this.popup.add(a);
       this.popup.getComponent(this.popup.getComponentCount()-1)
         .setFont(new Font("Georgia", Font.ITALIC, 20));
       popup.setLabel("JTextArea insert file list");
       this.add(this.label, BorderLayout.NORTH);
       this.add(new JScrollPane(this.area), BorderLayout.CENTER);
     }
     public void mouseExited(MouseEvent e) { }
     public void mouseEntered(MouseEvent e) { }
     public void mousePressed(MouseEvent e) { checkPopup(e); }
     public void mouseClicked(MouseEvent e) { checkPopup(e); }
     public void mouseReleased(MouseEvent e) { checkPopup(e); }
     private void checkPopup(MouseEvent e) {
       if (e.isPopupTrigger()) { 
         this.label.setText(String.format(
           "Click Position(x, y) = (%d, %d)", e.getX(), e.getY()));
         popup.show(this, e.getX(), e.getY());
       }
     }
     /** inserts a list of files into the text area */
     public void insertFileList(File folder) {
       this.area.append("file list...");
       for (File f: folder.listFiles()) {
         this.area.append(f.getAbsolutePath() + "\n");
       } 
     }
     public static void main(String s[]) {
       JFrame f = new JFrame("JTextArea Action popup menu example");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(new FolderPopup()); f.pack();
       f.setLocationRelativeTo(null); f.setVisible(true);
     }
     class InsertFileListAction extends AbstractAction {
       File folder;
       public InsertFileListAction(File folder) {
         this.folder = folder;
         putValue(Action.NAME, "Insert * " + this.folder.toString());
         putValue(Action.SHORT_DESCRIPTION, 
           "Inserts a list of files into a text area");
         putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_I));
       }
       public void actionPerformed(ActionEvent e) {
         FolderPopup.this.insertFileList(this.folder);
       }
     }
   }

Jmenuitems And Other Elements ‹↑›

We can retrieve a JMenuItem with the getComponent(int) method or maybe also with getSubElements()

retrieve the last added JMenuItem from a JPopupMenu

 item = popup.getComponent(popup.getComponentCount()-1);

iterate through the JMenuItems of a popup menu java1.5+

   for (Component child : jpopupmenu.getComponents()) {
     if (child instanceof JMenuItem) {
       //...
     }
   }

another way to iterate through JMenuItems java < 1.5

   JPopupMenu menu = new JPopupMenu();
   ...
   for (int ii = menu.getComponentCount()-1; ii >= 0; ii--) {
     Component child = menu.getComponent(ii);
     if (child instanceof JMenuItem) { ... }
   }

Appearance Of The Jpopupmenu ‹↑›

One can set the layout manager for a JPopupMenu just as for any JPanel or other container component. This is handy.

create a JPopupMenu which displays its item in 3 columns

     this.popup = new JPopupMenu();
     this.popup.setLayout(new GridLayout(0,2));
     JMenuItem item;
     for (String s: new String[]{"a", "b", c", "d", "e", "f"}) {
       popup.add(new JMenuItem(s));
     }

set the font of menu items when adding Actions

     popup.add(action);
     popup.getComponent(popup.getComponentCount()-1)
        .setFont(new Font("Georgia", Font.ITALIC, 20));

change the default font, not working for me

     import javax.swing.plaf.*;
     ...
     UIManager.put("PopupMenu.font", 
       new FontUIResource(Font.SERIF, Font.PLAIN, 20));

if (children == null) return 0;
PopupMenu.actionMap ActionMap PopupMenu.background Color PopupMenu.border Border PopupMenu.consumeEventOnClose Boolean PopupMenu.font Font PopupMenu.foreground Color PopupMenu.popupSound String PopupMenu.selectedWindowInputMapBindings Object[ ] PopupMenu.selectedWindowInputMapBindings.RightToLeft Object[ ] PopupMenuSeparatorUI String PopupMenuUI String

Adding Items To A Jpopupmenu ‹↑›

There are many different ways to add JMenuItems or other elements to a popup menu.

We can add items explicitly to a JPopupMenu by creating JMenuItems and using the add() method of the popup menu. Another alternative is to add Actions directly to the JPopupMenu. The menu extracts the information which it needs to create the JMenuItems (implicitly) from the Action properties (name, description, icon etc). Also, strings can be added directly to the menu

place any sort of component in a JPopupMenu with insert

 public void insert(Component component, int index)

Strangely the add() methods dont support adding any sort of Component but insert() does.

add a JTextField as the third element in a JPopupMenu

   import java.awt.event.*;
   import java.awt.*;
   import javax.swing.*;
   import javax.swing.event.*;
   
   public class TextFieldPopup extends JPanel 
   implements ActionListener, MouseListener {
     JPopupMenu popup;
     JLabel label;

     public TextFieldPopup() {
       super(new BorderLayout());
       this.label = new JLabel("info");
       this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.popup = new JPopupMenu();
       JMenuItem item;
       for (String s: new String[]{"oak", "yew", "elm", "tree"}) {
         popup.add(item = new JMenuItem(s));
         item.addActionListener(this);
         item.setFont(new Font("Georgia", Font.ITALIC, 20));
       }
       popup.insert(new JTextField("type here"), 2);
       this.addMouseListener(this);
       this.add(this.label, BorderLayout.NORTH);
     }
     public void actionPerformed(ActionEvent event) {
       this.label.setText(String.format(
         "menu item '%s' was clicked", event.getActionCommand()));
     }
   
     public void mouseExited(MouseEvent e) { }
     public void mouseEntered(MouseEvent e) { }
     public void mousePressed(MouseEvent e) { checkPopup(e); }
     public void mouseClicked(MouseEvent e) { checkPopup(e); }
     public void mouseReleased(MouseEvent e) { checkPopup(e); }
     private void checkPopup(MouseEvent e) {
       if (e.isPopupTrigger()) {
         popup.show(this, e.getX(), e.getY());
       }
     }
     
     public static void main(String s[]) {
       JFrame f = new JFrame("JPopupMenu example");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setContentPane(new TextFieldPopup()); f.pack();
       f.setSize(300, 300); f.setVisible(true);
     }
   }

Events And The Jpopupmenu ‹↑›

JPopupMenus have 3 classes of events associated with them. The mouse events which are captured to show the menu; the click events which select an item in the menu; and the menu showing and disappearing events.

 popup.addPopupMenuListener(new PopupMenuListener());

an example using a JPopupMenu and a PopupMenuListener

   import java.awt.event.*;
   import java.awt.*;
   import javax.swing.*;
   import javax.swing.border.BevelBorder;
   import javax.swing.event.*;
   
   public class PopupListener extends JPanel implements ActionListener {
     JPopupMenu popup;
     JLabel label;
     public PopupListener() {
       super(new BorderLayout());
       this.label = new JLabel("info");
       this.popup = new JPopupMenu();
       JMenuItem item;
       for (String s: new String[]{"oak", "yew", "elm", "tree"}) {
         popup.add(item = new JMenuItem(s));
         item.addActionListener(this);
         item.setFont(new Font("Georgia", Font.ITALIC, 20));
       }
       popup.addPopupMenuListener(new PopupPrintListener());
       this.addMouseListener(new MousePopupListener());
       this.add(this.label, BorderLayout.NORTH);
     }
   
     public void actionPerformed(ActionEvent event) {
       this.label.setText(String.format(
         "Popup menu item [%s] was pressed.", event.getActionCommand()));
     }
     class MousePopupListener extends MouseAdapter {
       public void mousePressed(MouseEvent e) { checkPopup(e); }
       public void mouseClicked(MouseEvent e) { checkPopup(e); }
       public void mouseReleased(MouseEvent e) { checkPopup(e); }
   
       private void checkPopup(MouseEvent e) {
         if (e.isPopupTrigger()) {
           popup.show(PopupListener.this, e.getX(), e.getY());
         }
       }
     }
   
     // show when popup events occur
     class PopupPrintListener implements PopupMenuListener {
       public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
         System.out.println("Popup menu will be visible!");
       }
       public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
         System.out.println("Popup menu will be invisible!");
       }
       public void popupMenuCanceled(PopupMenuEvent e) {
         System.out.println("Popup menu is hidden!");
       }
     }
     public static void main(String s[]) {
       JFrame frame = new JFrame("JPopupMenu example");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setContentPane(new PopupListener());
       frame.setSize(300, 300); frame.setVisible(true);
     }
   }

Gotchas For The Jpopupmenu ‹↑›

JTextComponents such as JTextArea seem to consume mouseclicks, so you need to add the MouseListener to the JTextComponent itself rather than its parent container.

Actions And Menus ‹↑›

If we add Actions directly to the JMenu, we dont have to create JMenuItems; the Action does all the work of providing text and possibly an icon and also an action for the JMenuItem.

test out the default actions for a text area by building a menu

   import javax.swing.*;
   public class TextAreaActions {
     public static void main(String[] args) {
       JTextArea ta = new JTextArea();
       ta.setLineWrap(true);
   
       Action[] actions = ta.getActions();
       JMenuBar menubar = new JMenuBar();
       JMenu actionmenu = new JMenu("Actions");
       menubar.add(actionmenu);
   
       JMenu firstHalf = new JMenu("1st Half");
       JMenu secondHalf = new JMenu("2nd Half");
       actionmenu.add(firstHalf);
       actionmenu.add(secondHalf);
       int mid = actions.length / 2;
       for (int i = 0; i < mid; i++) {
         firstHalf.add(actions[i]);
       }
       for (int i = mid; i < actions.length; i++) {
         secondHalf.add(actions[i]);
       }
       JFrame f = new JFrame("Default Actions for JTextArea");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.getContentPane().add(ta); f.setJMenuBar(menubar);
       f.setSize(300, 200); f.setVisible(true);
     }
   }

Textareas have a 'dump-model' default action which is interesting.

The code below shows and easy way to create a menu of actions, this can be used to test the default actions for a JTextComponent.

add some custom actions and some defaulteditorkit actions to a menu

   JMenu menu = new JMenu("Edit");
   //the actions below extend AbstractAction
   undoAction = new UndoAction();
   menu.add(undoAction);
   redoAction = new RedoAction();
   menu.add(redoAction);
   menu.addSeparator();
   
   menu.add(getActionByName(DefaultEditorKit.cutAction));
   menu.add(getActionByName(DefaultEditorKit.copyAction));
   menu.add(getActionByName(DefaultEditorKit.pasteAction));
   
   JMenuBar mb = new JMenuBar();
   mb.add(menu);
   jframe.setJMenuBar(mb);

if we dont use Actions we have to create menu items and then attached event listeners to each of them.

    frame = new JFrame("Java Menubar Example");
    // build the Edit menu
    editMenu = new JMenu("Edit");
    cutMenuItem = new JMenuItem("Cut");
    cutMenuItem.addActionListener(this);
    copyMenuItem = new JMenuItem("Copy");
    copyMenuItem.addActionListener(this);
    editMenu.add(cutMenuItem);
    editMenu.add(copyMenuItem);
    JMenuBar menuBar = new JMenuBar();
    menuBar.add(editMenu);
    // put the menubar on the frame
    frame.setJMenuBar(menuBar);

Jtooltips ‹↑›

Tooltips, known by various other names, are little boxes that can pop up when the user places a pointing device (ok, lets just call it a mouse) over a component in a user-interface. The tooltip could also be triggered by other user actions. In java this functionality is provided by the javax.swing.JToolTip class.

Tool-tips are actually very useful as a user-help feature, since they are an unobtrusive and context-sensitive way to give the user information about the interface when he or she wants it. Also they fit reasonably well with touch-screen devices where the human finger replaces the mouse as the 'pointing device'

http://www.javarichclient.com/how-to-create-a-callout-border/ a nice baloon label, using a custom border with a JLabel, rounded corners and a triangle arrow. This can be used as a tool tip replacement.

turn off the tooltip for JComponent 'c'

 c.setToolTipText(null);

If the method below returns null, the swing system will determine the location of the tooltip

override this method to determine the location of the tooltip

 Point getToolTipLocation(MouseEvent)

set tooltips on jbuttons

   import javax.swing.*;
   import java.io.File;
   public class TipPanel extends JPanel {
     public TipPanel() {
       super(new java.awt.GridLayout(0,2));
       for (File f: new File(".").listFiles()) {
         JButton b = new JButton(f.getName());
         b.setToolTipText("File length: " + f.length());
         this.add(b);
       }
     } 
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new TipPanel());
         }
       });
     }
   }

Appearance Of Jtooltip ‹↑›

Look and Feel UIManager properties for JPopupMenu

list all look-and-feel keys and values which relate to ToolTips

   import javax.swing.*;
   public class ToolTipDefaults {
     public static void main(String[] args) {
       java.util.Enumeration keys = UIManager.getDefaults().keys();
       while (keys.hasMoreElements()) {
         String key = keys.nextElement().toString();
         if (key.startsWith("ToolTip")) { 
           System.out.println(key);
           Object value = UIManager.get(key);
           //String name = value.getClass().getName();
           System.out.println("  " + value);
         }
       }
     }
   }

In the example below the background painting of the tooltip does not suit the RoundedBorder because the background is a normal rectangle and the RoundedBorder paints a RoundedRectangle, so that the background extends outside of the Border.

set a new Font and a custom RoundedBorder for JToolTips on JButtons

   import javax.swing.*;
   import javax.swing.plaf.*;
   import java.io.File;
   import java.awt.*;
   public class TipPanel extends JPanel {
     public TipPanel() {
       super(new java.awt.GridLayout(0,2));
       Font font = new Font("Georgia", Font.ITALIC, 20);
       UIManager.put("ToolTip.font", new FontUIResource(font));
       UIManager.put("ToolTip.border", new RoundedBorder());
       for (File f: new File(".").listFiles()) {
         JButton b = new JButton(f.getName());
         b.setToolTipText("File length: " + f.length());
         this.add(b);
       }
     } 
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JOptionPane.showMessageDialog(null, new TipPanel());
         }
       });
     }
   }

Idea set a translucent color for the background of a tooltip, but the tooltip seems to be alway opaque, so this doesnt work

 Color translucentRed = new Color(150, 0, 0, 0);

Custom Tooltip ‹↑›

http://rcforte.wordpress.com/2010/10/10/custom-jtooltip/ a complete example of creating a multicomponet jtooltip

To create a custom JToolTip, override JComponent.createToolTip() and use a subclass of JToolTip.

the basic skeleton for creating a custom JToolTip

   checkBox = new JCheckBox() {
     @Override
     public JToolTip createToolTip() {
       System.out.println("creating tip");
       return new ImageToolTip(m.getImage());
     }
   };

customise a jtooltip by anonymously subclassing JButton

   import javax.swing.*;
   public class TipButton {
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JButton b = new JButton("Anonymous JButton") {
             public JToolTip createToolTip() {
               JToolTip tip = super.createToolTip();
               tip.setBackground(java.awt.Color.yellow);
               return tip;
             }
           };
           b.setToolTipText("custom tool tip");
           JOptionPane.showMessageDialog(null, b);
         }
       });
     }
   }

In the example below, there are 2 interesting points: that the setToolTipText() method actually triggers the creation of the tooltip (and hence fires the createToolTip() method) and secondly that the text set within the createToolTip() method for the tooltip is ignored, or rather gets overwritten.

override the createToolTip method to install a custom JToolTip

   import javax.swing.*;
   public class TipBox extends JCheckBox {
     public TipBox(String s) { super(s); }
     @Override
     public JToolTip createToolTip() {
       System.out.println("creating custom tooltip");
       JToolTip tt = new JToolTip(); 
       tt.setTipText("this text is ignored");
       return tt;
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           TipBox t = new TipBox("tip box"); 
           t.setToolTipText("hi");
           JOptionPane.showMessageDialog(null, t);
         }
       });
     }
   }

To just use the standard (rather ugly) java tool-tip, call component.setToolTipText("help text") on any swing component.

Multicomponent Jtooltip ‹↑›

If you want to do something fancy you may want to display many components in your JToolTip, here is how. The following example seems to work but the m_ coding style is bizarre.

a multi-component JToolTip example (by rcforte)

   import java.awt.BorderLayout;
   import java.awt.Dimension;
   import java.awt.EventQueue;
   import javax.swing.JButton;
   import javax.swing.JFrame;
   import javax.swing.JLabel;
   import javax.swing.JPanel;
   import javax.swing.JToolTip;
   
   public class CustomTooltipSample extends JFrame {
     private CustomLabel m_label;
   
     public CustomTooltipSample() {
       setTitle("Custom tooltip sample");
       setSize(300, 200);
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       m_label = new CustomLabel("My Label");
       m_label.setToolTipText("Yo, I am a tooltip with components!"); // activate tooltips for this component
       add(m_label);
     }
   
     public static void main(String[] args) {
       EventQueue.invokeLater(new Runnable() {
         @Override public void run() {
           JFrame frame = new CustomTooltipSample();
           frame.setVisible(true);
         }
       });
     }
   
     private static class CustomLabel extends JLabel {
       private CustomTooltip m_tooltip;
       public CustomLabel(String text) { super(text); }
       @Override public JToolTip createToolTip() {
         if (m_tooltip == null) {
           m_tooltip = new CustomTooltip();
           m_tooltip.setComponent(this);
         }
         return m_tooltip;
       }
     }
   
     private static class CustomTooltip extends JToolTip {
       private JLabel m_label;
       private JButton m_button;
       private JPanel m_panel;
       public CustomTooltip() {
         super();
         m_label = new JLabel();
         m_button = new JButton("See, I am a button!");
         m_panel = new JPanel(new BorderLayout());
         m_panel.add(BorderLayout.CENTER, m_label);
         m_panel.add(BorderLayout.SOUTH, m_button);
         setLayout(new BorderLayout());
         add(m_panel);
       }
   
       @Override public Dimension getPreferredSize() {
         return m_panel.getPreferredSize();
       }
   
       @Override public void setTipText(String tipText) {
         if (tipText != null && !tipText.isEmpty()) {
           m_label.setText(tipText);
         } else {
           super.setTipText(tipText);
         }
       }
     }
   }

Location Specific Tooltip ‹↑›

subclass and JComponent and override getToolTipText(MouseEvent)

Tooltipmanager ‹↑›

books.google.com.au/books?isbn=1590594479 page 84 a book with good info

The manager controls delay of appearance and such things.

disable all tooltips

 ToolTipManager.sharedInstance().setEnabled(false);

Mouse ‹↑›

The venerable 'mouse' is a pointing device. The mouse interface techniques are worth learning since they are easily translated to more modern world of touch screens, tablet computer and 'smart' phones.

Mouseevents And Mouselisteners ‹↑›

Mouselisteners ‹↑›

The java.awt.event.MouseListener listens for mouse clicks, presses and releases. The MouseEvent contains information about where the mouse was clicked. The x and y coordinates of the mouse click will probably be relative to the Component or JComponent on which the MouseListener was registered with the addMouseListener() method.

check if the left mouse button was clicked

 if (SwingUtilities.isLeftMouseButton(ev)) {...}

add a mouselistener to a jtextarea, only listens for clicks

   textArea.addMouseListener(new MouseAdapter() {
     @Override
     public void mouseClicked(MouseEvent e) {
       if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 1) {
         // do something here
       }
     });

a simple mouseadaptor example (the label doesnt block the clicks)

  import javax.swing.*;
  import java.awt.BorderLayout;
  import java.awt.event.*;
  public class LabelOnPanel {
    public static void main(String[] args) {
      final JPanel mainPanel = new JPanel(new BorderLayout());
      mainPanel.add(new JLabel(
        "This is a JLabel covering the entire panel"));
      mainPanel.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
          JOptionPane.showMessageDialog(mainPanel, "Panel received click");
        }
      });
      JFrame frame = new JFrame("Testing mouse clicks on a panel");
      frame.setBounds(100, 100, 300, 300);
      frame.add(mainPanel, BorderLayout.CENTER);
      frame.setVisible(true);
    }
  }

Mousemotionlisteners ‹↑›

The java.awt.event.MouseMotionListener as its name states clearly, listens for movement of the mouse, rather than clicks or presses.

add a mousemotionlistener to a JPanel

     jpanel.addMouseMotionListener(new MouseMotionAdapter() {
       public void mouseDragged(MouseEvent evt) { ...  }
     });

Cursor ‹↑›

The cursor is the small icon which indicates the position of the mouse. The cursor is set for a particular (swing) component, and all the components contained in that component. In a swing text component the 'cursor' (usually a little flashing vertical line) is referred to as the 'caret'

set the cursor to a wait symbol when it is over the container

 component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

set the cursor

 setCursor (Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

set cursor to an image icon

    Toolkit toolkit = Toolkit.getDefaultToolkit();
    Image image = toolkit.getImage("icons/handwriting.gif");
    Cursor c = toolkit.createCustomCursor(
      image, newPoint(mainPane.getX(), mainPane.getY()), "img");
    mainPane.setCursor(c);

set the cursor for the root pane

 frame.getRootPane().setCursor(...);

Calendars ‹↑›

java.util.Calendar and java.util.Timezone are useful classes for getting information about times and dates. The Calendar class seems to have a bad reputation for being confusing. The Android api reimplements the Calendar class.

use some methods of the Calendar class

    Calender c = Calendar.getInstance();
    miliSecond = c.get(Calendar.MILLISECOND);
    second = c.get(Calendar.SECOND);
    minute = c.get(Calendar.MINUTE);
    hour = c.get(Calendar.HOUR_OF_DAY);
    dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
    dayOfYear = c.get(Calendar.DAY_OF_YEAR);
    dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
    month = c.get(Calendar.MONTH);
    daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH);
    daysInYear = c.getActualMaximum(Calendar.DAY_OF_YEAR);

print the current date and time as a 'formatted' string

     import java.util.Calendar;
     public class PrintTime {
       public static void main(String[] args) {
         System.out.println("Time: " + Calendar.getInstance().getTime());
       }
     }

Dates ‹↑›

Apparently JodaTime should be used instead of the standard java classes.

The 'epoch' which is midnight 1 jan 1970 UTC is important in some date and time manipulations.

convert miliseconds since the 'epoch' (midnight 1 jan 1970) to readable

   import java.util.Calendar;
   public class EpochTime {
     public static void main(String[] args) {
       Calendar cal = Calendar.getInstance();
       cal.setTimeInMillis(System.currentTimeMillis());
       //String dateStr = String.format("%tc", cal);
       System.out.format("%tc", cal);
     }
   }

parse a string into a date using a SimpleDateFormat

   SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
   try {
     final Date date = parser.parse(dateString);
     System.out.println(integer + " -> " + date);
   } catch (final ParseException pe) {
     System.err.println("bad date: " + dateString + ": " + pe);
   }

The example below does not consider if the start and end dates are included in the calculation.

get the number of days between to dates

   import java.util.*;
   public class DayDiff {
     public static void main(String[] args) {
       GregorianCalendar cal1 = new GregorianCalendar(2012,7,17);
       GregorianCalendar cal2 = new GregorianCalendar(2012,10,21);
       long ms1 = cal1.getTime().getTime();
       long ms2 = cal2.getTime().getTime();
       long difMs = ms2-ms1;
       long msPerDay = 1000*60*60*24;
       double days = difMs / msPerDay;
       //System.out.format("number of days: %g", days);
       System.out.println(days);
     }
   }

Time ‹↑›

getLocale() ?? below

create a readable date format for this local and get the current time

   import java.text.DateFormat;
   import java.util.Date;
   public class TimerTest {
     public static void main(String[] args) {
       DateFormat f =
         DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale());
       String s = f.format(new Date());
     }
   }
   

get the current time in nanoseconds

 long lastTime = System.nanoTime();

get the current time in milli seconds

 long startTime = System.currentTimeMillis();

a simple way to find out roughly how long some code takes

   long startTime = System.currentTimeMillis();
   // ... code that takes time
   long endTime = System.currentTimeMillis();
   jframe.setTitle("took " + (endTime - startTime) + " ms");

Timers ‹↑›

A javax.swing.Timer can be used to execute an action periodically. They are said to be superior to using a technique such as 'Thread.sleep()'

use a timer to update the text of a label each second

   import java.awt.*;
   import java.awt.event.ActionEvent;
   import java.awt.event.ActionListener;
   import javax.swing.*;
   public class TimerTest {
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           final JLabel label = new JLabel("Timed Label");
           ActionListener listener = new ActionListener() {
             @Override
             public void actionPerformed(ActionEvent ae) {
               label.setText(String.valueOf(System.nanoTime()));
               label.repaint();
             }
           };
        Timer timer = new Timer(1000, listener);
        timer.start();
        JOptionPane.showMessageDialog(null, label);
      }

     });
    }
  }

use a timer to change the color of textfield text every second


   import java.awt.Color;
   import java.awt.event.ActionEvent;
   import java.awt.event.ActionListener;
   import javax.swing.*;

   public class BlinkColorTextField {
    BlinkColorTextField() {
        final JTextField blinkingText = new JTextField("Red & Blue");
        ActionListener blinker = new ActionListener() {
            boolean isRed = true;
            public void actionPerformed(ActionEvent ae) {
                if (isRed) {
                    blinkingText.setForeground(Color.BLUE);
                } else {
                    blinkingText.setForeground(Color.RED);
                }
                isRed = !isRed;
            }
        };
        Timer timer = new Timer(1000, blinker);
        timer.start();
        JOptionPane.showMessageDialog(null, blinkingText);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new BlinkColorTextField();
            }
        });
    }
  }

add a word to a JTextArea one per second

   ActionListener l = new ActionListener() {
     @Override
     public void actionPerformed(...) {
       textArea.append(words.remove(0));
     }
   };
   Timer timer = new Timer(1000, l);
   timer.start();

Events And Listeners ‹↑›

Events in java are any type of user input action or change of computer state. These events are fired (create event objects) and can be listened to by other objects. The listener is responsible for doing something when the event occurs.

There are always 2 steps to set up a Listener to react when a certain event occurs. 1. Implement the Listener interface or extend the Adapter class. 2. Attach the Listener to the component you want to listen to with the method component.add?Listener where the ? symbol stands for the type of Listener you are using (eg ActionListener, PropertyChangeListener etc)

Propertychangelisteners And Propertychangeevents ‹↑›

A Java bean (such as Swing Components) may have certain bound variables. These variables can be listened to for changes by a PropertyChangeListener.

Only one method is required to implement the PropertyChangeListener interface, namely propertyChange(...). In the example below, the name of the bound variable in the javabean object is 'progress'

an example of a propertyChange() method

   public class Example implements PropertyChangeListener {
     ...
     javabean.addPropertyChangeListener(this);
     ...
     public void propertyChange(PropertyChangeEvent e) {
       if ("progress" == e.getPropertyName()) {
         int progress = (Integer) e.getNewValue();
         jprogressbar.setValue(progress);
       }
     }
   }

Actionlisteners And Actionevents ‹↑›

A button which beeps when clicked

  import java.awt.*;
  import javax.swing.*;
  import java.awt.Toolkit;
  import java.awt.BorderLayout;
  import java.awt.event.ActionListener;
  import java.awt.event.ActionEvent;
   
  public class Beeper extends JPanel implements ActionListener {
    JButton button;
    public Beeper() {
        super(new BorderLayout());
        button = new JButton("Beep Button");
        button.setPreferredSize(new Dimension(200, 80));
        add(button, BorderLayout.CENTER);
        button.addActionListener(this);
    }
 
    public void actionPerformed(ActionEvent e) {
        Toolkit.getDefaultToolkit().beep();
    }
 
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
              JFrame frame = new JFrame("Beeper");
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              JComponent newContentPane = new Beeper();
              newContentPane.setOpaque(true); 
              frame.setContentPane(newContentPane);
              frame.pack();
              frame.setVisible(true);
            }
        });
      }
    }

Keylisteners Keyadapters And Key Stroke Events ‹↑›

Keystroke events occur when the user types, presses or releases keyboard keys.

uimanager properties for JToolTip
ToolTip.background - Color
ToolTip.backgroundInactive - Color
ToolTip.border - Border
ToolTip.borderInactive - Color
ToolTip.font - Font
ToolTip.foreground - Color
ToolTip.foregroundInactive - Color
ToolTip.hideAccelerator - Boolean
ToolTipUI - String

For information on DocumentListeners see the section in JTextComponents.

KeyListeners do not seem to 'consume' the keystroke. That is the same key stroke will be passed to any parent components which are also listening for keystrokes. So if you put a JTextField in a JOptionPane.showMessageDialog() and listen for ActionEvents on the JTextField, the message dialog will exit after the event is handled by the ActionListener.

Keyadapter ‹↑›

A KeyAdapter is an abstract class which implements the KeyListener interface. The only advantage of using a KeyAdapter as opposed to a KeyListener is that you do only have to implement the method which is of interest. In other words if you are only interested in reacting to keyTyped() events and not keyPressed() or keyReleased() then you just implement keyTyped(). This is really not a big advantage- it only saves you 2 lines of code.

listen to any printable keystroke and show the combobox popupmenu

   JComboBox cb = new JComboBox(items);
   cb.addKeyListener(new MyKeyListener());
   class MyKeyListener extends KeyAdapter {
     public void keyPressed(KeyEvent evt) {
       JComboBox cb = (JComboBox)evt.getSource();
       char ch = evt.getKeyChar();
       // If not a printable character, do nothing
       if (ch != KeyEvent.CHAR_UNDEFINED) {
         cb.showPopup();
       }
     }
   }

Keyevents ‹↑›

KeyEvents are fired by user keystrokes and are processed by KeyListeners.

show a text representation of the key typed

    public void keyTyped(KeyEvent e) {
      String s = e.getKeyText(e.getKeyCode());
    }

Keystrokes ‹↑›

Java has a class call javax.swing.KeyStroke that allows you to specify keystrokes to bind to actions (see 'keybindings').

There are various ways to specify keystrokes, using strings in a particular format or virtual key specifiers. If using strings the modifier keys must be in lower case, and the key itself in upper case.

different ways to react to keystrokes
use mnemonics and shortcut keys on JComponents
use ActionMap and InputMap to make keybindings (since 1.3)
implement a KeyListener -
extend a KeyAdapter - this is almost the same as KeyListener
use a DocumentListener on a JTextComponent

see also KeyMap

specify the 'control b' keystrokes

  KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK);

specify shift + '-' keystroke in an InputMap

 inputmap.put(KeyStroke.getKeyStroke("shift MINUS"), "x.bigger.font");

specify control a

    KeyStroke controlA = KeyStroke.getKeyStroke(
      KeyEvent.VK_A, InputEvent.CTRL_MASK);   

make the escape key put a text component into read only mode

 inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "set-read-only");

Keymaps ‹↑›

KeyMaps are older than InputMap and ActionMaps, and probably InputMaps are the preferred method for creating keybindings. This is because the Input/ActionMap system has a level of 'indirection', that is, KeyStrokes are bound to a (String) key in the InputMap, which is then bound to the same string key in the ActionMap.

http://www.java2s.com/Code/JavaAPI/javax.swing/JTextAreagetActions.htm create a custom TextAction and install it with a KeyMap

install a new keymap that has all the functionality of default keymap

    JTextField field = new JTextField();
    Keymap laf = field.getKeymap();
    Keymap myMap = JTextComponent.addKeymap(null, laf);
    myMap.addActionForKeyStroke(
      getKeyStroke(VK_PERIOD, SHIFT_DOWN_MASK), myAction);
    field.setKeymap(myMap);

make control L select the current line using a KeyMap

   import javax.swing.*;
   import javax.swing.text.*;
   import java.util.Hashtable;
   import java.awt.event.*;
   import java.awt.BorderLayout;
   
   public class KeymapExample {
     public static void main(String[] args) {
       JTextArea area = new JTextArea(6, 32);
       Keymap parent = area.getKeymap();
       Keymap newmap = JTextComponent.addKeymap("KeymapExampleMap", parent);
       KeyStroke u = 
         KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.CTRL_MASK);
       Action actionU = new UpWord();
       newmap.addActionForKeyStroke(u, actionU);
   
       Action actionList[] = area.getActions();
       Hashtable lookup = new Hashtable();
       for (int j=0; j < actionList.length; j+=1)
         lookup.put(actionList[j].getValue(Action.NAME), actionList[j]);
       KeyStroke L = 
         KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_MASK);
       Action actionL = 
         (Action)lookup.get(DefaultEditorKit.selectLineAction);
       newmap.addActionForKeyStroke(L, actionL);
       KeyStroke W = KeyStroke.getKeyStroke(
         KeyEvent.VK_W, InputEvent.CTRL_MASK);
       Action actionW = (Action)lookup.get(DefaultEditorKit.selectWordAction);
       newmap.addActionForKeyStroke(W, actionW);
       area.setKeymap(newmap);
       JFrame f = new JFrame("KeymapExample");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.getContentPane().add(new JScrollPane(area), BorderLayout.CENTER);
       area.setText("www.\n java2s \n .com.");
       f.pack();
       f.setVisible(true);
     }
     public static class UpWord extends TextAction {
       public UpWord() {
         super("uppercase-word-action");
       }
   
       public void actionPerformed(ActionEvent e) {
         JTextComponent comp = getTextComponent(e);
         if (comp == null) return;
         Document doc = comp.getDocument();
         int start = comp.getSelectionStart();
         int end = comp.getSelectionEnd();
         try {
           int left = javax.swing.text.Utilities.getWordStart(comp, start);
           int right = javax.swing.text.Utilities.getWordEnd(comp, end);
           String word = doc.getText(left, right-left);
           doc.remove(left, right-left);
           doc.insertString(left, word.toUpperCase(), null);
           comp.setSelectionStart(start); // restore previous position/selection
           comp.setSelectionEnd(end);
         } catch (BadLocationException ble) {
           return;
         }
       }
     }
   }

Keybindings ‹↑›

Keybindings are a way of associating keystrokes with Actions via the 3 InputMaps and the ActionMap.

Keybindings have several big advantages. Firstly the action associated with the keybinding can be activated (shared) by other interface components such a JButtons or JMenuItems. Secondly the Swing components already have many default Actions which the programmer may be able to reuse without creating a new Action. The only real difficulty is finding the default (String) action name, so that it can be associated with a new keystroke. Also the element with the keybinding does not necessarily have to have focus in order for the binding to work.

Key bindings are a slightly lower level interface than Keyboard Memonics for triggering events. Swing components have an ActionMap and an InputMap which can be used to bind keystrokes to Actions.

Many swing components already have keybindings established for them. For example the JList binds the up and down arrows to move the selected item up and down. The programmer can add to or modify these preset bindings, if she feels that it will enhance the functionality of the component.

www: http://java.sun.com/docs/books/tutorial/uiswing/misc/keybinding.html
The Sun tutorial on using keybindings
www: http://tips4java.wordpress.com/2008/10/10/key-bindings/
An application and post by rob camick which shows keybindings
Valid ways to specify keystrokes
KeyStroke.getKeyStroke("control Z") -
KeyStroke.getKeyStroke("ESCAPE")
KeyStroke.getKeyStroke((char)KeyEvent.VK_SLASH) - slash '/'
KeyStroke.getKeyStroke('/')

return the 'when focused' input map for a component

 c.getInputMap()

The code below may well fail if some input keys have no action defined for them. Also, it uses keys() not allKeys() so it only retrieves the keys defined in the current input map not its parents.

returns an html list of keystrokes and actions defined

    public String keyStrokeHelp() {
      InputMap im = jtextarea.getInputMap(WHEN_FOCUSED);
      ActionMap am = jtextarea.getActionMap();
      StringBuilder sb = new StringBuilder();
      sb.append("<h3>keystrokes and actions</h3>");
      sb.append("<dl>");
      for (KeyStroke key: im.keys()) {
        String actionKey = (String)im.get(key); 
        Action action = am.get(actionKey);
        sb.append(String.format("<dt>%s<dd>%s", 
          key.toString(), action.getValue(Action.SHORT_DESCRIPTION)));
      }
      sb.append("</dl>");
      return sb.toString();
    }

We link together the InputMaps and the ActionMaps with a string key which can describe the keystroke, or describe the action (better) or be any old unique string.

make control-a select all text in a JTextField when it is focussed

    JTextField field = new JTextField("hello");
    Action action = new AbstractAction() {
      public void actionPerformed(ActionEvent e) {
        System.out.println("selecting all text");
        // code to select all text in the JTextField
      }
    };
    KeyStroke keyStroke = KeyStroke.getKeyStroke("control A");
    field.getInputMap(WHEN_FOCUSED).put(keyStroke, "select-all");
    field.getActionMap().put("select-all", action);

make 'control b' go back one character using a default editor action

   InputMap inputMap = textPane.getInputMap();
   KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK);
   inputMap.put(key, DefaultEditorKit.backwardAction);

replace the Action of an existing key binding

    Action action = new AbstractAction() {...};
    KeyStroke keyStroke = KeyStroke.getKeyStroke("control Z");
    InputMap im = component.getInputMap(...);
    component.getActionMap().put(im.get(keyStroke), action);

In the code below, control-z will now do whatever it is that <enter> does

share an Action with a different KeyStroke

    InputMap im = component.getInputMap(WHEN_IN_FOCUSED_WINDOW);
    im.put(KeyStroke.getKeyStroke("control Z"), 
           im.get(KeyStroke.getKeyStroke("ENTER"));

remove the default key binding for up-arrow, when component is focussed

    InputMap im = component.getInputMap(JComponent.WHEN_FOCUSED);
    im.put(KeyStroke.getKeyStroke("UP"), "none");

To add a keybinding to a JFrame or Dialog you need to use the RootPane.

get the ActionMap of the application RootPane

   frame.getRootPane()
    .getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)...
   frame.getRootPane().getActionMap()...

add arrow key scrolling in a scrollpane with default actions

     JScrollPane scroll = new JScrollPane(jpanel);
     JScrollBar vertical = scroll.getVerticalScrollBar();
     InputMap im = vertical.getInputMap(
       JComponent.WHEN_IN_FOCUSED_WINDOW);
     im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
     im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");

In the keystroke below the word 'shift' has to be lower case

bind shift-j (capital letter J) to move a page down a scrollbar

 im.put(KeyStroke.getKeyStroke("shift J"), "positiveBlockIncrement");

another way to specify the 'control A' key stroke

     KeyStroke controlA = 
        KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK);   

an example of linking keystrokes to actions

   import java.awt.event.*;
   import javax.swing.*;
   public class KeyStrokeTest {
     public static void main(String[] args) {
       JPanel panel = new JPanel();
       panel.getActionMap().put("hello", new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
           System.out.println("hello keystrokes");
         }
       });
       // connect two keystrokes with the "hello" action:
       InputMap inputMap = panel.getInputMap();
       inputMap.put(KeyStroke.getKeyStroke("A"), "hello");
       inputMap.put(KeyStroke.getKeyStroke("control A"), "hello");
       JFrame frame = new JFrame();
       frame.getContentPane().add(panel);
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setSize(400, 400);
       frame.setVisible(true);
     }
   }

Using a JOptionPane for this example doesnt seem to work. Maybe the option pane doesnt handle the events ....

Default Keybindings ‹↑›

Swing provides many default keybinding for JComponents such as JTextAreas, JLists and also the default actions to be executed. Modifying these defaults can save the programmer a great deal of work when customizing a swing component.

The default keybindings for swing components are usually associated with the WHEN_FOCUSED InputMap.

www: http://tips4java.wordpress.com/2008/10/10/key-bindings/
An application which shows default keybindings for JComponents

Gotchas For Keybindings ‹↑›

Some key-binding are used by the operating system (eg control-C) and cannot be bound to a java Action

no, no, no. The following probably wont work

    ActionMap actionMap = jcomponent.getActionMap();
    InputMap inputMap = jcomponent.getInputMap(JComponent.WHEN_FOCUSED);
    inputMap.put(KeyStroke.getKeyStroke("control C"), "cancel-search");
    actionMap.put("cancel-search", new CancelSearchAction());

Default Actions ‹↑›

All the JTextComponents contain a set of useful default actions which can be used to implement editing functions.

The short description and long description fields for text component default actions appear to be null.

one way to list all default actions for a JTextComponent

   import javax.swing.text.JTextComponent;
   import javax.swing.Action;
   import java.util.*;
   public class TextComponentActions {
     public static void main(String[] args) throws Exception {
       Object o = Class.forName("javax.swing.JTextArea").newInstance();
       JTextComponent t = (JTextComponent)o;
       Action[] actions = t.getActions();
       //Arrays.sort(actions);
       for (Action a: actions) {
         System.out.println(a.getValue(Action.NAME));
       }
     }
   }

display default actions for a JTextArea in JLabels

   import javax.swing.text.JTextComponent;
   import javax.swing.*;
   import java.awt.*;
   public class DisplayActions extends JPanel {
     public DisplayActions() throws Exception {
       super(new GridLayout(0, 2));
       JLabel label = new JLabel(); 
       for (Action a: new JTextArea().getActions()) {
         label = new JLabel(a.getValue(Action.NAME).toString()); 
         label.setFont(new Font("Georgia", Font.ITALIC, 24));
         this.add(label); 
       }
     }
     public static void main(String[] args) throws Exception {
       JScrollPane p = new JScrollPane(new DisplayActions());
       JFrame f = new JFrame("JTextArea Default Actions");
       f.getContentPane().add(p);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);
       f.setVisible(true);
     }
   }

The following code shows all default actions which are defined for a particular JComponent. As we can see from the example, lots of useful actions are defined for the JTextArea. The following does not show what keys are bound to those actions (if any).

another way to show all actions which are defined for a swing component

   import javax.swing.*;
   import java.util.*;
   public class DefaultActions {
     public static void main(String[] args) throws Exception {
       Object o = Class.forName("javax.swing.JScrollBar").newInstance();
       JComponent component = (JComponent)o;
       ActionMap actionMap = component.getActionMap();
       Object[] keys = actionMap.allKeys();
       if  (keys == null) {
         System.out.println("No actions found");
         System.exit(0);
       }
       //  In some ActionMaps a key of type Object is found (why?) 
       //  causing a ClassCastException when sorting. 
       //  Convert these to a String
       for (int i = 0; i < keys.length; i++) {
         if (!(keys[i] instanceof String)) keys[i] = "[?]";
       }
       Arrays.sort(keys);
       for (Object action: keys) 
         if ((action != "") && (action instanceof String)) 
           System.out.println(action);
     }
   }

get an action by (string) name from a textarea

   final Action selectLine = getAction(
       textArea, DefaultEditorKit.selectLineAction);
   ...
   public static Action getAction(JTextArea textArea, String name) {
     Action action = null;
     Action[] actions = textArea.getActions();
     for (int i = 0; i < actions.length; i++) {
       if (name.equals(actions[i].getValue(Action.NAME).toString())) {
         action = actions[i];
         break;
       }
     }
     return action;
   }

list all actions for a jtextpane

    import java.util.Arrays;
    import java.util.Comparator;
    import javax.swing.Action;
    import javax.swing.JTextPane;
    import javax.swing.text.JTextComponent;

    public class ListActionsJTextPane {
      public static void main(String args[]) {
        JTextComponent component = new JTextPane();

        // Process action list
        Action actions[] = component.getActions();
        // Define comparator to sort actions
        Comparator<Action> comparator = new Comparator<Action>() {
          public int compare(Action a1, Action a2) {
            String firstName = (String) a1.getValue(Action.NAME);
            String secondName = (String) a2.getValue(Action.NAME);
            return firstName.compareTo(secondName);
          }
        };
        Arrays.sort(actions, comparator);

        int count = actions.length;
        System.out.println("Count: " + count);
        for (int i = 0; i < count; i++) {
          System.out.printf("%28s : %s\n",actions[i].getValue(Action.NAME),actions[i].getClass().getName());
        }
      }
    }

explicitly fire an actionperformed method but with no event object

 selectLine.actionPerformed(null);

Actions ‹↑›

Actions are a way of centralizing the action that is performed when the user interacts with a swing interface. The same action can be set on several gui components. When an action is added to a JComponent, the Action is added as an ActionListener for that component.

Get the 3 keybinding InputMaps associated with a JComponent.
c.getInputMap(JComponent.WHEN_FOCUSED); // the default InputMap
c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
c.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

If the same action is used on a JButton and JMenuItem, both will use the same 'shortcut' key combination and the short description as a tool tip. The text and icon will be used on both the menu item and the button.

Another advantage is that actions can be used in conjunction with keybindings, which is an easy way to modify the behavior of swing components. Finally actions can provide description of themselves allowing the developer to implement 'reflective' functionality.

Actions are usually created by subclassing the AbstractAction class

create an action which exits the application

   class ExitAction extends AbstractAction {
     public ExitAction() {
       putValue(Action.NAME, "Exit");
       putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
       putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
     }
     public void actionPerformed(ActionEvent e) {
       System.exit(0);
     }
   }

a quick way to configure a button to do something when clicked

   JButton button = new JButton(new AbstractAction("Close") {
     @Override
     public void actionPerformed(ActionEvent e) { System.exit(0); }
   });

create an action class with icon, text, tooltip and alt/shortcut key.

   leftAction = new LeftAction(
     "Go left", anIcon, "This is the left button.", new Integer(KeyEvent.VK_L));
   JButton test = new JButton(leftAction);
   class LeftAction extends AbstractAction {
     public LeftAction(String text, ImageIcon icon,
                       String desc, Integer mnemonic) {
       super(text, icon);
       putValue(Action.SHORT_DESCRIPTION, desc);
       putValue(Action.MNEMONIC_KEY, mnemonic);
     }
     public void actionPerformed(ActionEvent e) {
       displayResult("Action for first button/menu item", e);
     }
   }

In the code below, the braces {} with no method name is an anonymous constructor. This is a very odd java idiom.

another way to create a new Action using an anonymous class

   Action colourAction = new AbstractAction() {
     { putValue(Action.NAME, "Green On Black"); }
     public void actionPerformed(ActionEvent e)
     { /* do something */ }
   };

The strange curly braces without any method signature are actually a way to define the constructor within an anonymous inner class. How odd.

Actions consume KeyEvents (unlike KeyListeners which may or may not consume them)

jrootpane.setDefaultButton() make enter activate/click that button no matter where the focuss of the window is The actionEvent.getActionCommand() for a keybinding returns the keystroke

an actionlistener that listens to several JTextFields

    ActionListener commonListener = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();
        if (o instanceof JTextField) {
          JTextField textField = (JTextField)o;
          input[5] = textField.getText();
          textField.setVisible(true);
        }
      }
    };

getActionCommand() returns a string: for a JButton the text of the button or something specified with setActionCommand. For a JTextField, the text of the field

getSource() returns a reference to an object, must be cast. All EventObjects have getSource method

Cut And Paste ‹↑›

JTextComponents have default 'cut and paste' functionality usually activated with control-c and control-v or shift-insert and control-insert but JTextComponent dont, by default, have a right click pop up menu for copying or pasting text. See the JPopupMenu section for how to implement this functionality.

Clipboard ‹↑›

The term 'clipboard' refers to a facility provided by the operating system to allow data to be copied by the user from one application to another. Usually text data is copied, but other data types are usually supported, such as images. The data appears to be stored in a mime encoded format(?). The use of the clipboard often combines with 'drag-and-drop' features.

get text from the system clipboard (copy some text in another app)

   import java.awt.*;
   import java.awt.datatransfer.*;
   import java.io.*;
   public class ClipboardTest
   {
     public static void main(String[] args)
     throws UnsupportedFlavorException, IOException
     {
       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
       Transferable t = c.getContents(null);
       if ( t.isDataFlavorSupported(DataFlavor.stringFlavor) )
       {
         Object o = t.getTransferData(DataFlavor.stringFlavor);
         String data = (String)t.getTransferData(DataFlavor.stringFlavor);
         System.out.println("Clipboard contents: " + data);
       }
       System.exit(0);
     }
   }

copy a string to the system clipboard

    Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
    StringSelection testData = new StringSelection("Clipboard testing");
    c.setContents(testData, testData);

code which copies a string to and from the system clipboard

   import java.awt.*;
   import java.awt.datatransfer.*;
   import java.io.*;
   public class ClipboardTest {
     public static void main(String[] args)
     throws UnsupportedFlavorException, IOException
     {
       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
       StringSelection testData;
       //  Add some test data
       if (args.length > 0)
         testData = new StringSelection(args[0]);
       else
         testData = new StringSelection("Clipboard testing- cut and paste");
       c.setContents(testData, testData);
       //  Get clipboard contents, as a String
       Transferable t = c.getContents(null);
       if ( t.isDataFlavorSupported(DataFlavor.stringFlavor) )
       {
         Object o = t.getTransferData(DataFlavor.stringFlavor);
         String data = (String)t.getTransferData(DataFlavor.stringFlavor);
         System.out.println("Clipboard contents: " + data);
       }
       System.exit(0);
     }
   }

Drag And Drop ‹↑›

Drag-and-Drop ('DnD' or 'dnd') refers to moving components and data from one area in a java application to another, or moving the components from an external application into the java application or the reverse. This is achieved by using some kind of a 'gesture' with a pointing device, which means, in the usual case, clicking on a component, holding the left mouse button down, moving the mouse to the desired position and then releasing the mouse button.

Drag-and-drop is a very powerful facility to include in a java application because it mimics the way that human beings naturally and intuitively manipulate objects. DnD is also important because of the proliferation of 'touch-screen' devices ('tablet' computers, 'smart-phones') which are well suited to drag-and-drop functionality, where the human finger replaces the mouse.

Cut and Paste is considered to be a variation of drag-and-drop functionality in the java DnD system.

http://www.java2s.com/Tutorial/Java/0240__Swing/TransferbothTextandColorbetweenJTextFieldandJTextArea.htm A complete example of dragging colour as well as text. Implements a TransferHandler and a Transferable to contain the color (in a color DataFlavor) and text (the Transferable contains an array of 2 DataFlavors). This is a very good example.

http://stackoverflow.com/questions/8558876/drag-and-drop-for-a-jlabel-how-to-get-the-drag-source an example of dragging a label. also how to define a new DataFlavor

http://stackoverflow.com/questions/811248/how-can-i-use-drag-and-drop-in-swing-to-get-file-path an interesting question about drag and drop

http://www.java2s.com/Code/JavaAPI/java.awt.dnd/DropTargetListener.htm good drag and drop examples, including an example of dragging a file list into a text area- this example iterates through the dataflavour mime types

enable drag and drop on various components

   textArea.setDragEnabled(toggle);
   textField.setDragEnabled(toggle);
   list.setDragEnabled(toggle);
   table.setDragEnabled(toggle);
   tree.setDragEnabled(toggle);
   colorChooser.setDragEnabled(toggle);
  ,,,,

SIMPLE DRAG AND DROP ....

  Before becoming overwhelmed by the complexity of the java 
  drag-and-drop api, consider the following 2 examples:

  In the 1st example only 1 line of code "list.setDragEnabled(true);"
  is required to enable items to be dragged out of a JList 
  component.

  In the 2nd example only 9 lines of code are required to allow
  any property of a JComponent to be dragged.

  * simple DnD functionality for a JList and a JTextArea 
   import javax.swing.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class DefaultDragAndDrop extends JPanel {
     JList list;
     JTextArea area;
     public DefaultDragAndDrop() {
       super(new BorderLayout(10, 10));
       Font f = new Font("Georgia", Font.ITALIC, 20);
       this.list = new JList(new java.io.File(".").list()); 
       this.list.setFont(f); list.setDragEnabled(true);
       this.area = new JTextArea("drop here", 20, 40);
       this.area.setFont(f);
       this.add(new JScrollPane(this.list), BorderLayout.WEST);
       this.add(this.area, BorderLayout.CENTER);
     }
     public static void main(String args[]) {
       JFrame f = new JFrame("testing default dnd"); 
       f.add(new DefaultDragAndDrop());
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);  
       f.setVisible(true);
     }
   }

drag the text of a JLabel into a JTextArea

   import java.awt.BorderLayout;
   import java.awt.event.*;
   import javax.swing.*;
   public class DragLabel {
     public static void main(String args[]) {
       JFrame frame = new JFrame("Drag Label");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       JLabel label = new JLabel("Drag the text from this JLabel");
       label.setTransferHandler(new TransferHandler("text"));
       MouseListener listener = new MouseAdapter() {
         public void mousePressed(MouseEvent me) {
           JComponent comp = (JComponent) me.getSource();
           TransferHandler handler = comp.getTransferHandler();
           handler.exportAsDrag(comp, me, TransferHandler.COPY);
         }
       };
       label.addMouseListener(listener);
       frame.add(label, BorderLayout.SOUTH);
       JTextField text = new JTextField();
       frame.add(text, BorderLayout.NORTH);
       frame.setSize(300, 150);
       frame.setVisible(true);
     }
   }

The simplest way to use drag-and-drop in java is to make use of the built-in functionality of many swing components. In this case, one only needs to c.setDragEnabled(true) on the component, to activate its drag functionality.

Another simple way in to use drag-and-drop is to call the method c.setTransferHandler(new TransferHandler("text")). The string which is this case is "text" can be the name of any JComponent 'property' such as "icon", "border", "background" etc. This one line of code, combined with a MouseListener provides a lot of functionality: it allows the component (a JLabel for example) to drag-out and drop-in on its 'text' property (the text you see on the JLabel). Any property including the "icon" property of the JComponent can be used.

A number of swing components have a built-in (default) drag or drop functionality. For example you can drag a selected row from a JTable to a JTextArea and the row will be copied as text into the textarea. However if you wish to control how the information is dragged or dropped you need to implement a TransferHandler class.

Drag And Drop Overview ‹↑›

The java drag-and-drop api is quite large and can be somewhat daunting to the programmer. Here is an overview of the main classes, what they do, and what the programmer needs to implement. Drag-and-drop can be thought of as 2 separate areas: the data aspect and the visual aspects.

When you drag a component what you are actually dragging is some kind of data, an Object, a String, a Color. This data needs to be 'packaged' and 'exported' from the source JComponent and then 'unpackaged' and 'imported' to the target JComponent.

TransferHandler This class handles the exporting of data from the source JComponent and the importing of data into the target JComponent. The TransferHandler uses a Transferable to actually contain the data, and a DataFlavor to indicate what sort of data is being transported. You only need to extend a TransferHandler class if you wish to customise how the data is exported or imported from or into a JComponent. Transferable Actually contains the dragged data. You only need to implement a Transferable if you are transporting data of a type other than string, image, or a list of Files. DataFlavor Just indicates the type of data being dragged/transported (in a Transferable object) using a MIME type string. The DataFlavor doesnt contain the data being transported. A single Transferable object can have one or many different DataFlavors. These different DataFlavors can indicate different 'packets' (objects) of data within the Transferable (eg text and the text-color) or the different DataFlavors can just indicate a different way of accessing the same 'packet' of data (eg text data provided as an InputStream, or else the same text data provided in a String).

Default Drag And Drop Behaviors ‹↑›

Many Swing component include default drag-and-drop behaviors. For example JTextComponents can export (drag out) and import (drop into) text data. JList components can drag out list items but not (by default) import data. In order to enable the default drag action it is often only necessary to call the setDragEnable(true) method on the JComponent.

In the example below the default drag action for a JList is used, and the default drop action for a JTextArea. For this reason is is not necessary to write a TransferHandler class.

However if we wanted to have more control over how the data is imported into the JTextArea, we would have to write a TransferHandler class, implement the canImport() and importData() methods, and install the handler on the JTextArea with setTransferHandler()

an example of default dnd actions for a JList and a JTextArea

   import javax.swing.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class DefaultDragAndDrop extends JPanel {
     JList list;
     JTextArea area;
     public DefaultDragAndDrop() {
       super(new BorderLayout(10, 10));
       Font f = new Font("Georgia", Font.ITALIC, 20);
       this.list = new JList(new java.io.File(".").list()); 
       this.list.setFont(f); list.setDragEnabled(true);
       this.area = new JTextArea("drop here", 20, 40);
       this.area.setFont(f);
       this.add(new JScrollPane(this.list), BorderLayout.WEST);
       this.add(this.area, BorderLayout.CENTER);
     }
     public static void main(String args[]) {
       JFrame f = new JFrame("testing default dnd"); 
       f.add(new DefaultDragAndDrop());
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);  
       f.setVisible(true);
     }
   }

Enabling Drag And Drop ‹↑›

enable dragging out of (exporting data from) a JComponent

 jcomponent.setDragEnabled(true)

make dropped data replace the list item which is under the mouse cursor

 jlist.setDropMode(DropMode.ON)

specify the handler which deals with data export/import during dnd

 jcomponent.setTransferHandler(transferHandler)

Process Of Drag And Drop ‹↑›

A drag-and-drop from a JList to a JTextArea consists of the following stages: drag gesture within the JList the user holds down the mouse button and moves the mouse, while optionally holding down the control or shift key. JList packages data and declares what operation it supports eg MOVE, COPY, LINK TransportHandler.exportDone() method called Mouse moves into target JComponent (JTextArea) TransportHandler.canImport(...) is called continuously while the mouse move over the target component. Drop gesture The user releases the mouse button The JTextField imports the data by calling the method TransportHandler.import(...)

Transferhandler ‹↑›

The javax.swing.TransferHandler class performs most of the work and logic with java drag-and-drop. This class is responsable for exporting and importing data.

If a new TransferHandler is installed on a JComponent with component.setTransferHandler(...) then that new handler should re-implement (at least some) default drag-and-drop behaviors for the component, since the TransferHandler replaces the default TransferHandler for the JComponent.

The TransferHandler class can either be extended to provide special behaviors or else used as is

The example below shows the simplicity of icon drag and drop using the standard TransferHander class. With only one line of code we allow icons to be dragged into and out of a JLabel.

enable both icon drag out of and icon drop into a JLabel

 jlabel.setTransferHandler(new TransferHandler("icon"));

In the example below it does not seem possible to drag images into the labels or buttons from an external application (web-browser for example). Nor is it possible to drag the icon from the JButton but it is possible to drop and icon into the JButton

drag icons from one JLabel to another JLabel or JButton

   import java.awt.GridLayout;
   import java.awt.event.*;
   import javax.swing.*;
   public class IconDnD {
     public static void main(String[] args) {
       JFrame f = new JFrame("Icon Drag & Drop");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setLayout(new GridLayout(0, 3));
       MouseListener listener = new DragMouseAdapter();
       String[] ss = {
         "FileView.directoryIcon", "FileView.fileIcon",
         "FileView.computerIcon", "FileView.hardDriveIcon",
         "FileView.floppyDriveIcon", "FileChooser.newFolderIcon",
         "FileChooser.upFolderIcon", "FileChooser.homeFolderIcon",
         "FileChooser.detailsViewIcon",
       };
       Icon icon;
       JLabel label;
   for (String s: ss) {
         label = new JLabel(s, UIManager.getIcon(s), JLabel.CENTER);
         label.addMouseListener(listener);
         label.setTransferHandler(new TransferHandler("icon"));
         f.add(label);
       }
       f.pack();
       f.setLocationRelativeTo(null);
       f.setVisible(true);
     }
   }
   class DragMouseAdapter extends MouseAdapter {
     public void mousePressed(MouseEvent e) {
       JComponent c = (JComponent) e.getSource();
       TransferHandler handler = c.getTransferHandler();
       handler.exportAsDrag(c, e, TransferHandler.COPY);
     }
   }

The example below also gives an idea of how to drag colors from a color chooser into a gui interface.

drag colors from foreground to background in JLabels, working

   import java.awt.Color;
   import java.awt.FlowLayout;
   import java.awt.event.MouseEvent;
   import java.awt.event.MouseMotionAdapter;
   
   import javax.swing.JFrame;
   import javax.swing.JLabel;
   import javax.swing.TransferHandler;
   
   /* also try with JColorChooser component with dragEnabled=true.  */
   public class ColorDrag {
     public static void main(String args[]) {
       final JLabel label1 = new JLabel("Drag here");
       final JLabel label2 = new JLabel("Drop here");
       label1.setTransferHandler(new TransferHandler("foreground"));
       label2.setTransferHandler(new TransferHandler("background"));
   
       // Give label1 a foreground color other than the default
       // Make label2 opaque so it displays its background color
       label1.setForeground(new Color(100, 100, 200));
       label1.setOpaque(true);
       label2.setBackground(Color.orange);
       label2.setOpaque(true);
   
       // Now look for drag gestures over label1. When one occurs,
       // tell the TransferHandler to begin a drag.
       // Exercise: modify this gesture recognition so that the drag doesn't
       // begin until the mouse has moved 4 pixels. This helps to keep
       // drags distinct from sloppy clicks. To do this, you'll need both
       // a MouseListener and a MouseMotionListener.
       label1.addMouseMotionListener(new MouseMotionAdapter() {
         public void mouseDragged(MouseEvent e) {
           // should use e.getSource()
           TransferHandler handler = label1.getTransferHandler();
           handler.exportAsDrag(label1, e, TransferHandler.COPY);
         }
       });
       // Create a window, add the labels, and make it all visible.
       JFrame f = new JFrame("ColorDrag");
       f.setLayout(new FlowLayout());
       f.add(label1); f.add(label2); f.pack(); f.setVisible(true);
     }
   }

The example below doesnt work because the default TransferHandler for a JTextArea cannot import images or icons

drag a property of a JLabel into a JTextArea,

   import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;
   public class DragLabel {
     public static void main(String args[]) {
       JFrame frame = new JFrame("Drag Label");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       JLabel label = new JLabel("Hello, World");
       label.setTransferHandler(new TransferHandler("icon"));
       //label.setForeground(Color.orange);
       label.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
       MouseListener listener = new MouseAdapter() {
         public void mousePressed(MouseEvent me) {
           JComponent comp = (JComponent) me.getSource();
           TransferHandler handler = comp.getTransferHandler();
           handler.exportAsDrag(comp, me, TransferHandler.COPY);
         }
       };
       label.addMouseListener(listener);
       frame.add(label, BorderLayout.SOUTH);
       JTextPane text = new JTextPane();
       frame.add(text, BorderLayout.NORTH);
       frame.setSize(300, 150);
       frame.setVisible(true);
     }
   }

Export Methods For Transporthandler ‹↑›

getSourceActions(jcomponent) This method declares what dnd actions the source JComponent supports- eg MOVE, COPY, LINK. The value returned is a 'or' bit combination createTransferable(jcomponent) bundles the data to be exported into a Transferable object exportDone(jcomponent, transferable, int action) This method is called after the data is exported. This method is where changed to the source component are made. For example in a MOVE drag operation, the dragged item would be deleted from the JList in this method.

an example of export methods for a TransferHandler

   int getSourceActions(JComponent c) { return COPY_OR_MOVE; }

   Transferable createTransferable(JComponent c) {
     return new StringSelection(c.getSelection());
   }

   void exportDone(JComponent c, Transferable t, int action) {
     if (action == MOVE) { c.removeSelection(); }
   }

Import Methods For Transporthandler ‹↑›

2 methods need to be implemented within the TransportHandler class in order to support the dropping or importing of data into a JComponent

canImport(TransferHandler.TransferSupport) this method is called repeatedly (since java 1.6) as the mouse cursor hovers over the target component. If the area under the cursor can accept the drop (or paste) action then the method returns true, otherwise false. Using this method, some areas of a component can accept a drop, and other areas reject it. importData(TransferHandler.TransferSupport) This method actually imports the data into the target component.

example data import methods for a TransferHandler implementation

   public boolean acceptLocation(DropLocation dl) { ...  }
   public void insertAt(DropLocation dl, String data) { ...  }
   public boolean canImport(TransferSupport ts) {
     if (!ts.isDataFlavorSupported(stringFlavor)) { return false; }
     DropLocation loc = ts.getDropLocation();
     return acceptLocation(loc);
   }
   
   public boolean importData(TransferSupport ts) {
     if (!this.canImport(ts)) { return false; }
     Transferable t = ts.getTransferable();
     String data = t.getTransferData(stringFlavor);
     DropLocation loc = supp.getDropLocation();
     this.insertAt(loc, data);
     return true;
   }

a complete TransferHandler for importing string data into a JList

   import javax.swing.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   /* 
     enable drop on the JList with the following 1 or 2 lines
       jlist.setTransferHandler(new ListTransferHandler());
       jlist.setDropMode(DropMode.ON_OR_INSERT);   // optional
   */
   public class ListTransferHandler extends TransferHandler {
     public boolean canImport(TransferHandler.TransferSupport ts) {
       if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) {
         return false;
       }
       return true;
     }
     public boolean importData(TransferHandler.TransferSupport ts) {
       if (!ts.isDrop()) { return false; }
       JList list = (JList)ts.getComponent();
       DefaultListModel listModel = (DefaultListModel)list.getModel();
       JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
       int index = dl.getIndex();
       //boolean insert = dl.isInsert();
       Transferable t = info.getTransferable();
       String data;
       try {
         data = (String)t.getTransferData(DataFlavor.stringFlavor);
       }
       catch (Exception e) { return false; }
       if (insert) {
         listModel.add(index, data);
       } else {
         listModel.set(index, data);
       }
       return true;
     }
   }

Transferable ‹↑›

The Transferable class is the class which actually contains the data (text, an image, a color) which is being dragged and dropped. When you want to retrieve the data from the Transferable you call tranferable.getTransferData(DataFlavor.stringFlavor); The getTransferData() method takes a DataFlavor parameter. This parameter specifies the type of data you would like to get from the transferable (if data of that type is available). Transferable objects may contain many packets of data (for example, a string of text, the color of that text, and the font of the text). The DataFlavor specifies which packet (object) of data you would like to retrieve from the Transferable.

If you would like to drag or drop a data type for which there is no pre-defined DataFlavor then you can implement a Tranferable along with a TransferHandler. The example below demonstrates this.

The example is very complete and demonstrates all the processes of implementing a Transferable and a TransferHandler

how to implement a transferable to transfer a Color and a String

   import java.awt.Color;
   import java.awt.datatransfer.*;
   import java.io.IOException;
   import java.util.Arrays;
   
   import javax.swing.*;
   import javax.swing.text.JTextComponent;
   
   public class TransferableDragAndDrop {
     public static void main(String[] args) {
       JFrame frame = new JFrame();
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setContentPane(new JPanel());
   
       JTextField textField = new JTextField(25);
       textField.setText("Let's swing higher");
       frame.add(textField);
   
       JTextArea textArea = new JTextArea("Demonstrating\ndrag and drop");
       textArea.setForeground(Color.red);
       frame.add(new JScrollPane(textArea));
   
       textArea.setDragEnabled(true);
       textField.setDragEnabled(true);
       TextColorTransferHandler transferHandler = 
         new TextColorTransferHandler();
       textArea.setTransferHandler(transferHandler);
       textField.setTransferHandler(transferHandler);
       frame.pack(); frame.setVisible(true);
     }
   }
   
   class TextColorTransferHandler extends TransferHandler {
     public int getSourceActions(JComponent c) { return COPY_OR_MOVE; }
     protected Transferable createTransferable(JComponent component) {
       String text = ((JTextComponent) component).getText();
       Color color = component.getForeground();
       TextColor transferable = new TextColor(text, color);
       return transferable;
     }
     public boolean canImport(JComponent c, DataFlavor[] flavors) {
       return true;
     }
     public boolean importData(JComponent co, Transferable tf) {
       String colorMimeType = 
         DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
       JTextComponent textComponent = (JTextComponent) co;
       try {
         DataFlavor colorFlavor = new DataFlavor(colorMimeType);
         Color color = (Color) tf.getTransferData(colorFlavor);
         String text = 
           (String) tf.getTransferData(DataFlavor.stringFlavor);
         textComponent.setForeground(color);
         textComponent.setText(text);
       }
       catch (ClassNotFoundException e) { e.printStackTrace(); }
       catch (IOException e) { e.printStackTrace(); }
       catch (UnsupportedFlavorException e) { e.printStackTrace(); }
       return true;
     }
   }
   
   class TextColor implements Transferable {
     private String text;
     private Color color;
     private DataFlavor[] flavors;
   
     public TextColor(String text, Color color) {
       String colorMimeType = 
         DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
       DataFlavor colorFlavor = null;
       try {
         colorFlavor = new DataFlavor(colorMimeType);
       } catch (ClassNotFoundException e) {}
       this.flavors = 
         new DataFlavor[]{DataFlavor.stringFlavor, colorFlavor};
       this.text = text; this.color = color;
     }
     public DataFlavor[] getTransferDataFlavors() {
       return (DataFlavor[]) flavors.clone();
     }
     public boolean isDataFlavorSupported(DataFlavor flavor) {
       // another way
       // return Arrays.asList(this.flavors).contains(flavor);
       for (DataFlavor f: this.flavors) 
         { if (flavor.equals(f)) return true; }
       return false;
     }
   
     public Object getTransferData(DataFlavor flavor) 
       throws UnsupportedFlavorException, IOException {
       if (flavor.equals(flavors[0])) {
         return text;
       } else if (flavor.equals(flavors[1])) {
         return color;
       } else {
         throw new UnsupportedFlavorException(flavor);
       }
     }
   }

Transportsupport Inner Class ‹↑›

The TransferHandler.TransportSupport class (since java 1.6) provides information about the transfer (drag-and-drop) currently underway.

how adding an Action affects the component
the Action is added as an ActionListener to the component.
component configures some of its properties to match the Action.
component installs PropertyChangeListener on the Action so that the component can change its properties to reflect changes in the Action's properties.
getComponent() returns the target component of the transfer isDrop() returns if this is a drop (dnd) or a paste action getDataFlavors() gets all available DataFlavors. This seems to be a list of DataFlavors supported by the source component. For example, if you drag an image from a web-page, you can import that component into your application as html text or as image data (java.awt.Data). isDataFlavorSupport(DataFlavor.stringFlavor) determines if the target compenent of the drop or paste action supports importing data of the text or string type.

Exporting Or Dragging Data ‹↑›

a complete TransferHandler implementation for exporting data

   import javax.swing.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class ListTransferHandler extends TransferHandler {
     private int[] indices = null;
     private int addIndex = -1; //Location where items were added
     private int addCount = 0;  //Number of items added.
     public boolean canImport(TransferHandler.TransferSupport info) {
       // Check for String flavor
       if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
         return false;
       }
       return true;
     }
     protected Transferable createTransferable(JComponent c) {
       return new StringSelection(exportString(c));
     }
     public int getSourceActions(JComponent c) {
       return TransferHandler.COPY_OR_MOVE;
     }

     protected void exportDone(
     JComponent c, Transferable data, int action) {
       cleanup(c, action == TransferHandler.MOVE);
     }

     //Bundle up the selected items in the list as a string, for export.
     protected String exportString(JComponent c) {
       JList list = (JList)c;
       indices = list.getSelectedIndices();
       Object[] values = list.getSelectedValues();
       StringBuffer buff = new StringBuffer();
       for (int i = 0; i < values.length; i++) {
         Object val = values[i];
         buff.append(val == null ? "" : val.toString());
         if (i != values.length - 1) {
           buff.append("\n");
         }
       }
       return buff.toString();
     }
   
     //If the remove argument is true, the drop has been
     //successful and it's time to remove the selected items
     //from the list. If the remove argument is false, it
     //was a Copy operation and the original list is left
     //intact.
     protected void cleanup(JComponent c, boolean remove) {
       if (remove && indices != null) {
         JList source = (JList)c;
         DefaultListModel model  = (DefaultListModel)source.getModel();
         //If we are moving items around in the same list, we
         //need to adjust the indices accordingly, since those
         //after the insertion point have moved.
         if (addCount > 0) {
           for (int i = 0; i < indices.length; i++) {
             if (indices[i] > addIndex) {
               indices[i] += addCount;
             }
           }
         }
         for (int i = indices.length - 1; i >= 0; i--) {
           model.remove(indices[i]);
         }
       }
       indices = null;
       addCount = 0;
       addIndex = -1;
     }
   }

Dropping Or Importing Data ‹↑›

a simple location sensitive drop implementation

    public boolean acceptLocation(DropLocation dl) { ...  }
    public boolean canImport(TransferSupport ts) {
      if (!ts.isDataFlavorSupported(stringFlavor)) { return false; }
      DropLocation loc = ts.getDropLocation();
      return acceptLocation(loc);
    }

import on text data via (drag and) drop, not via (cut and) paste

   public boolean canImport(TransferHandler.TransferSupport info) {
     if (!ts.isDrop()) return false;
     if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) return false; 
     return true;
   }

In the example below you can drag text into the JList from outside the java application or also from another component in the application. The text will either replace a list item or else insert a new item depending on where the mouse cursor is when the button is released (dropped).

a complete example for importing string data into a JList

   import javax.swing.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class DropList extends JPanel {
     JList list;
     public DropList() {
       super(new BorderLayout());
       DefaultListModel model = new DefaultListModel();
       for (String s: new java.io.File(".").list()) model.addElement(s);
       this.list = new JList(model);
       this.list.setFont(new Font("Georgia", Font.ITALIC, 20));
       list.setTransferHandler(new ListTransferHandler());
       list.setDropMode(DropMode.ON_OR_INSERT);
       this.add(new JScrollPane(this.list));
     }
     public static void main(String args[]) {
       JFrame f = new JFrame(); f.add(new DropList());
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);  
       f.setVisible(true);
     }
   }
   class ListTransferHandler extends TransferHandler {
     public boolean canImport(TransferHandler.TransferSupport ts) {
       if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) {
         return false;
       }
       return true;
     }
     public boolean importData(TransferHandler.TransferSupport ts) {
       if (!ts.isDrop()) { return false; }
       JList list = (JList)ts.getComponent();
       DefaultListModel listModel = (DefaultListModel)list.getModel();
       JList.DropLocation dl = (JList.DropLocation)ts.getDropLocation();
       int index = dl.getIndex();
       boolean insert = dl.isInsert();
       Transferable t = ts.getTransferable();
       String data;
       try {
         data = (String)t.getTransferData(DataFlavor.stringFlavor);
       }
       catch (Exception e) { return false; }
       if (insert) {
         listModel.add(index, data);
       } else {
         listModel.set(index, data);
       }
       return true;
     }
   }

hooray the example below is importing image data into textarea. It works from an image in chrome but not from the EyeOfGnome image viewer, strangely. The getTransferDataFlavors and getDataFlavors seem to return the same thing

a text area which displays information when something is dropped

   import javax.swing.*;
   import javax.swing.text.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class FlavorArea extends JPanel {
     JTextArea area;
     public FlavorArea() {
       super(new BorderLayout());
       this.area = new JTextArea("drop something here\n", 20, 30);
       this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.area.setTransferHandler(new AreaTransferHandler());
       this.add(new JScrollPane(this.area));
     }
     public static void main(String args[]) {
       JFrame f = new JFrame(); f.add(new FlavorArea());
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);  
       f.setVisible(true);
     }
   }
   class AreaTransferHandler extends TransferHandler {
     public boolean canImport(TransferHandler.TransferSupport ts) {
       /*
       if (!ts.isDataFlavorSupported(DataFlavor.imageFlavor)) {
         return false;
       }
       */
       return true;
     }
     public boolean importData(TransferHandler.TransferSupport ts) {
       //if (!ts.isDrop()) { return false; }
       int index = -1;
       JTextArea area = (JTextArea)ts.getComponent();
       if (ts.isDrop()) {
         JTextComponent.DropLocation dl = 
           (JTextComponent.DropLocation)ts.getDropLocation();
         index = dl.getIndex();
       }
       Transferable t = ts.getTransferable();
       String data = "-";
       Image i; 
       try {
         //data = (String)t.getTransferData(DataFlavor.stringFlavor);
         /*
         i = (Image)t.getTransferData(DataFlavor.imageFlavor);
         JLabel imageLabel = new JLabel(new ImageIcon(i));

         JOptionPane.showMessageDialog(null, imageLabel);
         */
         //JOptionPane.showMessageDialog(null, 
         //  "image width:" + i.getWidth(null) + " height:" + i.getHeight(null));
       }
       catch (Exception e) { 
         e.printStackTrace();
         //return false; 
       }
       
       /*
       area.append("TransferDataFlavors: \n");
       for (DataFlavor df: t.getTransferDataFlavors()) {
         area.append(df.toString() + "\n");
       }
       */
       StringBuilder sb = new StringBuilder();
       sb.append("DataFlavors: \n");
       for (DataFlavor df: ts.getDataFlavors()) {
         sb.append(df.toString() + "\n");
         if (df.isFlavorJavaFileListType()) 
           sb.append(" javaFileListFlavor\n");
         if (df.isFlavorTextType()) sb.append(" stringFlavor\n");
       }
       String info = String.format(
         "DropLocation.getIndex():%d \nisDrop():%s \ndata:%s \n", 
         index, ts.isDrop(), data);
       sb.append(info);
       area.setText(sb.toString());
       return true;
     }
   }

Image Drag And Drop ‹↑›

When dragging an image from a webbrowser, for example, DataFlavor will probably be imageFlavor (mime type 'image') but when dragging from an image viewer, the DataFlavor may well be javaFileListFlavor

The TransferHandler class supports by default, supports importing IconImages into JLabels and JButtons, so this makes drag and drop very easy to implement. We just call

 jlabel.setTransferHandler(new TransferHandler("icon"));

The example below is incomplete.

a JLabel which displays information when something is dropped

   import javax.swing.*;
   import javax.swing.text.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class ImageDrop extends JPanel {
     JTextArea area;
     JLabel label;
     public ImageDrop() {
       super(new BorderLayout());
       this.area = new JTextArea("drop something here\n", 20, 30);
       this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
       this.area.setTransferHandler(new ImageTransferHandler());
       this.label = new JLabel();
       this.add(new JScrollPane(this.area));
     }
     public static void main(String args[]) {
       JFrame f = new JFrame(); f.add(new ImageDrop());
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.pack(); f.setLocationRelativeTo(null);  
       f.setVisible(true);
     }
   }
   class ImageTransferHandler extends TransferHandler {
     public boolean canImport(TransferHandler.TransferSupport ts) {
       if (!ts.isDataFlavorSupported(DataFlavor.imageFlavor)) {
         return false;
       }
       return true;
     }
     public boolean importData(TransferHandler.TransferSupport ts) {
       if (!ts.isDrop()) { return false; }
       int index = -1;
       JTextArea area = (JTextArea)ts.getComponent();
       TransferHandler.DropLocation dl = 
           (TransferHandler.DropLocation)ts.getDropLocation();
       Transferable t = ts.getTransferable();
       String data = "-";
       Image i; 
       try {
         //data = (String)t.getTransferData(DataFlavor.stringFlavor);
         i = (Image)t.getTransferData(DataFlavor.imageFlavor);
         JLabel imageLabel = new JLabel(new ImageIcon(i));
         JOptionPane.showMessageDialog(null, imageLabel);
       }
       catch (Exception e) { 
         e.printStackTrace();
         //return false; 
       }
       
       StringBuilder sb = new StringBuilder();
       sb.append("DataFlavors: \n");
       for (DataFlavor df: ts.getDataFlavors()) {
         sb.append(df.getMimeType() + "\n");
         if (df.isFlavorJavaFileListType()) 
           sb.append(" javaFileListFlavor\n");
         if (df.isFlavorTextType()) sb.append(" stringFlavor\n");
       }
       String info = String.format(
         "DropPoint:%s \nisDrop():%s \ndata:%s \n", 
         dl.getDropPoint().toString(), ts.isDrop(), data);
       sb.append(info);
       area.setText(sb.toString());
       return true;
     }
   }

Jlist Drag And Drop ‹↑›

The JList component support export (drag out) by default but not import (drop in).

JList.DropLocation This class converts the pixel location of the drop location into JList item indexes which are much more convenient. Also this class can determine whether the location is an 'insert' location or a replace location.

some methods

The setDropMode() method is defined for the JList, JTable, and JTree components but the semantics and DropModes for each component are slightly different.

replace or insert dropped (or pasted?) items into a JList

 list.setDropMode(DropMode.ON_OR_INSERT);

JList.DropLocation methods
getIndex() - returns the list item index of the drop location
isInsert() - returns if the location is an insert location or not
DropMode.USE_SELECTION The dropped data replaces the item under the mouse cursor. The currently selected item of the JList is set to the item just replaced. This is the default but is apparently not recommended- and is only included for backwards compatibility. DropMode.ON The dropped data replaces the item under the mouse cursor. The current selected item is not changed DropMode.INSERT The dropped data is inserted between the items closest to the mouse cursor. The selected item is unchanged. It is not possible to replace JList items with this DropMode DropMode.ON_OR_INSERT The dropped data either replaces the item under the mouse cursor or is inserted between the closest items, depending on the position of the mouse cursor.

a complete TransferHandler inserting data into a JList component

   import javax.swing.*;
   import java.awt.*;
   import java.awt.datatransfer.*;
   public class ListTransferHandler extends TransferHandler {
     public boolean canImport(TransferHandler.TransferSupport ts) {
       if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) {
         return false;
       }
       return true;
     }
     public boolean importData(TransferHandler.TransferSupport ts) {
       if (!ts.isDrop()) { return false; }
       JList list = (JList)ts.getComponent();
       DefaultListModel listModel = (DefaultListModel)list.getModel();
       JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
       int index = dl.getIndex();
       boolean insert = dl.isInsert();
       Transferable t = info.getTransferable();
       String data;
       try {
         data = (String)t.getTransferData(DataFlavor.stringFlavor);
       }
       catch (Exception e) { return false; }

       if (insert) { listModel.add(index, data); } 
       else { listModel.set(index, data); }
       return true;
     }
   }

In the following example it is possible to drag a listbox item ontop of another (thereby replacing it) or drag it between two listbox items, inserting a new item (with the same text as the dragged item). It is also possible to drag a multiple selection. The several items get concatenated as a string and become the new element. This is not very useful but demonstrates what can be done within the createTransferable() method.

A JList box which can drag and drop items onto itself

    import javax.swing.*;
    import java.awt.*;
    import java.awt.datatransfer.*;
    public class DragBox {
      public static void main(String[] args) {
        JFrame t = new JFrame();
        DefaultListModel listModel = new DefaultListModel();
        for (String s: new String[]{"Acacia", "Yew", "Oak", "Gum"})
          listModel.addElement(s);
        final JList list = new JList(listModel);
        list.setFont(new Font("Georgia", Font.PLAIN, 30));
        list.setTransferHandler(new TransferHandler() {
          public boolean canImport(TransferHandler.TransferSupport info) {
            if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
              return false;
            }
            JList.DropLocation dl = 
              (JList.DropLocation)info.getDropLocation();
            if (dl.getIndex() == -1) { return false; }
            return true;
          }
          public boolean importData(TransferHandler.TransferSupport info) {
            if (!info.isDrop()) { return false; }
            if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
               JOptionPane.showMessageDialog(null, 
                 "List doesn't accept a drop of this type.");
               return false;
            }

          JList.DropLocation dl = 
            (JList.DropLocation)info.getDropLocation();
          DefaultListModel listModel = (DefaultListModel)list.getModel();
          // Get the string that is being dropped.
          Transferable t = info.getTransferable();
          String data;
          try { data = (String)t.getTransferData(DataFlavor.stringFlavor); } 
          catch (Exception e) { return false; }
          if (dl.isInsert()) {
            System.out.println("'" + data + "' inserted at index " + dl.getIndex());
          } else {
            System.out.println("'" + data + "' replacing index " + dl.getIndex());
          }
          if (dl.isInsert()) { listModel.add(dl.getIndex(), data); } 
          else { listModel.set(dl.getIndex(), data); }
          return true;
      }
       
      public int getSourceActions(JComponent c) { return COPY; }
      protected Transferable createTransferable(JComponent c) {
        JList list = (JList)c;
        Object[] values = list.getSelectedValues();
        StringBuffer buff = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
          Object val = values[i];
          buff.append(val == null ? "" : val.toString());
          if (i != values.length - 1) { buff.append("\n"); }
        }
        return new StringSelection(buff.toString());
      }
   });
        list.setDropMode(DropMode.ON_OR_INSERT);
        list.setDragEnabled(true);
        JPanel p = new JPanel(); p.add(list);
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setLocationRelativeTo(null);
        t.setVisible(true);
      }
    }

Jtree Drag And Drop ‹↑›

The JTree uses the some DropModes as the JList component

JList setDropMode() modes (since java 1.6)

Jtable Drag And Drop ‹↑›

The JTable as several additional DropModes for inserting rows and columns.

Jtextcomponent Drag And Drop ‹↑›

JTree.DropLocation methods
getChildIndex()
getPath()

In the example below, if the user tries to paste text into the text component (say a JTextArea, or a JTextField) then an IllegalStateException will be thrown by the getDropLocation() method. This is because there is no 'drop location' for a (cut and) paste operation- you just check the position of the document caret and paste the data there (or any where else you like)

get the drop location for a text component.

   JTextComponent.DropLocation dl = 
    (JTextComponent.DropLocation)ts.getDropLocation();

Dataflavors ‹↑›

The DataFlavor is the class which specifies the type of data which is contained in the Transferable object. The DataFlavor does not actually contain the data. The Transferable object is the object which contains the data which is being dragged (an image, text, a color etc). The DataFlavor class uses a MIME type string to specify the type of data.

rfc2045 and rfc2046 are the technical specification of MIME (or content) types. The java DnD implementation interprets the paramater of the mime type string as the class returned by Transferable.getTransferData()

JTextComponent.DropLocation methods
getIndex() - returns the document (model) index of the drop location
getBias() - ?
imageFlavor - "image/x-java-image;class=java.awt.Image" media (primary) type: image subtype: x-java-image parameter (representation class): java.awt.Image stringFlavor - javaFileListFlavor -

MIME types

DataFlavor important methods
selectBestTextFlavor() -
getMimeType()

If you want to transfer a type of data for which there is no predefined DataFlavor (stringFlavor, imageFlavor etc), then you instantiate a new DataFlavor using the technique in the example below. This dataflavor will only function for drag-and-drop or cut-and-paste within the java application, not to or from external applications. The new DataFlavor object is then placed in a Transferable. See the Transferable section for a complete example of dragging and dropping a Color data type.

create a new DataFlavor for dragging and dropping Color objects

    String colorMimeType = 
      DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
    DataFlavor colorFlavor = null;
    try {
      colorFlavor = new DataFlavor(colorMimeType);
    } catch (ClassNotFoundException e) { }

In the example below the DataFlavor constructor can throw a ClassNotFoundException because it checks that the 'class=' parameter classname exists or not.

create a new image DataFlavor using a mime type string

    String mimeType = "image/x-java-image;class=java.awt.Image";
    DataFlavor flavor = null
    try { flavor = new DataFlavor(mimeType); } 
    catch (ClassNotFoundException e) {}

Import File List ‹↑›

Doesnt seem to be working

drag a file list into application

import java.awt.BorderLayout; import java.awt.Color; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.*; import javax.swing.*;

public class DropTest extends JFrame implements DropTargetListener {

DropTarget dt; JTextArea ta = new JTextArea(); public DropTest() { super("Drop Test"); setSize(300, 300); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); add(new JLabel("Drop a list from your file chooser here:"), BorderLayout.NORTH); ta.setBackground(Color.white); getContentPane().add(ta, BorderLayout.CENTER);

dt = new DropTarget(ta, this); setVisible(true); }

public void dragEnter(DropTargetDragEvent dtde) { System.out.println("Drag Enter"); }

public void dragExit(DropTargetEvent dte) { System.out.println("Source: " + dte.getSource()); System.out.println("Drag Exit"); }

public void dragOver(DropTargetDragEvent dtde) { System.out.println("Drag Over"); }

public void dropActionChanged(DropTargetDragEvent dtde) { System.out.println("Drop Action Changed"); }

public void drop(DropTargetDropEvent dtde) { try { Transferable tr = dtde.getTransferable(); DataFlavor[] flavors = tr.getTransferDataFlavors(); for (int i = 0; i < flavors.length; i++) { System.out.println("Possible flavor: " + flavors[i].getMimeType()); if (flavors[i].isFlavorJavaFileListType()) { dtde.acceptDrop(DnDConstants.ACTION_COPY); ta.setText("Successful file list drop.\n\n"); java.util.List list = (java.util.List) tr.getTransferData(flavors[i]); for (int j = 0; j < list.size(); j++) { ta.append(list.get(j) + "\n"); } dtde.dropComplete(true); return; } } System.out.println("Drop failed: " + dtde); dtde.rejectDrop(); } catch (Exception e) { e.printStackTrace(); dtde.rejectDrop(); } }

public static void main(String args[]) { new DropTest(); } } ,,,

Look And Feel ‹↑›

The "look and feel" of a windowed application refers to the general style of the graphics used to display the application and the way that buttons change when they are clicked with the mouse Generally each look and feel may correspond to the visual style of an operating system. The default look and feel for java is not particularly attractive, which is why we want to change it.

http://weblogs.java.net/blog/ljnelson/archive/2007/12/useful_swing_th.html an interesting article about look and feel and how to get escape to cancel a window.

some predefined DataFlavors
DataFlavor.stringFlavor - for text data
DataFlavor.imageFlavor - a mime type for java.awt.Image
DataFlavor.javaFileListFlavor - a java.util.List of File objects

The Windows classic is basically Windows 95 style components, Windows looks a lot better, Motif is an old X windows style, Metal is the default java style quite ugly, and Nimbus is the Apple osx style and therefor quite pretty.

The className is used with UIManager.setLookAndFeel()

 String className = info[i].getClassName();

print out the names and classnames of available look and feels

    import javax.swing.UIManager;
    public class LookAndFeel 
    {
      public static void main(String[] args) throws Exception
      {
        UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
        for (int i = 0; i < info.length; i++)
        {
          System.out.println("L & F name:" + info[i].getName());
          System.out.println("L & F classname:" + info[i].getClassName());
        }
     }
   }

print the name of the native look and feel

    import javax.swing.UIManager;
    public class LookAndFeel {
      public static void main(String[] args) throws Exception
      {
        System.out.println("Native look and feel: " + 
          UIManager.getSystemLookAndFeelClassName());
      }
   }

display a file chooser with the native operating system look and feel

    import javax.swing.*;
    public class NiceFileDialog {
      public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JFrame f = new JFrame("Trying to make the FileChooser look nicer");
        JFileChooser c = new JFileChooser();
        if (c.showOpenDialog(f) == JFileChooser.CANCEL_OPTION)
          System.exit(-1);
      }
    }

The result on a windows computer of using the system look and feel is much more aesthetically pleasing. Nimbus has a nice rounded corners but the colours are very cold and the fonts dont seem very good.

display a file chooser with the nimbus look and feel

    import javax.swing.*;
    import java.awt.Font;
    public class NiceFileDialog {
      public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
        JFrame f = new JFrame("A Nimbus Style File Chooser");
        JFileChooser c = new JFileChooser("C:\\");
        c.setFont(new Font("Georgia", Font.PLAIN, 40));
        if (c.showOpenDialog(f) == JFileChooser.CANCEL_OPTION)
          System.exit(-1);
      }
    }

a listbox with names of looks and feels

    import javax.swing.*;
    import java.awt.*;
    public class LookAndFeelBox {
      public static void main(String[] args) {
        ListModel looks = new AbstractListModel() {
           UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
           public int getSize() { return info.length; }
           public Object getElementAt(int index) 
             { return info[index].getClassName(); } 
         };

        Font font = new Font("Georgia", Font.PLAIN, 30);
        JList list = new JList(looks);
        list.setFont(font); list.setForeground(Color.gray);
        //JPanel p = new JPanel(); p.add(l);
        JFrame f = new JFrame();
        f.getContentPane().add(list);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);  
        f.pack(); f.setVisible(true);
      }
    }

The Look and Feel does not effect the window decorations, which are controlled by the host operating system.

The following fragment works but generates runtime exceptions, possible because I update the gui from within a function rather than from within the paint method. The nimbus look and feel seems to be the most pleasant at least on an ms windows computer.

show look and feels and change the look and feel when clicked

   import javax.swing.*;
   import javax.swing.event.*;
   import java.awt.*;
   public class LookAndFeel extends JFrame implements ListSelectionListener {
     JList list;
     ListModel looks = new AbstractListModel() {
       UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
       public int getSize() { return info.length; }
       public Object getElementAt(int index)
         { return info[index].getClassName(); }
     };
     public LookAndFeel()
     {
       Font font = new Font("Georgia", Font.PLAIN, 20);
       list = new JList(looks);
       list.addListSelectionListener(this);
       list.setFont(font);
       list.setForeground(Color.gray);
       JButton button = new JButton("Does Nothing");
       JPanel p = new JPanel();
       p.add(list);
       p.add(button);
       JFrame f = new JFrame();
       this.getContentPane().add(p);
       this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       this.pack();
       this.setVisible(true);
     }
   
     public void valueChanged(ListSelectionEvent e) {
       if (e.getValueIsAdjusting() == false) {
         if (list.getSelectedIndex() == -1) { /* No selection */ }
         else {
           try
           {
             UIManager.setLookAndFeel(list.getSelectedValue().toString());
             SwingUtilities.updateComponentTreeUI(this.getContentPane());
           }
           catch (Exception ex) {}
         }
       }
     }
     public static void main(String[] args)
     {
       LookAndFeel t = new LookAndFeel();
     }
   }

set the native system look and feel.

     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           try {
             UIManager.setLookAndFeel(
               UIManager.getSystemLookAndFeelClassName());
           } catch (Exception useDefault) {}
           initGui();
         }
       });
     }

install a new look and feel.

     try {
       UIManager.
         setLookAndFeel ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
     }
     catch (InstantiationException e) { }
     catch (ClassNotFoundException e) { }
     catch (UnsupportedLookAndFeelException e) { }
     catch (IllegalAccessException e) { }

change the look and feel

 UIManager.setLookAndFeel("...");
 SwingUtilities.updateComponentTreeUI(getContentPane());

set native look and feel

 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

set java look and feel

 Manager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

set the window decorations to the host system look and feel

 JFrame.setDefaultLookAndFeelDecorated(true);
 JFrame frame = new JFrame("A window");

Modifying A Look And Feel ‹↑›

We can modify any look and feel by changing its default attributes. For example we can change the default font or the default panel colours etc.

show the default font for a textfield in the current look and feel

 Font font = UIManager.getFont("TextField.font");

change the default font for all textfield components

 UIManager.put("TextField.font", new FontUIResource(<font>));

change the default font for a colorchooser

 UIManager.put("ColorChooser.font", new FontUIResource("Georgia", Font.PLAIN, 18));

change the default font for all labels and anti-alias fonts (>= 1/6)

    import javax.swing.*;
    import javax.swing.plaf.*;
    import java.awt.*;
    public class LabelFont {
      public static void main(String[] args) {
        System.setProperty("awt.useSystemAAFontSettings","on");
        UIManager.put("Label.font", 
          new FontUIResource(Font.SERIF, Font.PLAIN, 60));
        JPanel p = new JPanel(new GridLayout(0, 1));
        for (String s: new String[]{"jl1", "jl2", "jl3"}) {
          JLabel l = new JLabel(s); p.add(l);
        }
        JOptionPane.showMessageDialog(null, p);
      }
    }

Getdefaults ‹↑›

see all look and feel keys whose values are Icons

   import java.util.Enumeration;
   import javax.swing.plaf.*;
   import javax.swing.*;
   import java.awt.*;
   public class IconList {
     public static void main(String[] args) {
       java.util.Enumeration keys = UIManager.getDefaults().keys();
       while (keys.hasMoreElements()) {
         Object key = keys.nextElement();
         Object value = UIManager.get(key);
         if (value instanceof javax.swing.Icon) System.out.println(key); 
       }
     }
   }

a method to set the default font for all swing elements

  public static void setUIFont (javax.swing.plaf.FontUIResource f){
    java.util.Enumeration keys = UIManager.getDefaults().keys();
    while (keys.hasMoreElements()) {
      Object key = keys.nextElement();
      Object value = UIManager.get(key);
      if (value instanceof javax.swing.plaf.FontUIResource)
        UIManager.put(key, f);
      }
    }    
  }  

List the UIManager keys in a listbox

    import java.util.Enumeration;
    import javax.swing.plaf.*;
    import javax.swing.*;
    import java.awt.Font;
    public class UIListBox {
      public static void main(String[] args) {
        System.setProperty("awt.useSystemAAFontSettings","on");
        DefaultListModel listModel = new DefaultListModel();
        java.util.Enumeration keys = UIManager.getDefaults().keys();
        while (keys.hasMoreElements()) 
          listModel.addElement(keys.nextElement().toString());
        JList list = new JList(listModel);
        list.setFont(new Font("Georgia", Font.PLAIN, 30));
        JPanel p = new JPanel(); p.add(new JScrollPane(list));
        JOptionPane.showMessageDialog(null, p);
      }
    }

List the UIManager keys in a listbox

    import java.util.Enumeration;
    import javax.swing.plaf.*;
    import javax.swing.*;
    import java.awt.Font;
    public class KeysBox extends JList {
      public KeysBox() {
        super();
        DefaultListModel model = new DefaultListModel();
        Enumeration keys = UIManager.getDefaults().keys();
        while (keys.hasMoreElements()) 
          model.addElement(keys.nextElement().toString());
        this.setModel(model);  
        this.setFont(new Font("Georgia", Font.PLAIN, 25));
      }
      public static void main(String[] args) {
        JFrame t = new JFrame();
        JPanel p = new JPanel(); 
        p.add(new JScrollPane(new KeysBox()));
        t.getContentPane().add(p);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.pack(); t.setLocationRelativeTo(null);
        t.setVisible(true);
      }
    }

the above method can be executed with

 setUIFont(new javax.swing.plaf.FontUIResource("Serif",Font.ITALIC,12));

set the default font for all swing components.

    import javax.swing.*;
    import javax.swing.plaf.*;
    import java.awt.*;
    public class LabelFont {
      public static void setUIFont (FontUIResource f){
        java.util.Enumeration keys = UIManager.getDefaults().keys();
        while (keys.hasMoreElements()) {
          Object key = keys.nextElement();
          Object value = UIManager.get(key);
          if (value instanceof javax.swing.plaf.FontUIResource)
            UIManager.put(key, f);
        }    
      }  
      public static void main(String[] args) {
        Font font = new Font("Georgia", Font.PLAIN, 40);
        LabelFont.setUIFont(new FontUIResource("Georgia",Font.ITALIC,25));
        JFrame f = new JFrame();
        JPanel p = new JPanel();
        JLabel l = new JLabel("This is the Georgia Font"); p.add(l);
        JButton b = new JButton("Elm Trees"); p.add(b);
        f.getContentPane().add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }

show a file chooser dialog and determine the result

    import javax.swing.*;
    import javax.swing.plaf.*;
    import java.awt.Font;
    public class ChooseFile {
      public static void main(String[] args) {
        Font font = new Font("Georgia", Font.PLAIN, 30);
        UIManager.put("FileChooser.font", new FontUIResource(font));
        JFrame f = new JFrame("test file chooser");
        JFileChooser chooser = new JFileChooser();
        int result = chooser.showOpenDialog(f);
        java.io.File file = chooser.getSelectedFile();
      }
    }

Custom Jcomponents And Ui Delegates ‹↑›

It is possible to create a new UI for a swing component. These are referred to as 'delegates'. Basically, the component delegates the task of its display details to another class. To create a new look for a JTextField create a TextFieldUI by extending a BasicTextFieldUI. For any component it is possible to create a ComponentUI to change the default look and feel for a component.

http://today.java.net/pub/a/today/2007/02/22/how-to-write-custom-swing-component.html a good article about custom swing components and the ComponentUI

a simple TextFieldUI example

   public class MyTextUI extends BasicTextFieldUI {
     @Override
     protected String getPropertyPrefix() {
       return "TextField";
     }
     protected void paintBackground(Graphics g) {
       g.setColor(new Color(0, 0, 0));
       g.fillRect(0, 0, getComponent().getWidth(), getComponent().getHeight());
     }
   }
   textField.setUI(new MyTextUI());

Java Documentation ‹↑›

includes a link to a method using suns online api documentation

 http://java.sun.com/javase/6/docs/api/javax/sound/sampled/AudioSystem.html#getAudioInputStream(java.io.File)

consult the java 1.5 documentation for the sound 'Clip' class

 http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/sampled/Clip.html

look up the online api documentation for the 'Class' class

 firefox java.sun.com/javase/6/docs/api/java/lang/Class.html

This will open the javadoc documentation for the 'Class' class (used with the reflection classes) in a new firefox tab if firefox is already running

look up the java 6 documentation for the 'File' class

 firefox java.sun.com/javase/6/docs/api/java/io/File.html

a bash function to look up the documentation for a class

 jdoc(){ firefox "java.sun.com/javase/6/docs/api/java/lang/$1.html"; }

This function can be used by typing 'jdoc String' to look up the Sun documentation for the 'String' class

a better java api documentation look-up bash function

    jdoc() { 
      [ -z "$1" ] && echo "usage: $FUNCNAME <java-class>" && return 1
      c=$1; [[ $c != *.* ]] && c=java/lang/$c || c=${c//./\/}
      firefox "java.sun.com/javase/6/docs/api/$c.html";
    }
    jdoc java.io.File; jdoc String

Sound ‹↑›

Java programs using sound can be written with javax.sound.sampled

Since the early days, computers have been able to beep, and they still can.

play the classic beep

 java.awt.Toolkit.getDefaultToolkit().beep();

Playing Sound ‹↑›

www: http://forums.sun.com/thread.jspa?threadID=5401845
A Thread which talks about using Applet audioClip etc.
www: http://forums.sun.com/thread.jspa?messageID=10780561#10780561
Simple code to play a sound file (as a 'clip')
AndrewThompson65 (forums.sun.com) http://forums.sun.com/profile.jspa?userID=590366 his posts on the sun forums, read and learn

Richard G. Baldwin wrote some java audio tutorials

www: http://forums.sun.com/thread.jspa?forumID=31&threadID=792949
Simple code for playing a sound using a SourceDataLine (not a Clip)
PLAYING MP3 AND OGG VORBIS ....

example code for using mp3plugin.jar to play mp3s

 https://blogs.oracle.com/kashmir/entry/java_sound_api_2_mp3

download mp3plugin.jar (from sun) and put in the current folder

 mp3plugin.jar

run your mp3 application with jar in current folder

 java -cp "mp3plugin.jar:." Mp3App     Linux
 java -cp "mp3plugin.jar;." Mp3App     Windows

See below for code that actually plays mp3s. The mp3 format must be first converted to something that the java sound api can deal with.

copy the mp3plugin.jar to the extensions folder

 cp mp3plugin.jar /usr/lib/jvm/jdk1.7.0/jre/lib/ext/

The above procedure avoids having to set the classpath on the command line, since the jre automatically loads classes from the /lib/ext folder. The jar file above does not need the JMF Java Media Framework in order to run.

Strangely, even with the plugin you cant use the same code to play an mp3 as a wav. You need to convert the format first

play an mp3 with the mp3plugin.jar

   import javax.sound.sampled.*;
   import java.io.File;
   public class Player2 {
     // Buffer size = 44100 x 16 x 2 / 8
     private static final int BUFFER_SIZE = 176400; 
     public static void main(String[] args) throws Exception {
       byte[]  buffer = new byte[BUFFER_SIZE];
       AudioInputStream in = 
         AudioSystem.getAudioInputStream(
           AudioFormat.Encoding.PCM_SIGNED, 
           //AudioSystem.getAudioInputStream(new File(args[0])));
           AudioSystem.getAudioInputStream(new File("abuztuan.mp3")));
       AudioFormat audioFormat = in.getFormat();
       SourceDataLine line = 
         (SourceDataLine) AudioSystem.getLine(
           new DataLine.Info(SourceDataLine.class, audioFormat));
       line.open(audioFormat);
       line.start();
       while (true) {
         int n = in.read(buffer, 0, buffer.length);
         if (n < 0) { break; }
         line.write(buffer, 0, n);
       }
       line.drain();
       line.close();
     }
   }
Success! The above code works. After many tries

the only difference in the code above is

     AudioInputStream in = AudioSystem.getAudioInputStream(
       AudioFormat.Encoding.PCM_SIGNED, 
       AudioSystem.getAudioInputStream(new File("abuztuan.mp3")));

Using Tritonius ‹↑›

This procedure is untested.

play an mp3 file o- get http://www.javazoom.net/javalayer/sources.html - put the jar in the class path or current directory - see http://www.cs.princeton.edu/introcs/faq/mp3/MP3.java.html

put these in your classpath tritonus_share.jar, ....

put the tritonus class on the class path and run 'Test'

 java -cp ".:tritonus_share.jar:..." Test

www: www.javazoom.net/mp3spi/documents.html
example code for playing mp3s
www: www.jsresources.org
More examples of how to play mp3 sound files using the tritonius decoder classes. These examples tend to be difficult to understand because they include so much unnecessary code

Formats And Encoders ‹↑›

Service Provider Interface

The Java Sound API uses a Service Provider Interface to identify encoders & decoders for sound formats and sequence types. This way, adding support for a new format or type is as simple as providing a decoder and/or encoder for it, adding an SPI file to the manifest of the Jar it is in, then adding the Jar to the run-time class-path of the application.

The mp3plugin.jar of the Java Media Framework supports decoding MP3s.

Audio Information ‹↑›

commonly installed look and feel classes
Metal javax.swing.plaf.metal.MetalLookAndFeel
Nimbus javax.swing.plaf.nimbus.NimbusLookAndFeel
CDE/Motif com.sun.java.swing.plaf.motif.MotifLookAndFeel
Windows com.sun.java.swing.plaf.windows.WindowsLookAndFeel
Windows Classic com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel

Sound files consist of a file format (which in java is represented by the AudioFileFormat class). This file format contains header information and other metadata such as frame length. The sound file also has an audio format (represented by the class AudioFormat) which consists of the sampling rate, the sample bit size, mono or stereo etc.

An audio format consists of the number of samples per second (hz), number of channels (stereo=2), bits per sample, and sample encoding

show the audio format for the file 'test.wav'

    import javax.sound.sampled.*;
    import java.io.File;
    public class Test
    {
      public static void main(String[] args) throws Exception
      {
        File file = new File("test.wav");
        AudioInputStream ais = AudioSystem.getAudioInputStream(file);
        AudioFormat format = ais.getFormat();
        System.out.println(format);
     }
   }

This produces output such as

 PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian

show more detailed audio format information

    import javax.sound.sampled.*;
    import java.io.File;
    public class Test
    {
      public static void main(String[] args) throws Exception
      {
        File file = new File("test.wav");
        AudioInputStream ais = AudioSystem.getAudioInputStream(file);
        AudioFormat format = ais.getFormat();
        System.out.println(
          "encoding: " + format.getEncoding());
        System.out.println(
          "frame rate: " + format.getFrameRate());
        System.out.println(
          "frame size: " + format.getFrameSize() + "(bytes)");
        System.out.println(
          "sample rate: " + format.getSampleRate());
        System.out.println(
          "sample size: " + format.getSampleSizeInBits() + "(bits)");
        System.out.println(
          "channels: " + format.getChannels());
        System.out.println(
          "big endian: " + format.isBigEndian());
     }
   }

show the audio file format for an audio file

    import javax.sound.sampled.*;
    import java.io.File;
    public class Test
    {
      public static void main(String[] args) throws Exception
      {
        File file = new File("abuztuan.mp3");
        AudioFileFormat af = AudioSystem.getAudioFileFormat(file);
        System.out.println("Audio Type: " + af.getType());
        System.out.println("Audio File Format: " + af);
     }
   }

show what audio file formats can be written by the java sound system

    import javax.sound.sampled.*;
    public class FileFormatList 
    {
      public static void main(String[] args) throws Exception
      {
        AudioFileFormat.Type[] aa = AudioSystem.getAudioFileTypes();
        for (int i = 0; i < aa.length; i++)
          System.out.println(aa[i].toString());
     }
   }

check for a particular type of audio format

  af = AudioSystem.getAudioFileFormat(new File("Test.wav");
  if (af.getType() != AudioFileFormat.Type.AIFF) 

open a local file or within a jar file

 URL url = this.getClass().getClassLoader().getResource("test.wav");

new audioformat in PCM encoding

 new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);

create an 8khz 8bit sample mono signed bigendian PCM format

 AudioFormat format =  new AudioFormat(8000, 8, 1, true, true);

This is a very low quality audioformat, but also of a small file size.

audio format constructor

 AudioFormat(AudioFormat.Encoding encoding, float sampleRate, int sampleSizeInBits, int channels, int frameSize, float frameRate, boolean bigEndian)

a PCM format at 44100 hz stereo, 16 bit sample, 4 byte frame

 AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0, 16, 2, 4, 44100.0, false)

calculate bytes per second

 format.getFrameRate() * format.getFrameSize();

The above calculation is important if you wish to read, play or record a certain number of seconds of audio, which is a reasonably common request.

Source Data Lines ‹↑›

www: http://forums.sun.com/thread.jspa?forumID=31&threadID=5310813
very clear code for using source data lines in a class
a simple example of playing a sound found with a SourceDataLine
    import java.io.*;
    import javax.sound.sampled.*;
    public class SoundLineTest {
       public static void main(String[] args) throws Exception {
         SourceDataLine line = null;
         int BUFFERSIZE = 64*1024;  // 64 KB
         File f = new File("rec.wav");
         AudioInputStream stream = AudioSystem.getAudioInputStream(f);
         AudioFormat format = stream.getFormat();
         DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
         line = (SourceDataLine) AudioSystem.getLine(info);
         line.open(format); line.start();
         int nBytesRead = 0;
         byte[] sampledData = new byte[BUFFERSIZE];
         boolean stopped = false;
         while (!stopped) {
           nBytesRead = stream.read(sampledData, 0, sampledData.length);
           if (nBytesRead == -1) break; 
           line.write(sampledData, 0, nBytesRead);
        }
        line.drain();
        line.close();
      }
   }

The boolean 'stopped' variable in the code above can be used to stop the play back if the user presses a button (which will set the stopped variable to true)

play a sound using a SourceDataLine catching Exceptions

    import java.io.*;
    import javax.sound.sampled.*;
    public class SoundLineTest {
       public static void main(String[] args) {
          SourceDataLine soundLine = null;
          int BUFFER_SIZE = 64*1024;  // 64 KB
        try {
         File soundFile = new File("test.wav");
         AudioInputStream audioInputStream = 
           AudioSystem.getAudioInputStream(soundFile);
         AudioFormat audioFormat = audioInputStream.getFormat();
         DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
         soundLine = (SourceDataLine) AudioSystem.getLine(info);
         soundLine.open(audioFormat);
         soundLine.start();
         int nBytesRead = 0;
         byte[] sampledData = new byte[BUFFER_SIZE];
         while (nBytesRead != -1) {
            nBytesRead = audioInputStream.read(sampledData, 0, sampledData.length);
            if (nBytesRead >= 0) {
               soundLine.write(sampledData, 0, nBytesRead);
            }
         }
      } catch (UnsupportedAudioFileException ex) {
         ex.printStackTrace();
      } catch (IOException ex) {
         ex.printStackTrace();
      } catch (LineUnavailableException ex) {
         ex.printStackTrace();
      } finally {
         soundLine.drain();
         soundLine.close();
      }
   }
   }

In the code above if the nBytesRead > 0 test is removed then an IllegalArgumentException is thrown at the end of the sound file

Cutting Sound Files ‹↑›

One strategy for cutting an audio file is to construct a new AudioInputStream from another but limit the number of frames

create a new shorter stream

     AudioInputStream newStream = 
       new AudioInputStream(
         oldStream, format, seconds * (int)format.getFrameRate());
     AudioSystem.write(shortenedStream, fileFormat.getType(), destinationFile);

Another strategy is to write bytes to an output stream. Then create an audio input stream from those bytes.

cut a section of a wav file and save to a new file

   import java.io.*;
   import javax.sound.sampled.*;
   class AudioFileProcessor {
   public static void copyAudio(
     String sourceFileName, String destinationFileName, 
     int startSecond, int secondsToCopy) {
     AudioInputStream inputStream = null;
     AudioInputStream shortenedStream = null;
     try {
       File file = new File(sourceFileName);
       AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(file);
       AudioFormat format = fileFormat.getFormat();
       inputStream = AudioSystem.getAudioInputStream(file);
       int bytesPerSecond = format.getFrameSize() * (int)format.getFrameRate();
       inputStream.skip(startSecond * bytesPerSecond);
       long framesOfAudioToCopy = secondsToCopy * (int)format.getFrameRate();
       shortenedStream = new AudioInputStream(inputStream, format, framesOfAudioToCopy);
       File destinationFile = new File(destinationFileName);
       AudioSystem.write(shortenedStream, fileFormat.getType(), destinationFile);
     } catch (Exception e) {
       println(e);
     } finally {
       if (inputStream != null) 
         try { inputStream.close(); } 
         catch (Exception e) { println(e); }
       if (shortenedStream != null) 
         try { shortenedStream.close(); } 
         catch (Exception e) { println(e); }
      }
     }
     public static void main(String[] args) {
       copyAudio("/tmp/uke.wav", "/tmp/uke-shortened.wav", 2, 1);
     }

   }

A technique to write a byte array to a wav file, incomplete example

    File f = new File(exportFileName + ".tmp");
    File f2 = new File(exportFileName);
    long l = f.length();
    //byte[] buffer;
    // read into byte array using AudioInputStream
    ByteArrayInputStream bs = new ByteArrayInputStream(buffer);
    AudioInputStream ai = new AudioInputStream(bs,mainFormat,l/4);
    AudioSystem.write(ai, Type.WAVE, f2);
    fi.close();
    f.delete();

another technique for writing bytes to an audio file, incomplete example

     ByteArrayOutputStream b_out = new ByteArrayOutputStream();
     // Read a frame from the file.
     while (audioInputStream.read(audioBytes) != -1) {       
       //Do stuff here....
       b_out.write(outputvalue);
     }       
     // Hook output stream to output file
     ByteArrayInputStream b_in  = new ByteArrayInputStream(b_out.toByteArray());
     AudioInputStream ais = new AudioInputStream(b_in, format, length);
     AudioSystem.write(ais, inFileFormat.getType(), outputFile);

Convert Raw Audio Data To Wav ‹↑›

File f = new File(exportFileName+".tmp"); File f2 = new File(exportFileName); long l = f.length(); FileInputStream fi = new FileInputStream(f); AudioInputStream ai = new AudioInputStream(fi,mainFormat,l/4); AudioSystem.write(ai, Type.WAVE, f2); fi.close(); f.delete();

Joining Sound Files ‹↑›

join 2 wav files

   import java.io.File;
   import java.io.IOException;
   import java.io.SequenceInputStream;
   import javax.sound.sampled.AudioFileFormat;
   import javax.sound.sampled.AudioInputStream;
   import javax.sound.sampled.AudioSystem;

   public class WavAppender {
     public static void main(String[] args) {
      String wavFile1 = "wav1.wav";
      String wavFile2 = "wav2.wav";
      try {
       AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));
       AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));
       AudioInputStream appendedFiles = new AudioInputStream(
          new SequenceInputStream(clip1, clip2), clip1.getFormat(), 
            clip1.getFrameLength() + clip2.getFrameLength());
       AudioSystem.write(appendedFiles, AudioFileFormat.Type.WAVE, 
             new File("joinwav.wav"));
     } catch (Exception e) {
          e.printStackTrace();
     }
    }
   }

Playing Audio ‹↑›

use a JToggleButton to stop and start a sound clip

   import java.net.URL;
   import java.awt.event.*;
   import javax.swing.*;
   import javax.sound.sampled.*;

   public class RestartableLoopSound {
    public static void main(String[] args) throws Exception {
      URL url = new URL("http://pscode.org/media/leftright.wav");
        final Clip clip = AudioSystem.getClip();
        AudioInputStream ais = AudioSystem.getAudioInputStream(url);
        clip.open(ais);
        SwingUtilities.invokeLater(new Runnable() {
           public void run() {
             final JToggleButton b = new JToggleButton("Loop");
             ActionListener listener = new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
                  if (b.isSelected()) {
                    clip.loop(Clip.LOOP_CONTINUOUSLY);
                  } else { clip.stop(); }
                }
              };
              b.addActionListener(listener);
              JOptionPane.showMessageDialog(null, b);
            }
        });
      }
   }

Clips ‹↑›

Clips are used for non streamed audio data. That is, all audio data is loaded into memory before playback

sound glossary
PCM - pulse-code modulation a simple encoding technique
encoding - eg PCM mu-law, a-law. Turns wave pressure into numbers
herz - the a frequency (eg samples/frames) per second
sample - a digital approximation of a sound wave at a point in time
frame - contains stereo samples and possibly other information
frame rate - the number of frames per second (herz)
sample rate - the number of samples per second (herz)

If a sound file/url is too large then the Clip will throw a javax.sound.sampled.LineUnavailableException with the message "Failed to allocate clip data: Requested buffer too large."

play a clip catching exceptions

    import java.io.*;
    import java.net.URL;
    import javax.sound.sampled.*;
    import javax.swing.*;
    public class SoundClipTest extends JFrame {
       
    public SoundClipTest() {
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.setTitle("Test Sound Clip");
      this.setSize(300, 200);
      this.setVisible(true);
      try {
         File f = new File("test.wav");
         AudioInputStream audioIn = AudioSystem.getAudioInputStream(f);
         Clip clip = AudioSystem.getClip();
         clip.open(audioIn);
         clip.start();
      } catch (UnsupportedAudioFileException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (LineUnavailableException e) {
         e.printStackTrace();
      }
   }
   
   public static void main(String[] args) {
      new SoundClipTest();
    }
   }

play an audio file (obtained from the web) continuously

    import javax.sound.sampled.*;
    import java.net.URL;
    import javax.swing.JOptionPane;
    public class AudioClipTest {
      public static void main(String[] args) throws Exception {
        URL url = new URL("http://pscode.org/media/100_2817.au");
        AudioInputStream ais = AudioSystem.getAudioInputStream(url);
        Clip clip = AudioSystem.getClip();
        clip.open(ais);
        clip.loop(Clip.LOOP_CONTINUOUSLY);
        JOptionPane.showMessageDialog(null, "Close to end..");
      }
    }
  ,,,,,

play an audio clip beginning 1/2 a second after the beginning (using code above)

 clip.open(); clip.setMicrosecondPosition(); clip.start();

play a sound file starting just after the beginning

   import javax.sound.sampled.*;
   import java.io.File;
   import javax.swing.JOptionPane;
   public class ClipTest {
     public static void main(String[] args) throws Exception {
       File f = new File("asagohan.wav");
       AudioInputStream ais = AudioSystem.getAudioInputStream(f);
       Clip clip = AudioSystem.getClip();
       clip.open(ais); 
       clip.setMicrosecondPosition(500000); clip.start();
       JOptionPane.showMessageDialog(null, "Close to end..");
     }
   }

play the local file 'sound.wav' (in the current folder) 6 times

   import javax.sound.sampled.*;
   import java.io.File;
   import javax.swing.JOptionPane;
   public class MpgPlay {
     public static void main(String[] args) throws Exception {
       File f = new File("abuztuan.mp3");
       AudioInputStream ais = AudioSystem.getAudioInputStream(f);
       Clip clip = AudioSystem.getClip();
       clip.open(ais); clip.loop(6); clip.start();
       JOptionPane.showMessageDialog(null, "Close to end..");
     }
   }

check if the system supports playing mp3 sound files

    import javax.sound.sampled.*;
    import java.io.File;
    public class MpgSupport {
      public static void main(String[] args) throws Exception {
        File f = new File("abuztuan.mp3");
        try
        {
          AudioInputStream ais = AudioSystem.getAudioInputStream(f);
          System.out.println("Mp3 is Ok to play");
        }
        catch (UnsupportedAudioFileException e)
        {
          System.out.println("Mp3 is NOT supported");
        }
      }
    }

The following may fail if the sound file is too big

create a simple loop to pause and restart a sound clip

    import javax.sound.sampled.*;
    import java.util.*;
    import java.io.File;
    
    public class PauseClip {
      public static void main(String[] args) throws Exception {
        File file = new File("test.wav");
        AudioInputStream ais = AudioSystem.getAudioInputStream(file);
        Clip clip = AudioSystem.getClip();
        clip.open(ais); clip.loop(1); clip.start();
        Scanner scan = new Scanner(System.in);
        String s = "";
        while (!s.equals("q"))
        {
          System.out.print("what? (p/s/q)>");
          s = scan.nextLine();
          if (s.equals("p")) { clip.stop(); }
          if (s.equals("s")) {
            //clip.flush();
            clip.start();
          }
        }
      }
    }

Recording Sound ‹↑›

www: www.jsresources.org
terribly complicated examples of using the javax.sound.sampled api. This will put you right off ever trying to use it.
www: http://www.developer.com/java/other/article.php/2105421/Java-Sound-Capturing-Microphone-Data-into-an-Audio-File.htm
A tutorial on recording sound by Baldwin.
record cd quality stereo audio
 AudioFormat format = new AudioFormat(
     AudioFormat.Encoding.PCM_SIGNED,
     44100.0F, 16, 2, 4, 44100.0F, false);

record a sound file from the computer microphone

    import java.io.*;
    import javax.sound.sampled.*;
    public class RecordAudio 
    {
      public static void main(String[] args) throws Exception
      {
        /* Cd quality PCM 44.1 kHz, 16 bit signed, stereo. */
        AudioFormat format = new AudioFormat(
          AudioFormat.Encoding.PCM_SIGNED,
          44100.0F, 16, 2, 4, 44100.0F, false);
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
        TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
        line.open(format); line.start();
        AudioInputStream ais = new AudioInputStream(line);
        System.out.println("Recording into 't.wav', [Cntrl] c to stop");
        AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("rec.wav"));
        line.stop(); 
        line.close();
    } }

record audio in a thread, this code is very messy and redundant

    import javax.sound.sampled.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.io.*;
    public class RecordAudio {
      private File audioFile;
      protected boolean running;
      private ByteArrayOutputStream out;
      private AudioInputStream inputStream;
      private AudioFormat format;
      private float level;
      private int frameSize;

    public RecordAudio(){ getFormat(); }
    private AudioFormat getFormat() {
        File file = new File("test.wav");
        AudioInputStream stream;
        try {
            stream = AudioSystem.getAudioInputStream(file);
            format=stream.getFormat();
            frameSize=stream.getFormat().getFrameSize();
            return stream.getFormat();
        }
        catch (UnsupportedAudioFileException e) {} 
        catch (IOException e) { }
        return null;
    }
    public void stopRecording() { running = false; }
    public void recordAudio() {
      try {
        final AudioFormat format = getFormat();
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
        final TargetDataLine line = (TargetDataLine)
        AudioSystem.getLine(info);
        line.open(format);
        line.start();
        Runnable runner = new Runnable() {
          int bufferSize = (int) format.getSampleRate()
                  * format.getFrameSize();
          byte buffer[] = new byte[bufferSize];
          public void run() {
            int readPoint = 0;
            out = new ByteArrayOutputStream();
            running = true;
            int sum=0;
            while (running) {
              int count = line.read(buffer, 0, buffer.length);
              System.out.println(level);
              if (count > 0) { out.write(buffer, 0, count); }
            }
            line.stop();
          }
          };

          Thread captureThread = new Thread(runner);
          captureThread.start();
        } catch (LineUnavailableException e) {
           System.err.println("Line unavailable: " + e);
           System.exit(-2);
        }
    }

    public File getAudioFile() {
        byte[] audio = out.toByteArray();
        InputStream input = new ByteArrayInputStream(audio);
        try {
          final AudioFormat format = getFormat();
          final AudioInputStream ais =
                  new AudioInputStream(input, format,
                          audio.length / format.getFrameSize());
          AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("rec.wav"));
          input.close();
          System.out.println("New file created!");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        return new File("rec.wav");
    }
    
    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
           public void run() {
             final RecordAudio a = new RecordAudio();
             final JToggleButton b = new JToggleButton("start recording");
             ActionListener listener = new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
                  if (b.isSelected()) {
                    a.recordAudio();
                    b.setText("stop recording");
                  } else { 
                    b.setText("start recording");
                    a.stopRecording();
                    File f = a.getAudioFile();
                  }
                }
              };
              b.addActionListener(listener);
              JOptionPane.showMessageDialog(null, b);
            }
        });
      }
   }

Silence ‹↑›

Silence can be calculated either by decibel dB levels or else by the RMS, or Root Mean Square.

Computes the Root Mean Square volume of signal sizes from -1 to 1.


  public double volumeRMS(double[] raw) {
    double sum = 0d;
    if (raw.length == 0) {
        return sum;
    } else {
        for (int ii=0; ii < raw.length; ii++) {
            sum += raw[ii];
        }
    }
    double average = sum/raw.length;

    double sumMeanSquare = 0d;
    for (int ii=0; ii<raw.length; ii++) {
        sumMeanSquare += Math.pow(raw[ii]-average,2d);
    }
    double averageMeanSquare = sumMeanSquare/raw.length;
    double rootMeanSquare = Math.pow(averageMeanSquare,0.5d);

    return rootMeanSquare;
  }

Mixers ‹↑›

show the available audio mixers on a system

    import javax.sound.sampled.*;
    public class MixerTest
    {
      public static void main(String[] args) throws Exception
      {
        Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
        System.out.println("Available mixers:");
        for (int ii = 0; ii < mixerInfo.length; ii++)
        {
          System.out.println(mixerInfo[ii].getName());
    } } }

Tones ‹↑›

code for generating tones

 http://stackoverflow.com/questions/7782721/java-raw-audio-output/7782749#7782749

Midi ‹↑›

Midi is a way of representing electronic music, symbolically rather than as a series of samples.

Playing a MIDI Sequence (a song)

  import javax.sound.midi.*;
  import javax.swing.JOptionPane;
  import java.net.URL;

  public class PlayMidi {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://pscode.org/media/EverLove.mid");
        Sequence sequence = MidiSystem.getSequence(url);
        Sequencer sequencer = MidiSystem.getSequencer();
        sequencer.open();
        sequencer.setSequence(sequence);
        sequencer.start();
        JOptionPane.showMessageDialog(null, "Everlasting Love");
    }
  }

Threads ‹↑›

Threads are a type of concurrent process. The subject of concurrency in programming is large and often requires very precise thinking. The word 'concurrent' (ie running at the same time) is misleading. The JVM handles the switching between all concurrent threads Each time a thread is run by the virtual machine, its run() method is called.

Threads may be creating in (at least) two ways: By subclassing the Thread class, or by implementing the Runnable interface and passing it as a parameter to the Thread constructor eg: Thread p = new Thread(runnable);

The second method allows existing classes to act as threads.

create an anonymous thread

    new Thread() {
      public void run()
      {
        // do something
      }
    }.start();

Swingworker ‹↑›

The swingworker class is a type of Thread and is a way of performing long running tasks without blocking the Swing user interface. As a general guide, it is only ok to update Swing components from the process() and the done() methods of the SwingWorker thread. This is because these methods are executed on the swing event dispatch thread (EDT). SwingWorker subclasses are usually implemented as inner or anonymous inner classes.

www: http://java.sun.com/developer/technicalArticles/javase/swingworker/
A very good article about swingworker and an example image download application.
www: http://stackoverflow.com/questions/6113944/how-cancel-the-execution-of-a-swingworker/6114890#6114890
a verbose but exegesic SwingWorkder example
a worker thread that returns an array of icons and publishes one by one
 SwingWorker worker = new SwingWorker<ImageIcon[], ImageIcon>() {

set the progress property, for use with a progress bar, and listener

 this.setProgress(4);

cancel a SwingWorker thread (check isCancelled in doInBackground)

 swingWorker.cancel(true);

The code below is working, and is the basis of a file search utility. A SwingWorker thread is created to search for files having a certain string in their path or name.

Enhancements: to allow the search to be cancelled with worker.cancel(true). Allow the user to determine the root of the file search/ if unix hidden folders should be searched. etc

publish file search results in a JList using process()

   import javax.swing.*;
   import java.io.*;
   import java.util.*;
   import java.awt.event.*;
   import java.awt.*;
   public class SearchList extends JPanel implements ActionListener {
     JList list;
     JButton button;
     JTextField field;
     public SearchList() {
       super(new BorderLayout());
       Font georgia = new Font("Georgia", Font.ITALIC, 22);
       this.list = new JList(new DefaultListModel());
       this.button = new JButton("search");
       this.button.setFont(georgia);
       this.button.addActionListener(this);
       this.field = new JTextField(".mp3", 20);
       this.field.setFont(georgia);
       this.field.addActionListener(this);
       JPanel topPanel = new JPanel();
       topPanel.add(this.button); topPanel.add(this.field); 
       this.add(new JScrollPane(this.list), BorderLayout.CENTER);
       this.add(topPanel, BorderLayout.NORTH);
     }
     public void actionPerformed(ActionEvent e) {
       ((DefaultListModel)this.list.getModel()).removeAllElements();
       SearchTask t = new SearchTask(this.field.getText());
       t.execute();
     }
     public static void main(String[] args) {
       javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Search for Files with SwingWorker");
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.add(new SearchList());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setVisible(true);
         }
       });
     }
     class SearchTask extends SwingWorker<Void, File> {
       int filesFound;
       String text;
       File root;
       public SearchTask(String text) {
         super();
         this.filesFound = 0;
         this.text = text;
         this.root = new File("/home/");
       }
       protected Void doInBackground() {
         this.list(this.root, this.text);
         //while (!this.isCancelled()) { }
         return null;
       }
       protected void process(java.util.List<File> results) {
         DefaultListModel model = 
           (DefaultListModel) SearchList.this.list.getModel();
         for (File file: results) { model.addElement(file); }
       }
       /** find files with names matching a certain string */
       public void list(File dir, final String filter) {
         FileFilter ff = new FileFilter() {
           public boolean accept(File file) {
             return ((file.getAbsolutePath().indexOf(filter)>0) ||
                     file.isDirectory());
           }
         };
         File[] files = dir.listFiles(ff);
         for (File f: files) {
           if (f.isDirectory()) this.list(f, filter);
           else {
             this.publish(f);
             this.filesFound++;
           }
         }
       }
     }
   }

Ideas: improve speed of search

enhanced file search with an information label

   import javax.swing.*;
   import java.io.*;
   import java.util.*;
   import java.awt.event.*;
   import java.awt.*;
   import java.util.concurrent.*;
   public class SearchList extends JPanel implements ActionListener {
     JList list;
     JButton button;
     JTextField field;
     JLabel info;
     public SearchList() {
       super(new BorderLayout());
       Font georgia = new Font("Georgia", Font.ITALIC, 22);
       this.list = new JList(new DefaultListModel());
       this.button = new JButton("search");
       this.button.setFont(georgia);
       this.button.addActionListener(this);
       this.field = new JTextField(".mp3", 20);
       this.field.setFont(georgia);
       this.field.addActionListener(this);
       this.info = new JLabel("info:");
       this.info.setFont(georgia);
       JPanel topPanel = new JPanel();
       topPanel.add(this.button); topPanel.add(this.field); 
       this.add(new JScrollPane(this.list), BorderLayout.CENTER);
       this.add(topPanel, BorderLayout.NORTH);
       this.add(this.info, BorderLayout.SOUTH);
     }
     public void actionPerformed(ActionEvent e) {
       ((DefaultListModel)this.list.getModel()).removeAllElements();
       SearchTask t = new SearchTask(this.field.getText());
       t.execute();
     }
     public static void main(String[] args) {
       javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Search for Files with SwingWorker");
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.add(new SearchList());
           f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
           f.setVisible(true);
         }
       });
     }
     class SearchTask extends SwingWorker<Void, File> {
       int filesFound;
       String text;
       File root;
       long searchTime;
       public SearchTask(String text) {
         super();
         this.filesFound = 0;
         this.text = text;
         this.root = new File("/home/");
         this.searchTime = -1;
       }
       protected Void doInBackground() {
         this.searchTime = System.currentTimeMillis();
         this.list(this.root, this.text);
         this.searchTime = System.currentTimeMillis() - this.searchTime;
         //while (!this.isCancelled()) { }
         return null;
       }
       protected void done() {
         SearchList.this.info.setText(String.format(
           "Files found: %d, Time taken: %d ms, Root folder: %s",
           this.filesFound, this.searchTime, this.root)); 
       }
       protected void process(java.util.List<File> results) {
         SearchList.this.info.setText(String.format(
           "Files found: %d", this.filesFound));
         DefaultListModel model = 
           (DefaultListModel) SearchList.this.list.getModel();
         for (File file: results) { model.addElement(file); }
       }
       /** find files with names matching a certain string */
       public void list(File dir, final String filter) {
         FileFilter ff = new FileFilter() {
           public boolean accept(File file) {
             return ((file.getAbsolutePath().indexOf(filter)>0) ||
                     file.isDirectory());
           }
         };
         File[] files = dir.listFiles(ff);
         for (File f: files) {
           if (f.isDirectory()) this.list(f, filter);
           else {
             this.publish(f);
             this.filesFound++;
           }
         }
       }
     }
   }

Publishing Results ‹↑›

The SwingWorker class allows us to obtain 'intermediate' results from the worker thread. These results are produced while the thread is still active. To obtain these results we use the publish() method and the process() method.

Successive calls to publish() are coalesced into a java.util.List, which is what is received by process()

using publish() and process()

    this.publish(file);
    ...
    protected void process(java.util.List<File> results) {...}

The code below is not complete, see the SearchList example for a compilable example.

publish intermediate results of the worker thread using process(...)

   public class FlipTask extends SwingWorker<Void, FlipPair> {
     @Override
     protected Void doInBackground() {
       long heads = 0;
       long total = 0;
       Random random = new Random();
       while (!isCancelled()) {
         total++;
         if (random.nextBoolean()) { heads++; }
         publish(new FlipPair(heads, total));
       }
       return null;
     }
     protected void process(List<FlipPair> pairs) {
       FlipPair pair = pairs.get(pairs.size() - 1);
       headsText.setText(String.format("%d", pair.heads));
       totalText.setText(String.format("%d", pair.total));
       devText.setText(String.format(
         "%.10g", ((double) pair.heads)/((double) pair.total) - 0.5));
     }
   }

Getting Results With Swingworker ‹↑›

When the SwingWorker completes its work, it makes available the final results with the done() and the get() methods.

The SwingWorker's get method returns an item of the same type as specified as the first type parameter given to the SwingWorker class.

 class Worker extends SwingWorker<ArrayList<Integer>, Integer> {...}

The first template argument, in this case, ArrayList<Integer>, is whats returned by doInBackground(), and by get(). The second template argument, in this case, Integer, is what is published with the publish method. It is also the data type which is stored by the java.util.List that is the parameter for the process method, which recieves the information published by the publish method.

using the done() and get() methods to obtain final worker results

   import javax.swing.*;
   import java.io.*;
   import java.util.*;
   import java.awt.event.*;
   import java.awt.*;
   import java.util.concurrent.ExecutionException;
   public class SomeTask extends SwingWorker<File[], File> {
     @Override
     protected File[] doInBackground() {
       File[] list = new File[]{};
       while (!this.isCancelled()) {
         /* do some lengthy task filling File[] array 'list'  */
       }
       return list;
     }
   
     @Override
     protected void done() {
       /* here we can update our gui, because this is the EDT */
       System.out.println("doInBackground is complete");
       try {
         File[] results = this.get();
         for (File f: results) { }
       } catch (InterruptedException e) {
         System.out.println("Interrupted: " + e);
       } catch (ExecutionException e) {
         System.out.println("Execution: " + e);
       }
     }

   }

Cancelling A Swingworker Thread ‹↑›

Its often nice to be able to stop a long running task before it finishes. This is called cancelling the task.

When we call the swingWorker.cancel(true) method, is caused isCancelled() method to return true. We call this method frequently in the doInBackground() code and stop all work if it returns true.

create a button which cancels the SwingWorker

   JButton b = new JButton("cancel work");
   b.addActionListener(this);
   ...
   @Override
   public void actionPerformed(ActionEvent e) {
     swingWorker.cancel(true);
     swingWorker = null;
   }

Verbose Example ‹↑›

a verbose example showing how to use the done() method

   import javax.swing.*;
   import java.awt.*;
   import java.awt.event.*;
   import java.util.ArrayList;
   
   public class SwingWorkerExample extends JFrame implements ActionListener {
   
     private static final long serialVersionUID = 1L;
     private final JButton startButton, stopButton;
     private JScrollPane scrollPane = new JScrollPane();
     private JList listBox = null;
     private DefaultListModel listModel = new DefaultListModel();
     private final JProgressBar progressBar;
     private mySwingWorker swingWorker;
   
     public SwingWorkerExample() {
       super("SwingWorkerExample");
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       getContentPane().setLayout(new GridLayout(2, 2));
       startButton = makeButton("Start");
       stopButton = makeButton("Stop");
       stopButton.setEnabled(false);
       progressBar = makeProgressBar(0, 99);
       listBox = new JList(listModel);
       scrollPane.setViewportView(listBox);
       getContentPane().add(scrollPane);
       //Display the window.
       pack();
       setVisible(true);
     }
   
     private class mySwingWorker extends SwingWorker<ArrayList<Integer>, Integer> {

       @Override
       protected ArrayList<Integer> doInBackground() {
         if (SwingUtilities.isEventDispatchThread()) {
           System.out.println(
             "SwingUtilities.isEventDispatchThread() returned true.");
         }
         Integer tmpValue = new Integer(1);
         List<Integer> list = new ArrayList<Integer>();
         for (int i = 0; i < 100; i++) {
           for (int j = 0; j < 100; j++) { 
             //find every 100th prime, just to make it slower
             tmpValue = FindNextPrime(tmpValue.intValue());
             if (isCancelled()) {
               System.out.println("SwingWorker - isCancelled");
               return list;
             }
           }
           publish(new Integer(i));
           list.add(tmpValue);
         }
         return list;
       }
   
       @Override
       protected void process(java.util.List<Integer> progressList) {
         if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
           System.out.println(
             "SwingUtilities.isEventDispatchThread() + returned false.");
         }
         Integer percentComplete = 
           progressList.get(progressList.size() - 1);
         progressBar.setValue(percentComplete.intValue());
       }
   
       @Override
       protected void done() {
         System.out.println("doInBackground is complete");
         if (!SwingUtilities.isEventDispatchThread()) {
           System.out.println(
             "SwingUtilities.isEventDispatchThread() returned false.");
         }
         try {
           ArrayList<Integer> results = get();
           for (Integer i : results) {
             listModel.addElement(i.toString());
           }
         } catch (Exception e) {
           System.out.println("Caught an exception: " + e);
         }
         startButton();
       }
      //... 
     }
   
     @Override
     public void actionPerformed(ActionEvent e) {
       if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
         startButton.setEnabled(false);
         stopButton.setEnabled(true);
         // Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
         (swingWorker = new mySwingWorker()).execute(); // new instance
       } else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
         startButton.setEnabled(true);
         stopButton.setEnabled(false);
         swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
         swingWorker = null;
       }
     }
   }
   

Drawing With Java Two D ‹↑›

This section will almost exclusively concentrate on the Java2D drawing apis instead of the older AWT drawing system. The Java2D system allows high quality, antialiased drawing both to the screen and to other output devices, such as printers.

Drawing usually takes place within the 'paint' method of an awt component, or within the 'paintComponent' method of a swing component. This seems to mean that you have to subclass a component in order to draw. See below for specific examples.

Things doable with a javax.sound.sampled.Clip
getMicrosecondLength() - how many microseconds long is the audio
getFrameLength() - how many sound frames the audio has
setMicrosecondPosition(long) - set the current play position
setLoopPoints(int int) - loop between 2 particular frames in the audio
long getMicrosecondPosition() - how long the audio has been playing for
long getLongFramePosition() - the current frame position of the audio
AudioFormat getFormat() - the format of the playing audio

General drawing procedure:
Create a new shape eg new Ellipse2D.Double(x y, w, h)
set the stroke eg g.setStroke(new BasicStroke(...))
set the fill on the graphics objects
the draw with g.draw(shape) or g.fill(shape)

GRAPHICS2D ....

The Graphic2D class, which is part of the Java2D api, provides lots advantages over the older java.awt.Graphics class. Just one example is using anti-aliasing with text and shape drawing commands. (that is the g2d.setRenderingHints() method). Without anti-aliasing everything looks pretty terrible.

www: http://docstore.mik.ua/orelly/java-ent/jfc/
Some chapters from a good, but old book on Java2D
To take advantage of all these advantages we just cast the Graphics object

cast a Graphics object to a Graphics2D object when painting a jcomponent

   public void paintComponent(Graphics g) {
     Graphics2D g2d = (Graphics2D) g;
     ...
   }

COORDINATE SYSTEM FOR GRAPHICS2D ....

The coordinate system for the Java 2D api is cartesian, with the origen (by default) in the top left corner. Coordinates are measured in pixels when drawing to the screen, but in points when drawing to a printer. These coordinates are the 'user space' system. Unlike AWT, coordinates can be float or double values, to take advantage of very high resolution output devices (eg printers). These float values also allow high quality transforms of the coordinate system. This is referred to as converting from user space to device space.

The coordinate system can be transformed by various methods. Transformations on the coordinate system are cumulative and are save in an AffineTransform object which can be obtained with g2d.getTransform()

notes about drawing:
Swing is doubled buffered by default (according to camickr)

set the coodinate origen to point (13,10)

 g2d.translate(13.0, 10.0)

scale the coordinate system by 2 along both axis

 g2d.scale(2.0, 2.0)

After this method call, the point (0,0) will infact refer to the point (13,10) and all other points will be suitably translated

set the origen to lower left corner on a 500x500 pixel screen

 g.translate(0.0, 500.0);  g.scale(1.0, -1.0);

The negative scaling by 1 means that the y coordinates will increase going upwards, instead of downwards (which is the default)

save the current transform, apply a new one, and then restore

    Graphics2D g = ...;
    AffineTransform t = g.getTransform(); 
    g.rotate(theta);                     
    g.drawRect(100, 100, 200, 200);     
    g.setTransform(t); 

Coordinate Rotations ‹↑›

Rotations of the coordinate systems are expressed in radians and are about the origin or about a particular point.

rotate the coordinate system by 45 degrees about the origin

 g2d.rotate(Math.PI/4)

rotate the coordinates by 90 degrees about point (20,20)

 g2d.rotate(Math.PI/4, 20, 20)

draw some text at 45 degrees and then restore the default coordinates

   import java.awt.*;
   import java.awt.geom.*;
   import javax.swing.*;
   public class RotateCoords extends JPanel {
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D gg = (Graphics2D) g;
       gg.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
       gg.setFont(new Font("Georgia", Font.ITALIC, 30));
       gg.drawString("Hello world", 30, 30);
       gg.rotate(Math.PI/4);
       gg.drawString("Hello world", 30, 30);
       gg.rotate(-Math.PI/4);
     }
     public Dimension getPreferredSize() { return new Dimension(400, 400); }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new RotateCoords());
     }
   }

Drawing Text ‹↑›

http://docstore.mik.ua/orelly/java-ent/jfc/ch04_09.htm stuff about glyph vectors etc.

Glyphvectors ‹↑›

A glyph vector (java.awt.font.GlyphVector) is a kind of precalculated set of glyph measurements for a particular (one-line?) string and one font. GlyphVectors are useful for creating Shapes, Areas and Images from text or characters.

The GlyphVector is created using a FontRenderContext object which contains, for example, information about whether anti-aliasing or fractional metrics are currently in use for the given Font.

Apparently creating a GlyphVector can speed up drawing text for a particular Font and String but its hard to see when that would be important

coordinate transform methods
g2d.translate(x y) - set the coodinate origen to point (x,y)
g2d.scale() - scale the coordinate system
g2d.rotate(Math.PI/4) - rotate coordinates by 45 degrees about origin
g2d.rotate(rx,y) - rotate coordinates by radians about point (x,y)
g2d.shear(float float) - shear the coordinate system

See also java.awt.font.TextLayout for multifont vectors and java.awt.font.LineBreakMeasurer for multiline vectors.

create a glyph vector for the text 'hello'

   GlyphVector msg = 
     font.createGlyphVector(g.getFontRenderContext(), "Hello");
   g.drawGlyphVector(msg, 100.0f, 100.0f);

a complete text art example

   import java.awt.*;
   import java.awt.geom.*;
   import java.awt.font.GlyphVector;
   import javax.swing.*;
   public class TextArt extends JPanel {
     public void paintComponent(Graphics g) {
       Graphics2D gg = (Graphics2D) g;
       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_ON);
       Font font = new Font("Georgia", Font.ITALIC, 10); 
       Font bigfont = font.deriveFont(
         AffineTransform.getScaleInstance(25.0, 25.0));
       GlyphVector gv = bigfont.createGlyphVector(
         gg.getFontRenderContext(), "Hello");
       Shape outline = gv.getOutline();
       gg.translate(10,300); 
       gg.setStroke(new BasicStroke(5));
       gg.setColor(Color.gray);
       gg.draw(outline);
     }
     public Dimension getPreferredSize() { return new Dimension(600, 800); }
     public static void main(String[] args) { 
       JOptionPane.showMessageDialog(null, new TextArt());
     }
   }

create shapes from character glyphs and then use those shapes to draw

   Graphics2D g;
   Font font = new Font("Serif", Font.BOLD, 10);  // a basic font
   Font bigfont =
     font.deriveFont(AffineTransform.getScaleInstance(30.0, 30.0));
   GlyphVector gv = 
     bigfont.createGlyphVector(g.getFontRenderContext(), "JAV");
   Shape jshape = gv.getGlyphOutline(0);   // Shape of letter J
   Shape ashape = gv.getGlyphOutline(1);   // Shape of letter A
   Shape vshape = gv.getGlyphOutline(2);   // Shape of letter V
   g.fill(jshape);

Textlayouts ‹↑›

A java.awt.font.TextLayout is a way of drawing (with a Graphics2D object) strings of text in multiple fonts. It supports bi-directional text (mixing English with Arabic for example)

Antialiasing ‹↑›

Antialiasing is a technique for smoothing curves. Antialiasing makes everything look much nicer so there is really no reason why you would not use it, ever.

turn on antialiasing for all drawing operations

 g2.setRenderingHint(
   RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

With java2D text can also be antialiased

turn on antialiasing for text (with g2d.drawString())

   graphics2D.setRenderingHint(
     RenderingHints.KEY_TEXT_ANTIALIASING,
     RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

This doesnt seem to affect text in JTextComponents or JLabels etc.

draw shapes with antialiasing and without, to see the difference

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class AntialiasDraw extends Component {           
    public void paint(Graphics g) { 
         Graphics2D g2 = (Graphics2D) g;
         g2.setStroke(new BasicStroke(20));
         g2.draw(new RoundRectangle2D.Double(0, 0, 200, 200, 40, 40));
         g2.draw(new Ellipse2D.Double(10, 20, 180, 120)); 
         CubicCurve2D c = new CubicCurve2D.Double();
         c.setCurve(80, 80, 100, 100, 120, 60, 150, 80);
         g2.draw(c);
         g2.setRenderingHint(
           RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         g2.draw(new RoundRectangle2D.Double(240, 0, 440, 200, 40, 40));
         g2.draw(new Ellipse2D.Double(250, 20, 420, 120)); 
         CubicCurve2D d = new CubicCurve2D.Double();
         d.setCurve(320, 80, 340, 100, 360, 60, 390, 80);
         g2.draw(d);
     }
    public AntialiasDraw() {}
    public Dimension getPreferredSize() { return new Dimension(800, 300); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Drawing Shapes");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new AntialiasDraw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

Arcs ‹↑›

draw a filled arc and get its start point

   Graphics2D g2 = (Graphics2D) g;
   Arc2D arc = new Arc2D.Float(x, y, n, m, w, z, Arc2D.PIE);
   g2.fill(arch);
   Point2D p = arch.getStartPoint();

Bezier Curves ‹↑›

Quadratic Bezier curves use one control point Cubic Bezier curves use two control points

Quadratic Bezier Curves ‹↑›

A parabola is an example of a quadratic curve. In java, these curves have 2 end points and a point of inflexion (where the curve bends).

draw a quadratic curve

     QuadCurve2D q = new QuadCurve2D.Float();
     q.setCurve(0, 0, 80, 80, 160, 0);
     g2.draw(q);

 q.setCurve(x1, y1, controlx, controly, x2, y2);

useful methods for GlyphVector
getOutline() - returns a Shape representing the text
getGlyphOutline(1) - a Shape of the 2nd glyph in the string
getGlyphMetrics() - gets detailed measurements for one Glyph
setGlyphPosition() - adjust position of one glyph in the vector
setGlyphTransform() - add an AffineTransform to one glyph

Cubic Bezier Curves ‹↑›

// c.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);

Generalpaths ‹↑›

A GeneralPath which is a java.awt.geom.GeneralPath is a specific type of java.awt.Shape . By using moveTo(), lineTo(), quadTo() and curveTo() a complex Shape can be constructed. Also one can add other shapes to the path.

quadratic curve parameters
x1 y1 - the first end point of the curve
controlx controly - the point of inflexion of the curve
x2 y2 - the 2nd end point of the curve
curveTo(float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x3, floaty3) - Adds a cubic bezier curve segment to the current path

draw a polygon using the GeneralPath class

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class PolyDraw extends Component {           
    public void paint(Graphics g) { 
       Graphics2D g2 = (Graphics2D) g;
       g2.setStroke(new BasicStroke(5));
       int x1Points[] = {0, 100, 0, 100};
       int y1Points[] = {0, 50, 50, 0};
       GeneralPath polygon = 
         new GeneralPath(GeneralPath.WIND_EVEN_ODD, x1Points.length);
       polygon.moveTo(x1Points[0], y1Points[0]);
       for (int index = 1; index < x1Points.length; index++) {
         polygon.lineTo(x1Points[index], y1Points[index]);
       };
       polygon.closePath();
       g2.draw(polygon);
    }
    public PolyDraw() { }
    public Dimension getPreferredSize() { return new Dimension(250, 250); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Drawing a Polygon");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new PolyDraw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

Examples ‹↑›

draw a line

     public void paint (Graphics g) {
         Graphics2D g2 = (Graphics2D) g;
         g2.draw(new Line2D.Double(x1, y1, x2, y2));
     }

The getPreferredSize() method is necessary because otherwise the java jre doesnt know how big to make the window, and makes it very small.

draw a line on a component using the Graphics2D class

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class LineDraw extends Component {           
    public void paint(Graphics g) { 
       Graphics2D g2 = (Graphics2D) g;
       g2.draw(new Line2D.Double(0, 0, 200, 200));
    }
    public LineDraw() { }
    public Dimension getPreferredSize() { return new Dimension(220, 220); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Drawing a Line");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new LineDraw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

draw a rounded rectangle, an oval and a quadratic curve

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class LineDraw extends Component {           
    public void paint(Graphics g) { 
         Graphics2D g2 = (Graphics2D) g;
         g2.setRenderingHint(
           RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         g2.setStroke(new BasicStroke(5));
         g2.draw(new RoundRectangle2D.Double(0, 0, 200, 200, 40, 40));
         g2.draw(new Ellipse2D.Double(10, 20, 180, 120)); 
         QuadCurve2D q = new QuadCurve2D.Float();
         q.setCurve(0, 0, 80, 80, 160, 0);
         g2.draw(q);
         CubicCurve2D c = new CubicCurve2D.Double();
         c.setCurve(80, 80, 100, 100, 120, 60, 150, 80);
         g2.draw(c);
     }
    public LineDraw() { }
    public Dimension getPreferredSize() { return new Dimension(250, 250); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Drawing a Line");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new LineDraw());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

draw with a thick stroke and colours and gradient colours

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class Draw extends Component {           
    public void paint(Graphics g) {
      Graphics2D g2 = (Graphics2D)g;
      Line2D line = new Line2D.Double(10, 10, 40, 40);
      g2.setColor(Color.blue);
      g2.setStroke(new BasicStroke(10));
      g2.draw(line);
      Rectangle2D rect = new Rectangle2D.Double(20, 20, 100, 100);
      g2.draw(rect);
      g2.setPaint(new GradientPaint(0, 0, Color.blue, 50, 25, Color.green, true));
      g2.fill(rect);
    }
    public Draw() { }
    public Dimension getPreferredSize() { return new Dimension(150, 150); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Drawing a Line");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new Draw());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

Strokes ‹↑›

The stroke of a line or curve refers to its thickness, texture etc. By defining new strokes it is possible to create dotted lines, textured lines. The simplest technique is to use the BasicStroke class, and for more complicated needs, one can implement a stroke class. The stroke is set on the graphics object and then applies for all drawing operations until the stroke is changed.

set the stroke to 40 pixels wide

 g2d.setStroke(new BasicStroke(40));

draw with a thick stroke using the BasicStroke class

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class ThickStroke extends JComponent {           
    public void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D)g;
      g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      RoundRectangle2D rect = 
        new RoundRectangle2D.Double(40, 40, 300, 300, 80, 80);
      g2.setStroke(new BasicStroke(40));
      g2.setColor(Color.darkGray);
      g2.draw(rect);
    }
    public ThickStroke() {}
    public Dimension getPreferredSize() { return new Dimension(400, 400); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Thick Strokes");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new ThickStroke());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

draw a rounded rectangle with a dashed (10px blank) line 6 pixels wide

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class DashStroke extends JComponent {           
    public void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D)g;
      g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      RoundRectangle2D rect = 
        new RoundRectangle2D.Double(40, 40, 300, 300, 80, 80);
      BasicStroke dashed = new BasicStroke(
        6, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 
        10.0f, new float[]{10.0f}, 0.0f);
      g2.setStroke(dashed); g2.setColor(Color.darkGray);
      g2.draw(rect);
    }
    //public DashStroke() {}
    public Dimension getPreferredSize() { return new Dimension(400, 400); }
    public static void main(String[] args) { 
        JOptionPane.showMessageDialog(null, new DashStroke());
    }
  }

Basicstrokes ‹↑›

BasicStrokes are immutable- they have no set() methods. So instances can be shared.

GeneralPath methods
moveTo(10.0f 20.0f) - Moves to point
lineTo(float x float y) - Adds a line segment to the current path
quadTo(float ctrlx float ctrly, float x2, floaty2) Adds a quadratic bezier curve segment to the current path
closePath() Closes the current path and makes a closed Shape

BasicStroke end-cap attribute, where a line ends
BasicStroke.CAP_BUTT - not line 'cap' line ends at point specified
BasicStroke.CAP_SQUARE - line projects beyond end point square end
BasicStroke.CAP_ROUND - line projects beyond end point round end

a BasicStroke example with no dash parameters

    g.setStroke(new BasicStroke(
      5.0f,                     // The pixel width of the line 
      BasicStroke.CAP_ROUND,    // how lines end 
      BasicStroke.JOIN_ROUND)); // how lines are joined together 

Stroke Interface ‹↑›

We can also create new strokes by implementing the stroke interface. which only involves implementing one method createStrokedShape()

Dashed Strokes ‹↑›

The BasicStroke can also take a dash array and a dash phase parameter. The dash phase is useful for creating animations (see the marching ants example).

The dash pattern array can consist in any number of values indicating alternate dashes and gaps.

a dash pattern: draw 21px, blank 9px, draw 3px, blank 9px

 new float[] {21.0f, 9.0f, 3.0f, 9.0}

a BasicStroke with miter limit and dash pattern

  Stroke s = new BasicStroke(
    4.0f,                      // width of the line 
    BasicStroke.CAP_SQUARE,    // extend line end in square ending 
    BasicStroke.JOIN_MITER,    // join lines with points 
    10.0f,                     // truncate miter if longer than 10px 
    new float[] {16.0f, 20.0f},// draw 16pixels, blank 20pixels 
    0.0f);                     // Dash phase (start position in pixels)

Filling Shapes ‹↑›

Filling refers to painting the interior of a shape with a colour, a colour gradient or a texture.

The .fill method draws the interior of a shape but not its border

To create a GradientPaint, you specify a beginning position and color and an ending position and color. The gradient changes proportionally from one color to the other color along the line connecting the two positions.

The position parameters for the gradient paint appear to be absolute, not relative to the shape you are trying to paint.

paint a rounded rectangle with gradient paint with no border

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.JFrame;
  public class Draw extends Component {           
    public void paint(Graphics g) {
      Graphics2D g2 = (Graphics2D)g;
      GradientPaint grad = new GradientPaint(20,20,Color.BLUE,180, 180,Color.WHITE);
      g2.setPaint(grad);
      g2.fill(new RoundRectangle2D.Double(40, 40, 140, 140, 30, 30));
    }
    public Draw() { }
    public Dimension getPreferredSize() { return new Dimension(200, 200); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Strokes");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new Draw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

The example above uses the technique of placing the gradient end points outside of the shape to make the gradient more subtle. A better way would be to use colour shades which are closer together

The following is an attempt to produce the bulgeing effect that is common in interfaces these days, but doesnt quite work.

a horizontal bar with a vertical green gradient paint

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.JFrame;
  public class Draw extends Component {           
    public void paint(Graphics g) {
      Graphics2D g2 = (Graphics2D)g;
      Color limeGreen = new Color(Integer.decode("#32cd32"));
      Color drabOlive = new Color(Integer.decode("#6b8e23"));
      //Color lawnGreen = new Color(Integer.decode("#7CFC00"));
      //Color yellowGreen = new Color(Integer.decode("#ADFF2F"));
      GradientPaint grad = 
        new GradientPaint(20, 20, limeGreen, 20, 40, drabOlive);
      g2.setPaint(grad);
      g2.fill(new Rectangle2D.Double(20, 20, 500, 40));
    }
    public Draw() { }
    public Dimension getPreferredSize() { return new Dimension(550, 100); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Strokes");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new Draw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

draw a dashed rounded rectangle and filled with a gradient paint

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.JFrame;
  public class Draw extends Component {           
    public void paint(Graphics g) {
      Graphics2D g2 = (Graphics2D)g;
      RoundRectangle2D rect = 
        new RoundRectangle2D.Double(40, 40, 200, 200, 80, 80);
      float dash1[] = {10.0f};
      BasicStroke dashed = new BasicStroke(
           6, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
      g2.setStroke(dashed);
      g2.draw(rect);
      GradientPaint grad = new GradientPaint(0,0,Color.GREEN,200, 0,Color.WHITE);
      g2.setPaint(grad);
      g2.fill(rect);
    }
    public Draw() { }
    public Dimension getPreferredSize() { return new Dimension(400, 400); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Strokes");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new Draw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

Shapes ‹↑›

A Shape or java.awt.Shape is an interface which represents either an open curve or else a closed area. With an AffineTransform we can scale, rotate, translate, and shear Shapes.

http://docstore.mik.ua/orelly/java-ent/jfc/ch04_04.htm A good chapter on shapes.

BasicStroke join-style values, where 2 lines meet
JOIN_BEVEL - a flat corner a little beyond the join point
JOIN_MITER - a pointed corner just beyond the join point (default)
JOIN_ROUND - a round corner just beyond the join point.

methods operating on shapes
g2d.fill(shape) - fills with a colour or paint closes an open shape
g2d.draw(shape) - draws the outline of the shape
g2d.clip(shape) - restricts drawing area to the shape bounds
g2d.hit(...) - check if a rectangle touches a shape

With ovals or ellipses, the x and y parameters represent the top left hand corner of the bounding rectangle for the ellipse (not its centre).

create a square shape

 Shape square = new Rectangle2D.Float(100.0f, 100.0f, 100.0f, 100.0f);

create a shape by subtracting one area from another

    Area area = new Area(new Rectangle2D.Double(...));
    Area inner = new Area(new Rectangle2D.Double(...));
    area.subtract(inner);

create a shape (based on some text) and draw it on an image with a stroke

   final BufferedImage textImage = new BufferedImage(
     width, height, BufferedImage.TYPE_INT_ARGB);
   Graphics2D g = textImage.createGraphics();
   FontRenderContext frc = g.getFontRenderContext();
   Font font = new Font("Arial", Font.BOLD, 250);
   GlyphVector gv = font.createGlyphVector(frc, "Cat");
   Rectangle2D box = gv.getVisualBounds();
   int xOff = 25+(int)-box.getX();
   int yOff = 80+(int)-box.getY();
   Shape shape = gv.getOutline(xOff,yOff);
   g.setColor(Color.WHITE);
   //g.setClip(null);
   g.setStroke(new BasicStroke(2f));
   g.setColor(Color.BLACK);
   g.setRenderingHint(
     RenderingHints.KEY_ANTIALIASING,
     RenderingHints.VALUE_ANTIALIAS_ON);
   g.draw(shape);
   g.dispose();

The code above draws the word cat in a big hollow font (its not really a font)

create a shape by adding two contigous areas, java2d

 Graphics2D g2d = (Graphics2D) g;
        // turn Anti-aliasing on to make the corners smooth
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(2));
        g.setColor(Color.BLACK);
        // create the callout "tip"
        int tipCenter = x+width/3;
        GeneralPath p = new GeneralPath();
        p.moveTo(tipCenter-insets.top/2, y+insets.top/2);
        p.lineTo(tipCenter, 0);
        p.lineTo(tipCenter+insets.top/2, y+insets.top/2);
        p.closePath();
        // create the shape
        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y+insets.top/2, width-1, height-1-insets.top/2, 20, 20);
        Area area = new Area(rect);
        area.add( new Area(p) );
        g2d.draw(area); // draw the shape

Areas ‹↑›

Areas (java.awt.geom.Areas) are a particular type of java.awt.Shape (they implement the Shape interface) and they allow one to define areas by subtracting or by the union of other areas or shapes. Unlike Shapes, Areas are alway closed. An interesting point is that if an Area is constructed from several intersecting shapes, it will form a single non intersecting area.

Like Shapes we can scale, rotate, translate and shear areas with an AffineTransform.

some shape implementations in java.awt and java.awt.geom
java.awt.Rectangle Rectangle2D.Float, Rectangle2D.Double - Rectangle
java.awt.Polygon - Polygon
RoundRectangle2D.Float RoundRectangle2D.Double - Rounded rectangle
Ellipse2D.Float Ellipse2D.Double - Ellipse (and circle)
Line2D.Float Line2D.Double - Line segment
Arc2D.Float Arc2D.Double - Arc (ellipse segment)
QuadCurve2D.Float QuadCurve2D.Double - Bezier curve (quadratic)
CubicCurve2D.Float CubicCurve2D.Double - Bezier curve (cubic)

define and show a shape (area) which is a square less a circle

   import javax.swing.*;
   import java.awt.geom.*;
   import java.awt.*;
   public class SubtractArea extends JPanel {
     protected void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D g2d = (Graphics2D) g;
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
       Shape square = new Rectangle2D.Float(100.0f, 100.0f, 100.0f, 100.0f);
       Shape circle = new Ellipse2D.Float(100.0f, 100.0f, 100.0f, 100.0f);
       Area area = new Area(square);
       area.subtract(new Area(circle));
       g2d.fill(area);
     }
     public Dimension getPreferredSize() { return new Dimension(400, 600); }
     public static void main(String[] args) { 
       JOptionPane.showMessageDialog(null, new SubtractArea());
     }
   }
   

Gradient Paints ‹↑›

GradientPaints are either cyclic or acyclic. Interesting effects can be achieved by creating gradient paints with translucent colours (colours which will be blended with the component background colour)

The technique below creates a nice looking gradient for a professional looking interface.

a trick to create nice gradients

  GradientPaint gp = new GradientPaint(0, 0,
             getBackground().brighter().brighter(), 0, getHeight(),
             getBackground().darker().darker());

A problem with the following example is that if the background color is already as bright as possible (for example rgb(255,0,0) then the brighter() method does nothing, and therefor the GradientPaint will have much less 'range' of color than otherwise.

a complete gradient paint example using brighter etc

   import java.awt.*;
   import javax.swing.*;
   public class GradientBackgroundDemo {
     public static void main(String args[]) {
       JFrame f = new JFrame("Gradient Background Demo");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       JPanel contentPane = new JPanel() {
         @Override
         protected void paintComponent(Graphics g) {
           Graphics2D g2d = (Graphics2D) g;
           g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
           GradientPaint gp = new GradientPaint(0, 0,
             getBackground().brighter().brighter(), 0, getHeight(),
             getBackground().darker().darker());
           g2d.setPaint(gp);
           g2d.fillRect(0, 0, getWidth(), getHeight());
           super.paintComponent(g);
         }
       };
       contentPane.setOpaque(false);
       contentPane.setBackground(Color.green);
       f.setContentPane(contentPane);
       contentPane.add(new JLabel("A Gradient Paint"));
       f.setSize(200, 200);
       f.setVisible(true);
     }
   }

Setting opaque to false is vital in the above example to stop swing painting a solid colour with super.paintComponent On my linux computer I cant see any difference with antialiasing switched on or off

 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, ....);

a gradient paint from red to orange, top left to bottom right

  Graphics2D imageGraphics = image.createGraphics();
    GradientPaint gp = new GradientPaint(
      20f, 20f, Color.red, 380f, 280f, Color.orange);
  imageGraphics.setPaint(gp);
  imageGraphics.fillRect(0, 0, 400, 300);

The above is a reasonably nice effect

another type of gradient paint with several colors\

   Color[] colors = { Color.RED, Color.YELLOW, Color.GREEN };
   g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
   g2.fillRect(x, y, 100, 10);

draw a box with a green gradient paint

   // This one alternates between deep opaque green and transparent green.
   // Note: the 4th arg to Color() constructor specifies color opacity
   g.setPaint(new GradientPaint(0, 0, new Color(0, 150, 0),
                                20, 20, new Color(0, 150, 0, 0), true));
   g.setStroke(new BasicStroke(15));         // use wide lines
   g.drawRect(25, 25, WIDTH-50, HEIGHT-50);  // draw the box

make a radial paint

 RadialPaint

CompoundPaint can use several different types of paint

Cyclic Gradientpaints ‹↑›

paint a square with a diagonal cyclic gradient paint

   import java.awt.*;
   import javax.swing.*;
   public class CyclicPaint extends JPanel {
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D gg = (Graphics2D) g;
       Paint p =
         new GradientPaint(0, 0, Color.red, 50, 50, Color.pink, true);
       gg.setPaint(p);
       gg.fillRect(0, 0, 300, 300);
     }
     public Dimension getPreferredSize() { return new Dimension(400, 400); }
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(null, new CyclicPaint());
     }
   }

Texture Paints ‹↑›

Another technique for filling shapes is to tile an image within the shape. This uses the TexturePaint class.

The pattern for the tiling of a TexturePaint class is defined by a BufferedImage class. To create a TexturePaint object, you specify the image that contains the pattern and a Rectangle2D that is used to replicate and anchor the pattern. Then you use the setPaint() method as for gradient paints

Advanced Painting ‹↑›

If none of the available painting classes is suitable, you may implement the Paint interface, and pass your class to the setPaint method of the graphics object

Drawing Onto Images ‹↑›

It is possible to draw onto a blank image. The purpose of this is to allow you to save the drawing.

skeleton code

   import java.awt.image.*;
   class Painting extends JPanel {
     BufferedImage grid;  // declare the image
     public void paintComponent(Graphics g) {
       super.paintComponent(g);       // paint background
       Graphics2D g2 = (Graphics2D)g; // we need a Graphics2D context
       if (grid == null) {
         // Compute the grid only one time
         int w = this.getWidth();
         int h = this.getHeight();
         grid = (BufferedImage)(this.createImage(w,h));
         Graphics2D gc = grid.createGraphics();
         for (int x=0; x<w; x+=10) {
           gc.drawLine(x, 0, x, h);
         }
         for (int y=0; y<h; y+=10) {
           gc.drawLine(0, y, w, y);
         }
       }
       // Draw the grid from the precomputed image
       g2.drawImage(grid, null, 0, 0);
       . . . // d
       incomplete
   

draw a filled rectangle onto a buffered image and display in JLabel

   BufferedImage bi = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
   Graphics2D g = bi.createGraphics();
   GradientPaint gp = new GradientPaint(
     20f,20f,Color.red, 180f,180f,Color.yellow);
   g.setPaint(gp);
   g.fillRect(0,0,200,200);
   ImageIcon ii = new ImageIcon(bi);
   JLabel imageLabel = new JLabel(ii);

Why does A. Thompson use an argb image here, and not an rgb image? that is the question.

Transforms ‹↑›

a tutorial on transforming shapes with Graphics2D

 http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html

how to use the AffineTransform with Graphics2D

 http://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html

interesting Area methods
new Area(shape) - make a new Area from a Shape
getBounds2D() - get a Rectangle2D which just encloses this area
isRectangular() - tests if this Area is a rectangle
intersect(area) - sets the area to intersection of this and other

Awt Drawing ‹↑›

The old awt drawing methods are extremely limited. Here is an example

draw a some shapes using the old awt graphics class (limited)

  import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  public class ShapeDraw extends Component {           
    public void paint(Graphics g) {
      g.drawLine(10,10,40,40);
      g.drawRect(20, 20, 100, 100);
      g.fillRect(120, 120, 200, 200);
    }
    public ShapeDraw() {}
    public Dimension getPreferredSize() { return new Dimension(400, 600); }
    public static void main(String[] args) { 
        JFrame f = new JFrame("Drawing Stuff");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new ShapeDraw());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

Images ‹↑›

Image Information ‹↑›

read an image from a url and get its height and width

   URL url = new URL("http://i.stack.imgur.com/Nqf3H.jpg");
   final BufferedImage originalImage = ImageIO.read(url);
   int width = originalImage.getWidth();
   int height = originalImage.getHeight();

create a new image icon

 ImageIcon i = new ImageIcon(imgURL, "some image");

get an image size without reading the whole image

   ImageInputStream in = ImageIO.createImageInputStream(resourceFile);
   try {
     final Iterator readers = ImageIO.getImageReaders(in);
     if (readers.hasNext()) {
       ImageReader reader = (ImageReader) readers.next();
       try {
         reader.setInput(in);
         return new Dimension(reader.getWidth(0), reader.getHeight(0));
       }
       finally {  reader.dispose(); }
     }
   }
   finally {if (in != null) in.close(); }

load an image into a component

  import java.awt.*;
  import java.awt.event.*;
  import java.awt.image.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;

  public class ImageApp extends Component implements KeyListener {           
    BufferedImage img;
    File[] imageList;
    public ImageApp() {
       try { this.img = ImageIO.read(new File("test.jpg"));}
       catch (IOException e) { System.out.println("Image File not found"); }
       // this.addKeyListener(this);
    }
 
    public void paint(Graphics g) { 
	g.drawImage(
          img, 0, 0, 400, (img.getHeight() * 400)/img.getWidth(), null);
	g.setFont(new Font("Georgia", Font.ITALIC, 20));
        g.drawString("Hello graphics", 20, 30); 
    }
 
    public void keyTyped(KeyEvent e) 
    {
      char key = e.getKeyChar();
      System.out.println("key typed:" + key); 
      switch (key)
      {
        case 'h': 
          this.setVisible(false);
          break;
        case 'l': 
          JFileChooser c = new JFileChooser();
          c.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
          int result = c.showOpenDialog(this);
          java.io.File folder = c.getSelectedFile();
          System.out.println("folder selected:" + folder ); 
          this.imageList = folder.listFiles();
          System.out.println("Files:" + java.util.Arrays.toString(this.imageList));
          break;
        default:
          break;
      }
    }
    public void keyPressed(KeyEvent e) {} 
    public void keyReleased(KeyEvent e) {}
      
    public Dimension getPreferredSize() {
        if (img == null) {
             return new Dimension(100,100);
        } else {
           //return new Dimension(img.getWidth(null), img.getHeight(null));
           return new Dimension(400, 600);
       }
    }
 
    public static void main(String[] args) { 
        JFrame f = new JFrame("Load Image Sample");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	ImageApp li = new ImageApp();
        f.add(li);
        f.addKeyListener(li);
	li.requestFocusInWindow();
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
  }

Loading Images ‹↑›

load an image

     try { img = ImageIO.read(new File("villa.jpg"));}
     catch (IOException e) { System.out.println("Image File not found"); }

Trying to read a file which is not an image but exists, doesnt seem to throw an IOException, it just leaves the image object as null.

The 'im' object will be null after the following statement

 Buffered im = ImageIO.read("doc.pdf");

load an image from a jar file

     java.net.URL imgURL = ImageDemo.class.getResource("path/to/image");
     if (imgURL != null)
       { return new ImageIcon(imgURL, "a description"); }
     else {
       System.err.println("Couldn't find file: " + path);
       return null;
     }

Progress Of Image Operations ‹↑›

Operations on images may well take noticeable time. For that reason it would usually be a good idea do display to the user some indication of progress during the read/write/filter operation. This can be done with interfaces such as IIOReadProgressListener added to an ImageReader object, or and IIOWriteProgressListener added to an ImageWriter (?) object.

See the jprogressbar section for another example of displaying progress using a SwingWorker thread.

The code below works but seems unnecessarily complicated. Need to simplify. Also, there is a problem when painting the JPanel- it appears to only paint the BorderLayout.CENTER part of the panel.

an image load with progress bar and swingworker, working

   import java.awt.*;
   import java.awt.event.*;
   import java.awt.image.*;
   import javax.swing.*;
   import java.beans.*;
   import java.io.*;
   import java.net.*;
   import java.util.Iterator;
   import javax.imageio.*;
   import javax.imageio.event.IIOReadProgressListener;
   import javax.imageio.stream.*;
   import java.util.concurrent.ExecutionException;
   public class ImageProgress extends JPanel implements ActionListener {
     private JProgressBar progressBar;
     private JButton startButton;
     private Task task;
     BufferedImage image;
     public BufferedImage getImage() {
       return this.image;
     }
     public ImageProgress() {
       super(new BorderLayout());
       this.image = null;
       this.startButton = new JButton("Load");
       this.startButton.addActionListener(this);
       this.progressBar = new JProgressBar(0, 100);
       this.progressBar.setValue(0); progressBar.setStringPainted(true);
       JPanel panel = new JPanel();
       panel.add(startButton); panel.add(progressBar);
       this.add(panel, BorderLayout.PAGE_START);
     }
     private Image load() { 
       //URL imgUrl = 
         // new URL("http://bumble.sourceforge.net/doc/cv/mjb-inchair.jpg");
       Image image = null;
       try {
         URL imgUrl = new URL("file:big.jpg");
         InputStream is = imgUrl.openStream();
         ImageInputStream iis = ImageIO.createImageInputStream(is);
         Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
         ImageReader reader = it.next();
         reader.setInput(iis);
         reader.addIIOReadProgressListener(new IIOReadProgressListener() {
           public void sequenceStarted(ImageReader source, int minIndex) {}
           public void sequenceComplete(ImageReader r) {}
           public void imageStarted(ImageReader r, int imageIndex) {}
           public void imageProgress(ImageReader r, float percentageDone) {
           //System.out.format("Percent Downloaded: %f\n", percentageDone);
             ImageProgress.this.progressBar.setValue((int)percentageDone);
           }
           public void imageComplete(ImageReader source) { }
           public void thumbnailStarted(
             ImageReader r, int imageIndex, int thumbnailIndex) { }
           public void thumbnailProgress(ImageReader r, float percentDone) 
            { }
           public void thumbnailComplete(ImageReader source) {}
           public void readAborted(ImageReader source) {}
         });
         image = reader.read(0);
       } 
       catch (MalformedURLException e) {}
       catch (IOException e) {}
       return image;
     }
     public void paintComponent(Graphics g) { 
       super.paintComponent(g);
       if (this.image != null) {
         int scaleWidth = 500;
         int scaleHeight = 10;
         float factor = (float) scaleWidth / image.getWidth();
         scaleHeight = (int) (factor * image.getHeight());
         g.drawImage(this.image, 0, 0, scaleWidth, scaleHeight, null);
       }
     }
     public Dimension getPreferredSize() {
       return (new Dimension(600, 600)); 
     }
     public void actionPerformed(ActionEvent evt) {
       startButton.setEnabled(false);
       setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
       this.task = new Task();
       this.task.execute();
     }
     public static void main(String[] args) {
       javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame f = new JFrame("Image Load");
           f.add(new ImageProgress()); 
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.pack(); f.setLocationRelativeTo(null);
           f.setVisible(true);
         }
       });
     }
     class Task extends SwingWorker<Image, Void> {
       @Override
       public Image doInBackground() {
         Image i = ImageProgress.this.load();
         return i;
       }
       @Override
       public void done() {
         try {
           ImageProgress.this.startButton.setEnabled(true);
           ImageProgress.this.progressBar.setValue(100);
           ImageProgress.this.progressBar.setString("Image Loaded");
           ImageProgress.this.image = (BufferedImage) this.get();
           ImageProgress.this.setCursor(null); //turn off the wait cursor
           ImageProgress.this.repaint();
         } catch (InterruptedException e) {}
           catch (ExecutionException e) {}
       }
     }
   }

code to demostrate how to show the progress of an image (down)load

   import java.awt.Image;
   import java.io.*;
   import java.net.MalformedURLException;
   import java.net.URL;
   import java.util.Iterator;
   import java.util.concurrent.ExecutionException;
   import javax.imageio.*;
   import javax.imageio.event.IIOReadProgressListener;
   import javax.imageio.stream.*;
   import javax.swing.*;
   public class ImageProgress {
     public static void main(String[] args) throws MalformedURLException, IOException {
       //URL imgUrl = new URL("http://bumble.sourceforge.net/doc/cv/mjb-inchair.jpg");
       URL imgUrl = new URL("file:big.jpg");
       InputStream is = imgUrl.openStream();
       ImageInputStream iis = ImageIO.createImageInputStream(is);
       Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
       ImageReader reader = it.next();
       reader.setInput(iis);
       reader.addIIOReadProgressListener(new IIOReadProgressListener() {
         public void sequenceStarted(ImageReader source, int minIndex) {}
         public void sequenceComplete(ImageReader r) {}
         public void imageStarted(ImageReader r, int imageIndex) {}
         public void imageProgress(ImageReader r, float percentageDone) {
           System.out.format("Percent Downloaded: %f\n", percentageDone);
         }
         public void imageComplete(ImageReader source) {
           System.out.println("Download Completed");
         }
         public void thumbnailStarted(
           ImageReader r, int imageIndex, int thumbnailIndex) { }
         public void thumbnailProgress(ImageReader r, float percentDone) {}
         public void thumbnailComplete(ImageReader source) {}
         public void readAborted(ImageReader source) {}
       });
       Image image = reader.read(0);
       Icon icon = new ImageIcon(image);
     }
   }

Displaying Images ‹↑›

display an image without scaling

 g.drawImage(img, 0, 0, null);

display an image in a JLabel using an image icon

   import java.awt.*;
   import java.awt.image.*;
   import javax.swing.*;
   import javax.imageio.ImageIO;
   import java.io.*;
   public class ImageLabel {
     public static void main(String[] args) throws Exception {
       final BufferedImage image = ImageIO.read(new File("villa.jpg"));
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            JLabel l = new JLabel(new ImageIcon(image)); 
            JOptionPane.showMessageDialog(null, l);
         }
       });
     }
   }

The technique below leaves the job of loading the image to the container component. This may facilitate using a ProgressListener during the ImageIO.read process.

a simple image display component

  import java.awt.*;
  import java.awt.image.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;
  public class ImageComponent extends Component {           
    BufferedImage image;
    public void paint(Graphics g) { 
	g.drawImage(this.image, 0, 0, null);
    }
    public ImageComponent(BufferedImage image) {
      this.image = image;
    }
    public Dimension getPreferredSize() {
      return this.getParent().getSize(); 
    }
    public static void main(String[] args) { 
       long startTime = System.currentTimeMillis(); 
       BufferedImage i;
       try { 
         i = ImageIO.read(new File("test.jpg")); 
         ImageComponent c = new ImageComponent(i); 
         JFrame f = new JFrame();
         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         f.add(c); f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
         f.setVisible(true);
         long endTime = System.currentTimeMillis(); 
         f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
       }
       catch (IOException e) 
        { System.out.println("Image file couldnt be read"); }
    }
  }

a simple panel which displays an image, name and size

  import java.awt.*;
  import java.awt.image.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;
  class ImageComponent extends Component {           
    BufferedImage image;
    public ImageComponent(BufferedImage image) {
      this.image = image;
    }
    public BufferedImage getImage() {
      return this.image;
    }
    public void paint(Graphics g) { 
      g.drawImage(this.image, 0, 0, null);
    }
    public Dimension getPreferredSize() {
      return this.getParent().getSize(); 
    }
  }
  public class ImagePanel extends JPanel {           
    ImageComponent imageDisplay;
    JLabel info;
    public ImagePanel(String imageName) {
      super(new BorderLayout());
      try { 
        BufferedImage i = ImageIO.read(new File(imageName)); 
        this.imageDisplay = new ImageComponent(i);
        this.info = new JLabel(String.format(
          "Image: %s, Dimensions: %dx%d", 
            imageName, i.getWidth(), i.getHeight()));
        this.add(this.imageDisplay, BorderLayout.CENTER);
        this.add(this.info, BorderLayout.SOUTH);
      }
      catch (IOException e) {
         this.add(new JLabel("Image file couldnt be read"));
      } 
    }
    public static void main(String[] args) { 
       long startTime = System.currentTimeMillis(); 
       ImagePanel p = new ImagePanel("test.jpg");  
       JFrame f = new JFrame();
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(p); f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setVisible(true);
       long endTime = System.currentTimeMillis(); 
       f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
    }
  }

display an image in a JLabel allowing the user to choose a file

   import java.awt.*;
   import java.awt.event.*;
   import java.awt.image.*;
   import javax.swing.*;
   import javax.imageio.ImageIO;
   import java.io.*;
   public class ChooseImage extends JPanel implements ActionListener {
     JButton button; 
     JLabel imageLabel;
     String imageName;
     Image image;
     public ChooseImage()
     {
       super(new BorderLayout());
       this.button = new JButton("Choose an Image");
       this.button.addActionListener(this);
       this.imageLabel = new JLabel();
       this.imageName = new String("...");
       this.add(this.button, BorderLayout.NORTH);
       this.add(this.imageLabel, BorderLayout.CENTER);
     }

     public void setImage(File imageFile)
     {
       try { 
         this.image = ImageIO.read(imageFile); 
         //this.imageName = imageName;
         this.imageLabel.setIcon(new ImageIcon(this.image));
       }
       catch (IOException e) 
        { System.out.println("Image file couldnt be read"); }
     }

     public void actionPerformed(ActionEvent e) 
     {
       if (e.getSource() == this.button) {
         JFileChooser chooser = new JFileChooser();
         int result = chooser.showOpenDialog(null);
         File file = chooser.getSelectedFile();
         if (result == JFileChooser.APPROVE_OPTION) {
           this.setImage(file);
           this.imageLabel.setText("yes");
         }
       }
       repaint();
     }

     public static void main(String[] args) throws Exception {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           try {
           UIManager.setLookAndFeel(
             "javax.swing.plaf.nimbus.NimbusLookAndFeel");
            } catch (Exception eee) {} 

            long startTime = System.currentTimeMillis(); 
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.getContentPane().add(new ChooseImage());
            f.setExtendedState(Frame.MAXIMIZED_BOTH);
            f.pack(); 
            f.setVisible(true);
            long endTime = System.currentTimeMillis(); 
            f.setTitle("Image loaded in " + (endTime-startTime) + " ms");

         }
       });
     }
   }

load an image and display it scaled to 400 by 600

  import java.awt.*;
  import java.awt.image.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;
  public class DisplayImage extends Component {           
    BufferedImage img;
    public void paint(Graphics g) { 
	g.drawImage(img, 0, 0, 400, 600, null);
    }
    public DisplayImage() {
       try 
        { img = ImageIO.read(new File("test.jpg")); }
       catch (IOException e) 
        { System.out.println("Image file couldnt be read"); }
    }
    public Dimension getPreferredSize() 
      { return new Dimension(400, 600); }
    public static void main(String[] args) { 
        long startTime = System.currentTimeMillis(); 
        JFrame f = new JFrame("Load and Display Image Example");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new DisplayImage());
        f.pack(); f.setLocationRelativeTo(null);
        f.setVisible(true);
        long endTime = System.currentTimeMillis(); 
        f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
    }
  }

displaying an image in a tooltip for a JLabel using swing html (A. Thompson)

import javax.swing.*; import java.awt.GridLayout; class ThumbTip { private static final String HTML = "<html><body>"; ThumbTip(String[] album) { JPanel p = new JPanel(new GridLayout(1,0,2,2)); for (String url : album) { String s = HTML + "<img src='" + url.toString() + "'"; String size = " width=200 height=150"; JLabel l = new JLabel(s + size + ">"); l.setToolTipText(s + ">"); p.add(l); } JOptionPane.showMessageDialog(null, p); } public static void main(String[] args) { final String[] urls = { "http://pscode.org/media/stromlo1.jpg", "http://pscode.org/media/stromlo2.jpg" }; SwingUtilities.invokeLater(new Runnable() { public void run() { new ThumbTip(urls); } }); } } ,,,

Gotchas ‹↑›

The getPreferredSize must be less than the screen width

    public Dimension getPreferredSize() {
      return new Dimension(image.getWidth(), image.getHeight());
    }

The above may produce an 'out of heap space error'

Scaling Images ‹↑›

Images can be scaled with the old (since java 1.1) image.getScaledInstance() or else with the more modern graphics.drawImage(). The getScaledInstance method produces reasonable results but may be slower than drawImage. Another technique is to use AffineTransforms to do the scaling, but this is considered more complicated that the drawImage method. To summarise, the drawImage method is prefered.

www: http://weblogs.java.net/blog/chet/archive/2004/07/imageio_just_an.html
good stuff about image scaling
www: http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
An important article about how to scale with drawImage(...) and produce good results- basically scale by half until a good size is reached

Getscaledinstance To Scale An Image ‹↑›

 Image.getScaledInstance(SCALE_AREA_AVERAGING)

some transformation methods for the Graphics2D class
rotate()
scale()
translate()
translate(AffineTransform)
SCALE_REPLICATE: Specific hint that provides higher performance, but lower-quality, "blocky" results. SCALE_FAST: General hint meaning "I prefer speed over quality, but I'm not picky about the exact algorithm;" in Sun's current implementation (JDK 6 at the time of this writing) this is synonymous with SCALE_REPLICATE. SCALE_AREA_AVERAGING: Specific hint that is slower, but provides higher-quality, "filtered" results. SCALE_SMOOTH: General hint meaning "I prefer quality over speed, but I'm not picky about the exact algorithm;" in Sun's current implementation, this is generally synonymous with SCALE_AREA_AVERAGING. (As with the other hints, this mapping is implementation-dependent and subject to change; read the Performance Notes section below for more on how this mapping could change in an upcoming release of Sun's JDK implementation.) SCALE_DEFAULT: General hint meaning "I don't care, just pick something for me;" in Sun's current implementation, this is synonymous with SCALE_FAST.

hints for the getScaledInstance(...) method
VALUE_INTERPOLATION_NEAREST_NEIGHBOR: Specific hint that provides higher performance, but lower-quality, "blocky" results. VALUE_INTERPOLATION_BILINEAR: Specific hint that is typically a bit slower, but provides higher-quality, "filtered" results. VALUE_INTERPOLATION_BICUBIC: Specific hint that is similar to BILINEAR except that it uses more samples when filtering and therefore has generally higher quality than BILINEAR. (Note: this hint constant has been available since JDK 1.2, but was not implemented by Sun until the JDK 5 release; prior to that release, this hint was synonymous with BILINEAR.)

scale an image to 400x200 and display in JLabel

   import java.awt.*;
   import java.awt.image.*;
   import javax.swing.*;
   import javax.imageio.ImageIO;
   import java.io.*;
   public class ImageLabel {
     public static void main(String[] args) throws Exception {
       final BufferedImage image = ImageIO.read(new File("villa.jpg"));
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
             Image scaledImage = 
                image.getScaledInstance (400, 200, Image.SCALE_SMOOTH);
             ImageIcon icon = new ImageIcon(scaledImage);
             JPanel p = new JPanel();
             p.add(new JLabel(icon));
             JOptionPane.showMessageDialog(null, p);
         }
       });
     }
   }

a simple algorithm to scale preserving image aspect ration

       final int newWidth = 400;
       float factor = (float) newWidth / image.getWidth();
       int newHeight = (int) (factor * image.getHeight());

App Notes:

The application below could be the skeleton for a useful application for manipulating an image using keystrokes

the method call repaint() is necessary after setting a new image in the ImageComponent. This shows that the paint method is only called when strictly necessary (when the window is resized etc).

RenderingHints.VALUE_INTERPOLATION_BICUBIC gives much higher quality results than RenderingHints.VALUE_INTERPOLATION_BILINEAR but is very slow.

In the example above for some reason adding the keylistener on the JPanel doesnt work, but on the JFrame, yes. Probably because the panel doesnt have focus.

It is proving difficult to get the ImageComponent to resize to the image size, probably because the BorderLayout does not respect the getPreferredSize() method, and just makes the CENTER component as big as possible.

a simple panel which can scale an image on a keystroke

  import java.awt.*;
  import java.awt.image.*;
  import java.awt.event.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;
  public class ImagePanel extends JPanel implements KeyListener {           
    BufferedImage original;
    BufferedImage image;
    ImageComponent imageDisplay;
    JLabel info;
    public ImagePanel(String imageName) {
      super(new BorderLayout());
      try { 
        this.image = ImageIO.read(new File(imageName)); 
        this.imageDisplay = new ImageComponent(this.image);
        this.info = new JLabel(String.format(
          "Image: %s, Dimensions: %dx%d", 
            imageName, this.image.getWidth(), this.image.getHeight()));
        this.add(this.imageDisplay, BorderLayout.CENTER);
        this.add(this.info, BorderLayout.SOUTH);
      }
      catch (IOException e) {
         this.add(new JLabel("Image file couldnt be read"));
      } 
    }
    public void keyTyped(KeyEvent e) {
       switch (e.getKeyChar()) {
         case 's': 
           this.scale(0.8f); break;
         case 'S': 
           this.scale(0.5f); break;
         case 'b': 
           this.scale(1.2f); break;
         case 'B': 
           this.scale(2.0f); break;
         case 'x': 
           System.exit(0); break;
         default:
           break;
      }
    } 
    public void keyPressed(KeyEvent e) {} 
    public void keyReleased(KeyEvent e) {}
    private void scale(float factor) {
      int newWidth = (int) (this.image.getWidth() * factor);
      int newHeight = (int) (this.image.getHeight() * factor);
      int type = (this.image.getTransparency() == Transparency.OPAQUE) ?
               BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
      BufferedImage tmp = new BufferedImage(newWidth, newHeight, type);
      Graphics2D g2 = tmp.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                         RenderingHints.VALUE_INTERPOLATION_BICUBIC);
      g2.drawImage(this.image, 0, 0, newWidth, newHeight, null);
      g2.dispose();
      this.image = tmp;
      this.imageDisplay.setImage(this.image);
      //this.revalidate();
      this.repaint();
    }

    public static void main(String[] args) { 
       long startTime = System.currentTimeMillis(); 
       ImagePanel p = new ImagePanel("test.jpg");  
       JFrame f = new JFrame();
       f.addKeyListener(p);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.add(p); f.pack(); f.setExtendedState(Frame.MAXIMIZED_BOTH);
       f.setVisible(true);
       long endTime = System.currentTimeMillis(); 
       f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
    }
  }
  class ImageComponent extends JComponent {           
    BufferedImage image;
    public ImageComponent(BufferedImage image) {
      this.image = image;
    }
    public BufferedImage getImage() {
      return this.image;
    }
    public void setImage(BufferedImage image) {
      this.image = image; 
    }
    public void paintComponent(Graphics g) { 
      super.paintComponent(g);
      int x = 0; int y = 0;
      // draw the image in the center of the component
      if (this.getSize().getWidth() > this.image.getWidth()) 
        x = (int)(this.getSize().getWidth() - this.image.getWidth())/2; 
      if (this.getSize().getHeight() > this.image.getHeight()) 
        y = (int)(this.getSize().getHeight() - this.image.getHeight())/2; 
      g.drawImage(this.image, x, y, null);
    }
    public Dimension getPreferredSize() {
      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
      if (this.image.getWidth() >= screen.getWidth() ||
          this.image.getHeight() >= screen.getHeight())
        return this.getParent().getSize(); 
      else
        return new Dimension(this.image.getWidth(), this.image.getHeight());
    }
  }
 

scale an image to width 400 preserving the aspect ratio

   import java.awt.*;
   import java.awt.image.*;
   import javax.swing.*;
   import javax.imageio.ImageIO;
   import java.io.*;
   public class ImageLabel {
     public static void main(String[] args) throws Exception {
       final BufferedImage image = ImageIO.read(new File("villa.jpg"));
       final int newWidth = 400;
       float factor = (float) newWidth / image.getWidth();
       int newHeight = (int) (factor * image.getHeight());
       Image scaledImage = 
          image.getScaledInstance(
            newWidth, newHeight, Image.SCALE_SMOOTH);
       ImageIcon icon = new ImageIcon(scaledImage);
       JPanel p = new JPanel();
       p.add(new JLabel("A scaled image", icon, JLabel.CENTER));
       JOptionPane.showMessageDialog(null, p);
     }
   }

scale an image and display information about load times etc

   import java.awt.*;
   import java.awt.image.*;
   import javax.swing.*;
   import javax.imageio.ImageIO;
   import java.io.*;
   public class ImageLabel {
     public static void main(String[] args) throws Exception {
       long startTime = System.currentTimeMillis();
       File imageFile = new File("test.jpg");
       final BufferedImage image = ImageIO.read(imageFile);
       long readTime = System.currentTimeMillis() - startTime;
       final int newWidth = 400;
       float factor = (float) newWidth / image.getWidth();
       int newHeight = (int) (factor * image.getHeight());
       long startScale = System.currentTimeMillis();
       Image scaledImage = 
          image.getScaledInstance(
            newWidth, newHeight, Image.SCALE_SMOOTH);
       long scaleTime = System.currentTimeMillis() - startScale;
       long iconTime = System.currentTimeMillis();
       ImageIcon icon = new ImageIcon(scaledImage);
       iconTime = System.currentTimeMillis() - iconTime;
       JLabel label = new JLabel(icon);
       // put the text under the image
       label.setHorizontalTextPosition(JLabel.CENTER);
       label.setVerticalTextPosition(JLabel.BOTTOM);
       long totalTime = System.currentTimeMillis() - startTime;
       String text = String.format(
         "<html><ul>" +
         "<li>original width: %d" +
         "<li>original height: %d" +
         "<li>Image file size: %d bytes" +
         "<li>Image read in %d ms (ImageIO.read)" +
         "<li>Image scaled in %d ms (getScaledInstance)" +
         "<li>Time to create the ImageIcon was %d ms" +
         "<li>Total time taken was %d ms" +
         "</ul>",
         image.getWidth(), image.getHeight(), imageFile.length(),
         readTime, scaleTime, iconTime, totalTime);
       label.setText(text);
       JOptionPane.showMessageDialog(null, label);
     }
   }

What we can see from the above is that the creation of the ImageIcon takes a very long time, and reading the image takes a considerable amount of time, but scaling the image even though we are using the older getScaledInstance method is relatively fast.

align the text of a label underneath its image icon

    label.setHorizontalTextPosition(JLabel.CENTER);
    label.setVerticalTextPosition(JLabel.BOTTOM);

some hints for drawImage()

    g.setComposite(AlphaComposite.Src);
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
      RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g.setRenderingHint(RenderingHints.KEY_RENDERING,
      RenderingHints.VALUE_RENDER_QUALITY);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
      RenderingHints.VALUE_ANTIALIAS_ON);

A component to scale an image to a width and maintain aspect ratio

  import java.awt.*;
  import java.awt.image.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;
  public class DisplayImage extends Component {           
    private int scaleWidth;
    private int scaleHeight;
    BufferedImage image;
    public void paint(Graphics G) { 
      Graphics2D g = (Graphics2D) G; 
      g.drawImage(image, 0, 0, scaleWidth, scaleHeight, null);
    }
    public DisplayImage(String imageName, int scaleWidth) {
      this.scaleWidth = scaleWidth;
      try {
        image = ImageIO.read(new File(imageName)); 
        float factor = (float) scaleWidth / image.getWidth();
        this.scaleHeight = (int) (factor * image.getHeight());
      }
      catch (IOException e) 
       { System.out.println("Image file couldnt be read"); }
    }
    public Dimension getPreferredSize() 
      { return new Dimension(this.scaleWidth, this.scaleHeight); }
    public static void main(String[] args) { 
      JOptionPane.showMessageDialog(
        null, new DisplayImage("test.jpg", 400));
    }
  }

The drawImage() method produces noticeably bad results when scaling to a small factor

scale an image with drawImage() and show benchmark times etc

  import java.awt.*;
  import java.awt.image.*;
  import java.io.*;
  import javax.imageio.*;
  import javax.swing.*;
  public class DisplayImage extends Component {           
    private int scaleWidth;
    private int scaleHeight;
    public long scaleTime;
    public long readTime;
    BufferedImage image;
    public void paint(Graphics g) { 
        this.scaleTime = System.currentTimeMillis();
	g.drawImage(image, 0, 0, scaleWidth, scaleHeight, null);
        this.scaleTime = System.currentTimeMillis() - this.scaleTime;
    }
    public DisplayImage(int scaleWidth) {
       this.scaleWidth = scaleWidth;
       try {
         this.readTime = System.currentTimeMillis();
         image = ImageIO.read(new File("test.jpg")); 
         this.readTime = System.currentTimeMillis() - this.readTime;
         float factor = (float) scaleWidth / image.getWidth();
         this.scaleHeight = (int) (factor * image.getHeight());
       }
       catch (IOException e) 
        { System.out.println("Image file couldnt be read"); }
    }
    public Dimension getPreferredSize() 
      { return new Dimension(this.scaleWidth, this.scaleHeight); }
    public static void main(String[] args) { 
        long totalTime = System.currentTimeMillis();
        DisplayImage component = new DisplayImage(300);
        totalTime = System.currentTimeMillis() - totalTime;
        JLabel label = new JLabel();
        String text = String.format(
         "<html><ul>" +
         "<li>Image read in %d ms (ImageIO.read)" +
         "<li>Image scaled in %d ms with g.drawImage(...)" +
         "<li>Total time taken was %d ms" +
         "</ul>",
         component.readTime, component.scaleTime, totalTime);
       label.setText(text);
       JPanel p = new JPanel(new GridLayout(0,1));
       p.add(component); p.add(new JLabel(text));
       JOptionPane.showMessageDialog(null, p);
    }
  }

scale an image by 50% with getScaledInstance and a 'hint'

     Image image = imageIcon.getImage ();
     int width = (int) (0.5 * image.getWidth (null));
     int height = (int) (0.5 * image.getHeight (null));
     Image newImage = image.getScaledInstance (width, height, Image.SCALE_SMOOTH);
     ImageIcon newImageIcon = new ImageIcon(newImage);

draw an image scaling to frame size, but this ignores aspect ratio

 g.drawImage(BuffImg,0,0,getWidth(),getHeight(),this):

resize (scale) an image

    BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
    Graphics2D g = resizedImage.createGraphics();
    g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
    g.dispose();

This example is incomplete, because you still need to actually write the new image to file- but that is not difficult

scale all image files in a folder

   import java.awt.*;
   import java.awt.image.*;
   import javax.imageio.ImageIO;
   import java.io.File;
   
   /** ImageScaler
    *
    * This class loads all images in a given directory and scales them to
    * the given sizes, saving the results as JPEG files in a new "scaled/"
    * subdirectory of the original directory.
    */

   public class ImageScaler {
   
     // Default w/h values; overriden by command-line -width/-height parameters
     static int IMAGE_W = 150;
     static int IMAGE_H = 250;

     public static void main(String args[]) {
       // Default directory is current directory, overridden by -dir parameter
       String imagesDir = ".";
       for (int i = 0; i < args.length; ++i) {
         if (args[i].equals("-dir") && ((i + 1) < args.length)) {
           imagesDir = args[++i];
         } else if (args[i].equals("-width") && ((i + 1) < args.length)) {
           IMAGE_W = Integer.parseInt(args[++i]);
         } else if (args[i].equals("-height") && ((i + 1) < args.length)) {
           IMAGE_H = Integer.parseInt(args[++i]);
         }
       }
       // new subdirectory for scaled images
       String scaledImagesDir = imagesDir + File.separator + "scaled";
       // directory that holds original images
       File cwd = new File(imagesDir);
       // directory for scaled images
       File subdir = new File(scaledImagesDir);
       subdir.mkdir();
       File files[] = cwd.listFiles();
       // temporary image for every scaled instance
       BufferedImage scaledImg = new BufferedImage(IMAGE_W, IMAGE_H,
           BufferedImage.TYPE_INT_RGB);
       Graphics2D gScaledImg = scaledImg.createGraphics();
       // Note the use of BILNEAR filtering to enable smooth scaling
       gScaledImg.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                   RenderingHints.VALUE_INTERPOLATION_BILINEAR);
       for (int i = 0; i < files.length; ++i) {
         try {
           // For every file in the directory, assume it's an image and
           // load it
           BufferedImage img = ImageIO.read(files[i]);
           // If we get here, we must have read the image file successfully.
           // Create a new File in the scaled subdirectory
           File scaledImgFile = new File(scaledImagesDir + File.separator +
                                         files[i].getName());
           // Scale the original image into the temporary image
           gScaledImg.drawImage(img, 0, 0, IMAGE_W, IMAGE_H, null);
           // Save the scaled version out to the file
           ImageIO.write(scaledImg, "jpeg", scaledImgFile);
         } catch (Exception e) {
           System.out.println("Problem with " + files[i]);
         }
       }
     }
   }

According to romain guy antialiasing is useless, the best way is rescale by half with 'bilinear'

a method to resize an image

   private static BufferedImage resize(
     BufferedImage image, int width, int height) {
     int type = 
       image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
     BufferedImage resizedImage = new BufferedImage(width, height, type);
     Graphics2D g = resizedImage.createGraphics();
     g.setComposite(AlphaComposite.Src);
     g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
     g.setRenderingHint(RenderingHints.KEY_RENDERING,
                        RenderingHints.VALUE_RENDER_QUALITY);
     g.drawImage(image, 0, 0, width, height, null);
     g.dispose();
     return resizedImage;
   }

using affinetransforms to do scaling, not a complete example

   public void paintComponent(Graphics g) {
     Graphics2D g2 = (Graphics2D)g;
     AffineTransform oldXform = g2.getTransform();
     g2.scale(2.0, 2.0);
     g2.drawImage(img, 0, 0, null);
     // Or I sometimes see this even more complicated approach...
     // AffineTransform xform = AffineTransform.getScaleInstance(2, 2);
     // g2.drawImage(img, xform, null);
     g2.setTransform(oldXform); // restore transform
   }

an attempt to blur an image, but blurring is probably more complex

   public static BufferedImage blurImage(BufferedImage image) {
     float ninth = 1.0f/9.0f;
     float[] blurKernel = {
       ninth, ninth, ninth,
       ninth, ninth, ninth,
       ninth, ninth, ninth
     };
   
     Map map = new HashMap();
     map.put(RenderingHints.KEY_INTERPOLATION,
             RenderingHints.VALUE_INTERPOLATION_BILINEAR);
     map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
     map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
     RenderingHints hints = new RenderingHints(map);
     BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
     return op.filter(image, null);
   }
   
   private static BufferedImage createCompatibleImage(BufferedImage image) {
     GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
     int w = image.getWidth();
     int h = image.getHeight();
     BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
     Graphics2D g2 = result.createGraphics();
     g2.drawRenderedImage(image, null);
     g2.dispose();
     return result;
   }

an on the fly scale method

   private float xScaleFactor, yScaleFactor = ...;
   private BufferedImage originalImage = ...;

   public void paintComponent(Graphics g) {
     Graphics2D g2 = (Graphics2D)g;
     int newW = (int)(originalImage.getWidth() * xScaleFactor);
     int newH = (int)(originalImage.getHeight() * yScaleFactor);
     g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                         RenderingHints.VALUE_INTERPOLATION_BILINEAR);
     g2.drawImage(originalImage, 0, 0, newW, newH, null);
   }

downscale by 2 until the correct width/ height is achieved

   public BufferedImage getScaledInstance(BufferedImage img,
                                          int targetWidth,
                                          int targetHeight)
   {
     int type = (img.getTransparency() == Transparency.OPAQUE) ?
                BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
     BufferedImage ret = (BufferedImage)img;
     int w, h;
       // Use multi-step technique: start with original size, then
       // scale down in multiple passes with drawImage()
       // until the target size is reached
       w = img.getWidth();
       h = img.getHeight();
   
     do {
       if (w > targetWidth) {
         w /= 2;
         if (w < targetWidth) { w = targetWidth; }
       }
   
       if (h > targetHeight) {
         h /= 2;
         if (h > targetHeight) { h = targetHeight; }
       }
       BufferedImage tmp = new BufferedImage(w, h, type);
       Graphics2D g2 = tmp.createGraphics();
       g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                          RenderingHints.VALUE_INTERPOLATION_BILINEAR);
       g2.drawImage(ret, 0, 0, w, h, null);
       g2.dispose();
       ret = tmp;
     } while (w != targetWidth || h != targetHeight);
     return ret;
   }

a complete example of multistep downscale

   import java.awt.*;
   import java.awt.image.*;
   import java.io.*;
   import javax.imageio.*;
   import javax.swing.*;
   public class DisplayImage extends Component {
     private int scaleWidth;
     private int scaleHeight;
     BufferedImage image;
     public void paint(Graphics G) {
       // some hints to improve quality, but dont work
       Graphics2D g = (Graphics2D) G;
       BufferedImage scaled = this.getScaledInstance(image, scaleWidth, scaleHeight);
       //g.drawImage(image, 0, 0, scaleWidth, scaleHeight, null);
       g.drawImage(scaled, 0, 0, null);
     }
     public DisplayImage(String imageName, int scaleWidth) {
       this.scaleWidth = scaleWidth;
       try {
         image = ImageIO.read(new File(imageName));
         float factor = (float) scaleWidth / image.getWidth();
         this.scaleHeight = (int) (factor * image.getHeight());
       }
       catch (IOException e)
         { System.out.println("Image file couldnt be read"); }
     }
     public Dimension getPreferredSize()
       { return new Dimension(this.scaleWidth, this.scaleHeight); }
     
     public static void main(String[] args) {
       JOptionPane.showMessageDialog(
         null, new DisplayImage("test.jpg", 400));
     }

     // Use multi-step technique: scale by 1/2 until target size.
     public BufferedImage getScaledInstance(BufferedImage img,
                                            int targetWidth,
                                            int targetHeight)
     {
       int type = (img.getTransparency() == Transparency.OPAQUE) ?
                  BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
       BufferedImage ret = (BufferedImage)img;
       int w, h;
       w = img.getWidth();
       h = img.getHeight();
       do {
         if (w > targetWidth) {
           w /= 2; if (w < targetWidth) w = targetWidth; 
         }
   
         if (h > targetHeight) {
           h /= 2; if (h > targetHeight) h = targetHeight;
         }
         BufferedImage tmp = new BufferedImage(w, h, type);
         Graphics2D g2 = tmp.createGraphics();
         g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                             RenderingHints.VALUE_INTERPOLATION_BILINEAR);
         g2.drawImage(ret, 0, 0, w, h, null);
         g2.dispose();
         ret = tmp;
       } while (w != targetWidth || h != targetHeight);
       return ret;
     }
   
   }

multistep downscale with more parameters

   public BufferedImage getScaledInstance(
     BufferedImage img, int targetWidth, int targetHeight, Object hint,
                    boolean higherQuality)
   {
     int type = (img.getTransparency() == Transparency.OPAQUE) ?
                BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
     BufferedImage ret = (BufferedImage)img;
     int w, h;
     if (higherQuality) {
       // Use multi-step technique: start with original size, then
       // scale down in multiple passes with drawImage()
       // until the target size is reached
       w = img.getWidth(); h = img.getHeight();
     } else {
       // Use one-step technique: scale directly from original
       // size to target size with a single drawImage() call
       w = targetWidth; h = targetHeight;
     }
   
     do {
       if (higherQuality &amp;&amp; w > targetWidth) {
         w /= 2;
         if (w < targetWidth) { w = targetWidth; }
       }
   
       if (higherQuality &amp;&amp; h &gt; targetHeight) {
         h /= 2;
         if (h < targetHeight) { h = targetHeight; }
       }
   
       BufferedImage tmp = new BufferedImage(w, h, type);
       Graphics2D g2 = tmp.createGraphics();
       g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
       g2.drawImage(ret, 0, 0, w, h, null);
       g2.dispose();
       ret = tmp;
     } while (w != targetWidth || h != targetHeight);
     return ret;
   }

Clipping Images ‹↑›

Clipping in this context refers to drawing an image within a particular shape, such as an oval or within the shape of text.

draw an image in the shape of some text using a clip, save image as png file

   // get the width and the height from the original image
   URL url = new URL("http://i.stack.imgur.com/Nqf3H.jpg");
   final BufferedImage originalImage = ImageIO.read(url);
   int width = originalImage.getWidth();
   int height = originalImage.getHeight();
   final BufferedImage textImage = new BufferedImage(
     width, height, BufferedImage.TYPE_INT_ARGB);
   Graphics2D g = textImage.createGraphics();
   FontRenderContext frc = g.getFontRenderContext();
   Font font = new Font("Arial", Font.BOLD, 250);
   GlyphVector gv = font.createGlyphVector(frc, "Cat");
   Rectangle2D box = gv.getVisualBounds();
   int xOff = 25+(int)-box.getX();
   int yOff = 80+(int)-box.getY();
   Shape shape = gv.getOutline(xOff,yOff);
   g.setColor(Color.WHITE);
   g.setClip(shape);
   g.drawImage(originalImage,0,0,null);
   g.dispose();
   ImageIO.write(textImage,"png",new File("cat-text.png"));

Icons ‹↑›

javax.swing.Icon is an interface designed to allow the creation of decorations for components

An idea: we can create a 'symbol' icon class which implements the icon interface and paints a glyph from the dingbats or miscelanous unicode blocks onto an icon. Or even a random icon class which paints a selection of dingbats. Maybe for decoration. We could then convert the icon to a BufferedImage as per below and save it into a gif file etc.

a simple implementation of the icon interface which just paints a color

   import java.awt.*;
   import javax.swing.Icon;
   public class ColorIcon implements Icon {
     private Color color;
     private int width;
     private int height;
   
     public ColorIcon(Color color, int width, int height) {
       this.color = color;
       this.width = width;
       this.height = height;
     }
   
     public int getIconWidth() { return width; }
     public int getIconHeight() { return height; }
     public void paintIcon(Component c, Graphics g, int x, int y) {
       g.setColor(color);
       g.fillRect(x, y, width, height);
     }
   }

Imageicons ‹↑›

create a jlabel with icon from a scaled buffered image

   BufferedImage img = ...;
   JLable l = new JLabel(new ImageIcon(img.getScaledInstance(
    img.getWidth(null)/2, img.getHeight(null)/2, Image.SCALE_SMOOTH))); 

convert an ImageIcon to a BufferedImage

    ImageIcon imageIcon = 
      new ImageIcon("http://pscode.org/media/stromlo2.jpg");
    JLabel imageLabel = new JLabel(
        "A Horse", imageIcon, SwingConstants.CENTER);
    JOptionPane.showMessageDialog(null, imageLabel);
    Icon icon = imageLabel.getIcon();
    BufferedImage bi = new BufferedImage(
        icon.getIconWidth(),
        icon.getIconHeight(),
        BufferedImage.TYPE_INT_RGB);
    Graphics g = bi.createGraphics();
    // paint the Icon to the BufferedImage.
    icon.paintIcon(null, g, 0,0);

Predefined Icons ‹↑›

You can obtain access to some of javas 'built-in' icons through the UIManager class and its static getIcon() method.

Get the option pane 'information' icon (usually a big blue 'I')

 Icon infoIcon = UIManager.getIcon("OptionPane.informationIcon");

get the icon which the operating system uses to display the File f

 FileSystemView.getFileSystemView().getSystemDisplayName(f);

show the icon which the system uses to display a folder

    import javax.swing.*;
    import javax.swing.filechooser.FileSystemView;
    public class SystemIcon {
      public static void main(String[] args) {
        JOptionPane.showMessageDialog(null, 
          new JLabel(FileSystemView.getFileSystemView().getSystemIcon(
            new java.io.File("."))));
      }
    }

show the the system file and folder icons

    import javax.swing.*;
    import javax.swing.filechooser.FileSystemView;
    import java.io.File;
    public class SystemIcon {
      public static void main(String[] args) {
        Icon folderIcon = 
          FileSystemView.getFileSystemView().getSystemIcon(new File("."));
        Icon fileIcon = 
          FileSystemView.getFileSystemView().getSystemIcon(
            new File("eg/SystemIcon.java"));
        JOptionPane.showMessageDialog(null, new JLabel(fileIcon));
      }
    }

The icons below are not particularly attractive but maybe better than nothing. To change the example below to a JList, only 2 lines of code need to be changed: JList box = new JList(icons); box.setCellRenderer(...)

Strangely the JList component has a setCellRenderer() method and the JComboBox a setRenderer() method

a combobox displaying most of the java standard icons and names

   import java.awt.*;
   import java.io.File;
   import javax.swing.*;
   import java.lang.reflect.*;
   public class IconComboBox {
     public static void main(String[] args) {
       SwingUtilities.invokeLater( new Runnable() {
         public void run() {
           String[] icons = {
             "OptionPane.questionIcon", "OptionPane.errorIcon",
             "OptionPane.informationIcon", "OptionPane.warningIcon",
             "FileView.directoryIcon", "FileView.fileIcon",
             "FileView.computerIcon", "FileView.hardDriveIcon",
             "FileView.floppyDriveIcon", "FileChooser.newFolderIcon",
             "FileChooser.upFolderIcon", "FileChooser.homeFolderIcon",
             "FileChooser.detailsViewIcon", "FileChooser.listViewIcon",
             "Tree.expandedIcon", "Tree.collapsedIcon",
             "Tree.openIcon", "Tree.leafIcon", "Tree.closedIcon"
             };
           JComboBox box = new JComboBox(icons);
           box.setFont(new Font("Georgia", Font.ITALIC, 22));
           box.setRenderer(new IconRenderer());
           JOptionPane.showMessageDialog(null, box);
         }
       });
     }
   }
   class IconRenderer extends DefaultListCellRenderer {
     public Component getListCellRendererComponent(
       JList list, Object value, int index,
       boolean isSelected, boolean cellHasFocus) {
       JLabel label = (JLabel)super.getListCellRendererComponent(
         list,value,index,isSelected,cellHasFocus);
       if (value instanceof String) {
         String s = (String)value;
         label.setIcon(UIManager.getIcon(s));
       } 
       return label;
     }
   }

trying to retrieve all predefined icons but throwing weird exceptions

   import java.awt.GridLayout;
   import java.awt.event.*;
   import javax.swing.*;
   public class AllIconsDragAndDrop {
     public static void main(String[] args) {
       JFrame f = new JFrame("Icon Drag & Drop");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       JPanel p = new JPanel(new GridLayout(0,4));
       MouseListener listener = new DragMouseAdapter();
       String[] ss = {"informationIcon", "warningIcon", "errorIcon"};
       Icon icon; JLabel label;
       java.util.Enumeration keys = UIManager.getDefaults().keys();
       while (keys.hasMoreElements()) {
         Object k = keys.nextElement();
         Object value = UIManager.get(k);
         if (value instanceof javax.swing.Icon) {
           System.out.println(k);
           icon = UIManager.getIcon((String)k);
             label = new JLabel(icon);
             p.add(label);
           //label = new JLabel((String)k);
           //label.setIcon(icon);
           //JOptionPane.showMessageDialog(null, icon);
         }
       }
       f.getContentPane().add(p); 
           try {
       f.pack();
       f.setLocationRelativeTo(null);  
           }
           catch (ClassCastException e) {
             System.out.println("noooo");
             System.exit(-1);
             }
       f.setVisible(true);
     }
   }

Screen Shots ‹↑›

A screen-shot is an image taken of what happens to be on the computer screen at a given time.

www: http://www.javarichclient.com/4-ways-to-capture-a-screenshot/
Complete info about ways to get screen shots
4 methods to capture a screen shot.

capture the entire screen

   import java.awt.image.*;
   public class ScreenShotPanel extends JPanel implements KeyListener {
     public BufferedImage captureEntireScreen() throws AWTException {
       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
       Rectangle screenBounds = new Rectangle(screenSize);
       return new Robot().createScreenCapture(screenBounds);
     }
     public void keyTyped(KeyEvent e) {
       switch (e.getKeyChar()) {
       case 's':
         this.captureEntireScreen();
         break;
       case 'S':
         break;
       default:
         break;
       }
       //this.setInfo();
       //repaint();
     }
     public void keyPressed(KeyEvent e) {}
     public void keyReleased(KeyEvent e) {}
   }

capture a region of the screen

   public BufferedImage captureScreenRegion(int x, int y, int width, int height) throws AWTException {
     Rectangle screenRegion = new Rectangle(x, y, width, height);
     return new Robot().createScreenCapture(screenRegion);
   }

Capture the region of a component using the Robot class.

   public BufferedImage captureComponentUsingRobot(Component c) throws AWTException {
     Rectangle bounds = c.getBounds();
     Point location = new Point(0, 0);
     SwingUtilities.convertPointToScreen(location, c);
     bounds.setLocation(location);
     return new Robot().createScreenCapture(bounds);
   }

Capture the region of a component using an image buffer.

   public BufferedImage captureComponentUsingImageBuffer(Component c) {
     Dimension preferredSize = c.getPreferredSize();
     BufferedImage img = new BufferedImage(preferredSize.width, preferredSize.height, BufferedImage.TYPE_INT_ARGB);
     c.paint(img.getGraphics());
     return img;
   }

The method above can capture an image of a component even when it is hidden.

capture a screen shot.

     try
     {
       Robot robot = new Robot ();
       // Capture a particular area on the screen
       int x = 100; int y = 100; int width = 200; int height = 200;
       Rectangle area = new Rectangle (x, y, width, height);
       BufferedImage bufferedImage = robot.createScreenCapture (area);

       // Capture the whole screen
       area = new Rectangle (Toolkit.getDefaultToolkit ().getScreenSize ());
       bufferedImage = robot.createScreenCapture (area);
     }
     catch (AWTException e) { }

get a buffered image of a jframe and write it to a png file

   Component c = f.getContentPane();
   BufferedImage i = getScreenShot(c);
   try {
     ImageIO.write(img, "png", new File("screenshot.png"));
   } catch (Exception e) {
     e.printStackTrace();
   }
   public static BufferedImage getScreenShot(Component component) {
     BufferedImage image = new BufferedImage(
       component.getWidth(), 
         component.getHeight(), BufferedImage.TYPE_INT_RGB
     );
     // call the Component's paint method, using
     // the Graphics object of the image.
     component.paint(image.getGraphics());
     return image;
   }

Saving Images ‹↑›

Compressing Jpeg Images ‹↑›

The jpeg format allows the reduction of the file size of the image by reducing the quality of the image. This can be important for emailing images or placing images in webpages.

compress a jpeg image with quality 85%, a tested example

   import javax.imageio.*;
   import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
   import javax.imageio.stream.ImageOutputStream;
   import java.io.File;
   import java.util.Locale;
   import java.awt.image.BufferedImage;
   public class ImageCompress {
     public static void main(String[] args) {
       float quality = 0.85f;
       File inFile = new File("big.jpg");
       File outFile = new File("compress.jpg" );
       try {
         BufferedImage image = ImageIO.read(inFile);
         ImageWriter imgWriter =
           ImageIO.getImageWritersByFormatName("jpg").next();
         ImageOutputStream ioStream = 
           ImageIO.createImageOutputStream(outFile);
         imgWriter.setOutput(ioStream);
         JPEGImageWriteParam jpegParams =
           new JPEGImageWriteParam(Locale.getDefault());
         jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
         jpegParams.setCompressionQuality(quality);
         imgWriter.write(null, new IIOImage(image, null, null), jpegParams);
         ioStream.flush();
         ioStream.close();
         imgWriter.dispose();
         System.out.format(
           "big.jpg size = %d, compress.jpg size = %d",
           inFile.length(), outFile.length());
       } catch (java.io.IOException e) {
         e.printStackTrace();
       }
     }
   }

The class IIOWriteProgressListener allows use to display the progress of the write and reduce quality operation (which will take a few seconds)

compress a jpeg image, quality 85%, with a write progress listener

   import javax.imageio.*;
   import javax.imageio.event.IIOWriteProgressListener;
   import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
   import javax.imageio.stream.ImageOutputStream;
   import java.io.File;
   import java.util.Locale;
   import java.awt.image.BufferedImage;
   public class ImageCompress implements IIOWriteProgressListener {
     public static void main(String[] args) {
       float quality = 0.85f;
       File inFile = new File("big.jpg");
       File outFile = new File("compress.jpg" );
       try {
         BufferedImage image = ImageIO.read(inFile);
         ImageWriter imgWriter =
           ImageIO.getImageWritersByFormatName("jpg").next();
         ImageOutputStream ioStream = 
           ImageIO.createImageOutputStream(outFile);
         imgWriter.setOutput(ioStream);
         JPEGImageWriteParam jpegParams =
           new JPEGImageWriteParam(Locale.getDefault());
         jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
         jpegParams.setCompressionQuality(quality);
         imgWriter.addIIOWriteProgressListener(new ImageCompress());
         imgWriter.write(null, new IIOImage(image, null, null), jpegParams);
         ioStream.flush();
         ioStream.close();
         imgWriter.dispose();
         System.out.format(
           "big.jpg size = %d, compress.jpg size = %d",
           inFile.length(), outFile.length());
       } catch (java.io.IOException e) {
         e.printStackTrace();
       }
     }
     //progress listener methods
     public void imageProgress(ImageWriter w, float percentageDone) {
       System.out.format("Percent written: %f\n", percentageDone);
     }
     public void imageComplete(ImageWriter w) {
       System.out.println("Write complete");
     }
     public void imageStarted(ImageWriter w, int imageIndex) {}
     public void thumbnailStarted(ImageWriter w, int index, int thumbi) {}
     public void thumbnailProgress(ImageWriter w, float percentDone) {}
     public void thumbnailComplete(ImageWriter w) {}
     public void writeAborted(ImageWriter w) {}
  }

reduce the file size of a jpeg image, to an output stream

   private Image getJpegCompressedImage(BufferedImage image) throws IOException {
     float qualityFloat = 0.85f;
     ByteArrayOutputStream outStream = new ByteArrayOutputStream();
     ImageWriter imgWriter = 
       ImageIO.getImageWritersByFormatName("jpg").next();
     ImageOutputStream ioStream = 
       ImageIO.createImageOutputStream(outStream);
     imgWriter.setOutput(ioStream);
     JPEGImageWriteParam jpegParams = 
       new JPEGImageWriteParam(Locale.getDefault());
     jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
     jpegParams.setCompressionQuality(qualityFloat);
     imgWriter.write(null, new IIOImage(image, null, null), jpegParams );
     ioStream.flush();
     ioStream.close();
     imgWriter.dispose();
     jpgSize = outStream.toByteArray().length;
     BufferedImage compressedImage = ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
     return compressedImage;
   }

Converting Image Formats ‹↑›

convert to a png compressed image without saving

    BufferedImage image = ...;
    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    ImageIO.write(image, "png", outStream);
    pngSize = outStream.toByteArray().length;
    BufferedImage compressedImage =
        ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));

Image Data ‹↑›

The data for a BufferedImage is stored in a WritableRaster combined with a ColorModel.

write all image data to a new RGB image, pixel by pixel

   BufferedImage image = ...;
   BufferedImage newImage = 
     new BufferedImage(
       image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
   for (int i=0; i<width; i++) {
     for (int j = 0; j < height; j++)
       newImage.setRGB(i, j, image.getRGB(i, j));
   }

The y loop (horizontal) should be the outer loop because that is how the image data is stored and therefore the code will execute faster.

loop through all the pixels in an image.

   
   for (int y = 0; y < image.getHeight(); y++) {
     for (int x = 0; x < image.getWidth(); x++) {
       int  clr   = image.getRGB(x, y);
       int  red   = (clr & 0x00ff0000) >> 16;
       int  green = (clr & 0x0000ff00) >> 8;
       int  blue  =  clr & 0x000000ff;
       image.setRGB(x, y, clr);
     }
   }

Bufferedimagesops And Image Manipulation ‹↑›

Java provides the interface BufferedImageOp and a number of implementations of this interface to carry out various 'filtering' operations on BufferedImages. These operation include blurring, converting to greyscale (black and white), changing colours et.

http://docstore.mik.ua/orelly/java-ent/jfc/ch04_10.htm A introduction to image operations.

hints for drawImage() RenderingHints.KEY_INTERPOLATION
www: ConvolveOp
- can be used for blurring an image
www: ColorConvertOp
- convert to greyscale
www: and
more ...

Image filtering class
www: AffineTransformOp
Performs an arbitrary geometric transformation--specified by an AffineTransform--on an image. The transform can include scaling, rotation, translation, and shearing in any combination. This operator interpolates pixel values when needed, using either a fast, nearest-neighbor algorithm or a slower, higher-quality bilinear interpolation algorithm. This class cannot process images in place.
www: ColorConvertOp
Converts an image to a new java.awt.color.ColorSpace. It can process an image in place.
www: ConvolveOp
Performs a powerful and flexible type of image processing called convolution, which is used for blurring or sharpening images and performing edge detection, among other things. ConvolveOp uses a java.awt.image.Kernel object to hold the matrix of numbers that specify exactly what convolution operation is performed. Convolution operations cannot be performed in place.
www: LookupOp
Processes the color channels of an image using a lookup table, which is an array that maps color values in the source image to color values in the new image. The use of lookup tables makes LookupOp a very flexible image-processing class. For example, you can use it to brighten or darken an image, to invert the colors of an image, or to reduce the number of distinct color levels in an image. LookupOp can use either a single lookup table to operate on all color channels in an image or a separate lookup table for each channel. LookupOp can be used to process images in place. You typically use LookupOp in conjunction with java.awt.image.ByteLookupTable.
www: RescaleOp
Like LookupOp, RescaleOp is used to modify the values of the individual color components of an image. Instead of using a lookup table, however, RescaleOp uses a simple linear equation. The color values of the destination are obtained by multiplying the source values by a constant and then adding another constant. You can specify either a single pair of constants for use on all color channels or individual pairs of constants for each of the channels in the image. RescaleOp can process images in place.
a summary of available BufferedImageOps

The requestFocusInWindow() below is necessary to set the focus onto the JPanel (GreyScale).

convert an image to greyscale when the user presses g

   import java.awt.image.*;
   import java.awt.color.*; import java.awt.*; import java.awt.event.*;
   import javax.imageio.ImageIO; import java.io.*;
   import javax.swing.*;
   public class GreyScale extends JPanel implements KeyListener {
     BufferedImage original;
     BufferedImage display;
     BufferedImage grey;
     public GreyScale() {
       try {
         this.original = ImageIO.read(new File("scale.jpg"));
         this.display = this.original;
       }
       catch (IOException e) {
         System.out.println("Image File not found");
       }
       this.addKeyListener(this);
     }
     public void makeGrey() {
       System.out.println("makeGrey");
       ColorConvertOp op = new ColorConvertOp(
         ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
       this.grey = op.filter(this.original, null);
       this.display = this.grey;
       this.repaint();
     }
     public void restore() {
       System.out.println("restore");
       this.display = this.original;
       this.repaint();
     }
     public void keyTyped(KeyEvent e) {
       switch (e.getKeyChar()) {
         case 'g': this.makeGrey(); break;
         case 'r': this.restore(); break;
         case 'x': System.exit(0); break;
         default: break;
       }
     }
     public void keyPressed(KeyEvent e) {}
     public void keyReleased(KeyEvent e) {}
     public Dimension getPreferredSize() {
       return new Dimension(500, 500);
     }
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D gg = (Graphics2D) g;
       gg.drawImage(this.display, 0, 0, null);
       this.requestFocusInWindow();
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame frame = new JFrame("Greyscale test");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           frame.setContentPane(new GreyScale()); frame.pack();
           //frame.setSize(500,300);
           frame.setVisible(true);
         }
       });
     } 
   }

Lookupop ‹↑›

make an image brighter with a LookupOp but this seems to change colors

     public void makeBrighter() {
       byte[] data = new byte[256];
       for(int i = 0; i < 256; i++) 
         data[i] = (byte)(Math.sqrt((float)i/255.0) * 255);
       ByteLookupTable table = new ByteLookupTable(0, data);
       LookupOp op = new LookupOp(table, null);
       this.brighter = op.filter(this.original, null);
     }

Rescaleop ‹↑›

The RescaleOp can scale the colours of an image, lighter darker negative etc.

The code below was actually crashing the java virtual machine. The problem was with TYPE_BYTE and TYPE_USHORT data type images. A work around is to copy the image to a BGR type before the rescaleop.

http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=c863c92fdd734ffffffffc12241b21250538?bug_id=4886506 The sun bug report for jre crashes on rescaleop

make a darker image

 RescaleOp op = new RescaleOp(0.5f, 0.5f, null);

make a negative type image

 RescaleOp op = new RescaleOp(-1.0f, 255f, null);

make a brighter image

 RescaleOp op = new RescaleOp(1.1f, 0.0f, null);

make an image like a negative or brighter

   import java.awt.image.*;
   import java.awt.color.*; import java.awt.*; import java.awt.event.*;
   import javax.imageio.ImageIO; import java.io.*;
   import javax.swing.*;
   public class NegativeImage extends JPanel implements KeyListener {
     BufferedImage original;
     BufferedImage display;
     BufferedImage negative;
     BufferedImage brighter;
     public NegativeImage() {
       try {
         this.original = ImageIO.read(new File("test1.jpg"));
         this.display = this.original;
       }
       catch (IOException e) {
         System.out.println("Image File not found");
       }
       this.addKeyListener(this);
     }
     public void rescale() {
       System.out.println("rescale");
       // copy the image to compatible to stop jre crashes
       BufferedImage adjusted=new BufferedImage(
         this.original.getWidth(),this.original.getHeight(),
         BufferedImage.TYPE_INT_BGR);
       Graphics2D ug = adjusted.createGraphics();
       ug.drawImage(this.original,0,0,null);
       ug.dispose();
       //RescaleOp op = new RescaleOp(-1.0f, 255f, null);
       RescaleOp op = new RescaleOp(1.1f, 0.0f, null);
       this.negative = op.filter(adjusted, null);
       this.display = this.negative;
       this.repaint();
     }
     // producing weird results
     public void makeBrighter() {
       byte[] data = new byte[256];
       for(int i = 0; i < 256; i++) 
         data[i] = (byte)(Math.sqrt((float)i/255.0) * 255);
       ByteLookupTable table = new ByteLookupTable(0, data);
       LookupOp op = new LookupOp(table, null);
       this.brighter = op.filter(this.original, null);
       this.display = this.brighter;
       this.repaint();
     }
     public void restore() {
       System.out.println("restore");
       this.display = this.original;
       this.repaint();
     }
     public void keyTyped(KeyEvent e) {
       switch (e.getKeyChar()) {
         case 'n': this.rescale(); break;
         case 'b': this.makeBrighter(); break;
         case 'r': this.restore(); break;
         case 'x': System.exit(0); break;
         default: break;
       }
     }
     public void keyPressed(KeyEvent e) {}
     public void keyReleased(KeyEvent e) {}
     public Dimension getPreferredSize() {
       return new Dimension(600, 600);
     }
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D gg = (Graphics2D) g;
       gg.drawImage(this.display, 0, 0, null);
       this.requestFocusInWindow();
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame frame = new JFrame("Rescale an image");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           frame.setContentPane(new NegativeImage()); frame.pack();
           frame.setVisible(true);
         }
       });
     } 
   }

Convolveop And Blurring Images ‹↑›

http://www.jhlabs.com/ip/blurring.html a good article about blurring in java.

When blurring an image each pixel is computed from itself and its surrounding pixels. This process is known as 'convolution' (hence the name of the ConvolveOp class). The matrix below represents the contribution of a pixel and the eight surrounding pixels to the blurred pixel.

increasing luminosity with convolution and a 1x1 matrix

    float[] matrix = { 1.1f };
    BufferedImageOp op = new ConvolveOp(new Kernel(1, 1, matrix));
    newImage = op.filter(original, newImage);

a basic blur example

   float[] matrix = {
     0.111f, 0.111f, 0.111f,
     0.111f, 0.111f, 0.111f,
     0.111f, 0.111f, 0.111f,
   };
   BufferedImageOp op = new ConvolveOp( new Kernel(3, 3, matrix) );
   blurredImage = op.filter(sourceImage, destImage);

a workaround for ImageOpException

   BufferedImage tmp = 
     new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
   for (int i=0; i<width; i++) {
     for (int j = 0; j < height; j++)
       tmp.setRGB(i, j, img.getRGB(i, j));
   }
   destImage = op.filter(tmp, null);

The below was throwing an exception ImagingOpException: The solution was to create a new simple rgb image but writing each pixel of the original image to a temporary one, and blurring the temporary image.

blur an image or make brighter, the brighter is throwing an Exception

   import java.awt.image.*;
   import java.awt.color.*; import java.awt.*; import java.awt.event.*;
   import javax.imageio.ImageIO; import java.io.*;
   import javax.swing.*;
   public class BlurImage extends JPanel implements KeyListener {
     BufferedImage original;
     BufferedImage display;
     BufferedImage blurred;
     public BlurImage() {
       try {
         this.original = ImageIO.read(new File("scale.jpg"));
         this.display = this.original;
       }
       catch (IOException e) {
         System.out.println("Image File not found");
       }
       this.addKeyListener(this);
     }
     public void blur() {
       System.out.println("blur");

       float[] matrix = {
         0.111f, 0.111f, 0.111f,
         0.111f, 0.111f, 0.111f,
         0.111f, 0.111f, 0.111f,
       };
       BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, matrix));
       //this.blurred = op.createCompatibleDestImage(
        // this.original, this.original.getColorModel());
   
       // the following is a workaround for the ImagingOpException
       BufferedImage tmp = new BufferedImage(
           this.original.getWidth(), this.original.getHeight(),
           BufferedImage.TYPE_INT_RGB);
       for (int i=0; i<tmp.getWidth(); i++) {
         for (int j = 0; j < tmp.getHeight(); j++)
           tmp.setRGB(i, j, this.original.getRGB(i, j));
       }
       this.blurred = op.filter(tmp, null);
       //this.blurred = op.filter(this.original, this.blurred);
       this.display = this.blurred;
       this.repaint();
     }
     public void makeBrighter() {
       float[] matrix = { 1.1f };
       BufferedImageOp op = new ConvolveOp(new Kernel(1, 1, matrix));
       this.blurred = op.filter(this.original, this.blurred);
       this.display = this.blurred;
       this.repaint();
     }
     public void restore() {
       System.out.println("restore");
       this.display = this.original;
       this.repaint();
     }
     public void keyTyped(KeyEvent e) {
       switch (e.getKeyChar()) {
         case 'g': this.blur(); break;
         case 'b': this.makeBrighter(); break;
         case 'r': this.restore(); break;
         case 'x': System.exit(0); break;
         default: break;
       }
     }
     public void keyPressed(KeyEvent e) {}
     public void keyReleased(KeyEvent e) {}
     public Dimension getPreferredSize() {
       return new Dimension(600, 600);
     }
     public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D gg = (Graphics2D) g;
       gg.drawImage(this.display, 0, 0, null);
       this.requestFocusInWindow();
     }
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           JFrame frame = new JFrame("Blur image with a ConvolveOp");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           frame.setContentPane(new BlurImage()); frame.pack();
           //frame.setSize(500,300);
           frame.setVisible(true);
         }
       });
     } 
   }

Animation ‹↑›

animation advice to reduce flicker

In a JPanel, override paintComponent(Graphics) rather than paint(Graphics) Instead of calling Thread.sleep(n) implement a Swing Timer for repeating tasks or a SwingWorker for long running tasks. See "Concurrency in Swing" for more details.

According to some, Swing is double buffered by default, apparently removing the need to write to an offscreen image buffer- need to investigate this.

www: http://www.javarichclient.com/animated-transitions-timingframeworks/
how to use the timingframworks library (created by Chet Haase) to 'transition' swing elements using animation. For example animate the closing of a window, etc
an animation to create 'marching ants' rectangle
   import java.awt.*;
   import java.awt.event.*;
   import java.awt.geom.Rectangle2D;
   import java.awt.image.BufferedImage;
   import java.io.File;
   import java.io.IOException;
   import javax.imageio.ImageIO;
   import javax.swing.*;
   public class AnimatedStroke {
     public static void main(String[] args) {
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           BasicStroke dashedStroke;
           final int width = 100;
           final int height = 30;
           final BufferedImage image = new BufferedImage(
             width,height,BufferedImage.TYPE_INT_ARGB);
           final JLabel label = new JLabel(new ImageIcon(image));
           int pad = 5;
           final Shape rectangle = new Rectangle2D.Double(
             (double)pad,(double)pad,
             (double)(width-2*pad),
             (double)(height-2*pad));
   
           ActionListener listener = new ActionListener() {
             float dashPhase = 0f;
             float dash[] = {5.0f,5.0f};
             @Override
             public void actionPerformed(ActionEvent ae) {
               dashPhase += 9.0f;
               BasicStroke dashedStroke = new BasicStroke(
                 1.5f,
                 BasicStroke.CAP_ROUND,
                 BasicStroke.JOIN_MITER,
                 1.5f, //miter limit
                 dash, dashPhase
               );
               Graphics2D g = image.createGraphics();
               g.setColor(Color.WHITE);
               g.fillRect(0,0,width,height);
               g.setColor(Color.BLACK);
               g.setStroke(dashedStroke);
               g.draw(rectangle);
               g.dispose();
               label.repaint();
   
               /*
               if (dashPhase<100f) {
               try { ImageIO.write(image, "PNG",
                 new File("img" + dashPhase + ".png"));
               } catch(IOException ioe) {}
               }*/
             }
           };
           Timer timer = new Timer(40, listener);
           timer.start();
           JOptionPane.showMessageDialog(null, label);
         }
       });
     }
   }

The following animation doesnt flicker much on my pc.

a waveform animation

   import java.awt.*;
   import javax.swing.*;
   public class FlickerPanel extends JPanel implements Runnable {
     private float[] pixelMap = new float[0];
     // Cached graphics objects to reduce flicker 
     private Image screenBuffer;
     private Graphics bufferGraphics;
   
     public FlickerPanel () {
       Thread t = new Thread(this);
       t.start();
     }
     private float addNoise () {
       return (float)((Math.random()*2)-1);
     }
     private synchronized void advance () {
       if (pixelMap == null || pixelMap.length == 0) return;
       float[] newPixelMap = new float[pixelMap.length];
       for (int i=1; i<pixelMap.length; i++) {
         newPixelMap[i-1] = pixelMap[i];
       }
       newPixelMap[newPixelMap.length-1] = addNoise();
       pixelMap = newPixelMap;
     }
     public void run() {
       while (true) {
         advance();
         repaint();
         try {
           Thread.sleep(25);
         } catch (InterruptedException e) {}
       }
     }
     private int getY (float height) {
       double proportion = (1-height)/2;
       return (int)(getHeight()*proportion);
     }
     public void paint (Graphics g) {
       if (screenBuffer == null || screenBuffer.getWidth(this) != getWidth() || screenBuffer.getHeight(this) != getHeight()) {
         screenBuffer = createImage(getWidth(), getHeight());
         bufferGraphics = screenBuffer.getGraphics();
       }
   
       if (pixelMap == null || getWidth() != pixelMap.length) {
         pixelMap = new float[getWidth()];
       }
       bufferGraphics.setColor(Color.BLACK);
       bufferGraphics.fillRect(0, 0, getWidth(), getHeight());
       bufferGraphics.setColor(Color.GREEN);
       int lastX = 0;
       int lastY = getHeight()/2;
       for (int x=0; x<pixelMap.length; x++) {
         int y = getY(pixelMap[x]);
         bufferGraphics.drawLine(lastX, lastY, x, y);
         lastX = x;
         lastY = y;
       }
       g.drawImage(screenBuffer, 0, 0, this);
     }
     public void update(Graphics g) {
       paint(g);
     }
     public static void main (String [] args) {
       JFrame frame = new JFrame("Flicker test");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setContentPane(new FlickerPanel());
       frame.setSize(500,300);
       frame.setVisible(true);
     }
   }

Charts ‹↑›

One option is to use JFreeChart

a simple example with jfreechart

    HistogramDataset dataset = new HistogramDataset();
    dataset.addSeries("series label",arrayOfValues,noOfBins);
    //Create a chart object

    JFreeChart chart = ChartFactory.
    createHistogram("plotTitle", "xaxis label", "yaxis label", 
                    dataset, PlotOrientation.VERTICAL, false, false, false);
    //If swing application use ChartPanel to render chart

    ChartPanel chartPanel = new ChartPanel(chart)
    chartPanel.setPreferredSize(new java.awt.Dimension JavaDoc(500, 270));
    chartPanel.setMouseZoomable(true, false);
    If need to write chart to a file/stream use ChartUtilities.saveChartAsPNG(...)

    ChartUtilities.saveChartAsPNG(new File("histogram.PNG"), chart, width, height);

Networks ‹↑›

This is a big topic and I havent even started yet

connect through a proxy host to the net

 java -Dhttp.proxyHost=proxyhost [-Dhttp.proxyPort=portNumber] URLReader

=

list network card interfaces java1.6+

import java.io.*; import java.net.*; import java.util.*; public class ListNetInterfaces { public static void main(String args[]) throws SocketException { Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); for (NetworkInterface ni : Collections.list(nets)) { System.out.println( "Display name:" + ni.getDisplayName()); System.out.println("Hardware address:" + Arrays.toString(ni.getHardwareAddress())); } } } ,,,

get the computer name and ip address

   public class NetInfo {
     public static void main(String[] args) {
       try {
         java.net.InetAddress i = java.net.InetAddress.getLocalHost();
         System.out.println(i);                  // name and IP address
         System.out.println(i.getHostName());    // name
         System.out.println(i.getHostAddress()); // IP address only
       }
       catch (Exception e) { e.printStackTrace(); }
     }
   }

list interfaces an associated ip addresses

   import java.net.*;
   import java.util.*;
   import java.io.*;
   import java.nio.*;
   public class IPAdress {
     public void  getInterfaces () {
       try {
         Enumeration e = NetworkInterface.getNetworkInterfaces();
         while (e.hasMoreElements()) {
           NetworkInterface ni = (NetworkInterface) e.nextElement();
           System.out.println("Net interface: "+ni.getName());
           Enumeration e2 = ni.getInetAddresses();
           while (e2.hasMoreElements()) {
             InetAddress ip = (InetAddress) e2.nextElement();
             System.out.println("IP address: "+ ip.toString());
           }
         }
       }
       catch (Exception e) { e.printStackTrace(); }
     }
   
     public static void main(String[] args) {
       IPAdress ip = new IPAdress();
       ip.getInterfaces();
     }
   }

Sockets ‹↑›

A socket is a tcp connection occuring on a particular port between 2 computers. Java makes these kinds of connections quite simple to set up. The entire net is based on them, so it worth knowing how to do it.

Server Sockets ‹↑›

Server sockets listen on a port for an incoming connection or request.

Socket aSock = myServerSocket.accept();

determine where a connection to a ServerSocket is coming from

    System.out.println
    ("Connection from : "
     + aSock.getInetAddress().getHostAddress()
     + ':' + aSock.getPort());

In the examples below, we can use streams directly rather than creating arrays of bytes. Examples from rgagnon. need to be adapted.

create a ServerSocket to send the file 'source.pdf' to a client

   import java.net.*;
   import java.io.*;
   public class FileServer {
     public static void main (String [] args ) throws IOException {
       // create socket
       ServerSocket servsock = new ServerSocket(13267);
       while (true) {
         System.out.println("Waiting...");
         Socket sock = servsock.accept();
         System.out.println("Accepted connection : " + sock);
   
         // send a file
         File file = new File ("source.pdf");
         byte[] byteArray  = new byte[(int)file.length()];
         FileInputStream fis = new FileInputStream(file);
         BufferedInputStream bis = new BufferedInputStream(fis);
         bis.read(byteArray, 0, byteArray.length);
         OutputStream os = sock.getOutputStream();
         System.out.println("Sending...");
         os.write(byteArray, 0, byteArray.length);
         os.flush();
         sock.close();
       }
     }
   }

the client application which receives a file from the server

   import java.net.*;
   import java.io.*;
   public class FileClient {
     public static void main (String[] args ) throws IOException {
       int filesize=6022386; // filesize temporary hardcoded
       long start = System.currentTimeMillis();
       int bytesRead;
       int current = 0;
       // localhost for testing
       Socket sock = new Socket("127.0.0.1", 13267);
       System.out.println("Connecting...");
       // receive file
       byte[] mybytearray  = new byte[filesize];
       InputStream is = sock.getInputStream();
       FileOutputStream fos = new FileOutputStream("source-copy.pdf");
       BufferedOutputStream bos = new BufferedOutputStream(fos);
       bytesRead = is.read(mybytearray, 0, mybytearray.length);
       current = bytesRead;
       do {
         bytesRead =
           is.read(mybytearray, current, (mybytearray.length-current));
         if (bytesRead >= 0) current += bytesRead;
       } while (bytesRead > -1);
   
       bos.write(mybytearray, 0 , current);
       bos.flush();
       long end = System.currentTimeMillis();
       System.out.println("Time taken:" + end - start);
       bos.close();
       sock.close();
     }
   }

Urls ‹↑›

Urls are the unique names given to resources on the local computer or the internet. There is some subtle distinction between Uri and Url but lets not worry. Java has the java.net.URL class.

a url which refers to a local file in same folder as the application

 URL url = new URL("file:MethodPanel.class");

a url for a local file using an absolute pathname

 URL url = new URL("file:/home/arjuna/MethodPanel.class");

a jar url for a local jar archive on a ms windows computer

 URL url = new URL("jar:file:/c:/almanac/my.jar!/");

a jar url referring to a remote jar archive

 URL url = new URL("jar:http://bumble.sf.net/books/java/m.jar!/");

check if the url 'webDoc' points to the same file as 'url'

 webDoc.sameFile(url)

check if a url supplied as an argument has a valid format

     import java.net.*;
     public class ValidUrl {
       public static void main(String[] args) {
         if (args.length < 1) {
           System.out.println("usage: java ValidUrl url");
           System.exit(-1);
         }
         URL url = null;
         try {
           url = new URL(args[0]);
         } catch (MalformedURLException e) {
           System.out.println("Invalid URL: " + args[0]);
         }
       }
     }

check if a url host is valid and the file exists

    import java.net.*;
    import java.io.*;
    public class ValidUrl {
      public static void main(String[] args) throws Exception  {
        URL url = new URL("http://bumble.sf.net/notes/index.txt");
        try
        {
          url.openStream();
          System.out.println("ok");
        }
        catch (UnknownHostException e)
          { System.out.println("unknown host: " + e); }
        catch (FileNotFoundException e)
          { System.out.println("file not found: " + e); }
      }
    }

Actually the UnkownHostException doesnt seem to get triggered, only the FileNotFoundException

Parts Of The Url ‹↑›

A url can be divided into parts such as hostname, filename, path etc. All this may seem rather trivial and boring, but since URLs are such as important part of the web, and therefore the world, its probably worth knowing.

getFile(), and getPath(), seem to return the same thing- that is all of the url after the protocol and host section.

display some of the parts of a url

   import java.net.*;
   public class UrlParts {
     public static void main(String[] args) {
       URL url;
       try {
         url = new URL(
           "http://www.eg.com/java/net/URI.html");
           //"file:/usr/lib/jvm/java-6-sun/docs/api/java/net/URI.html");
         System.out.format(
           "url.getFile(): %s \n" +
           "url.getPath(): %s \n" +
           "url.getHost(): %s \n" +
           "url.getPort(): %s \n" +
           "url.getProtocol(): %s \n" +
           "url.getDefaultPort(): %s \n" +
           "url.toString(): %s \n" +
           "url.toExternalForm(): %s \n", 
            url.getFile(), url.getPath(), url.getHost(), url.getPort(),
            url.getProtocol(), url.getDefaultPort(), url.toString(), 
            url.toExternalForm());
       } catch (MalformedURLException e) {
         System.out.println("Invalid URL: " + args[0]);
       }
     }
   }

References For Urls ‹↑›

The reference of a URL is the part after the hash '#' and indicates a section within the current (html) page.

check if there is no reference for the url

useful classes
NetworkInterface - very useful for getting card information

check if 2 urls point to the same file (with possibly different refs)

 if (urlA.sameFile(urlB)) {...}

Converting Urls To Other Formats Or Objects ‹↑›

convert a URL to a File object

 File f = new File(url.toURI());

experiment with converting to uri and files

   import java.net.*;
   public class ConvertUrl {
     public static void main(String[] args) {
       URL url;
       try {
         url = new URL(
           "file:/usr/lib/jvm/java-6-sun/docs/api/java/net/URI.html");
         System.out.format(
           "url.toString(): %s \n" +
           "url.toExternalForm(): %s \n", 
            url.toString(), url.toExternalForm());
       } catch (MalformedURLException e) {
         System.out.println("Invalid URL: " + args[0]);
       }
     }
   }

Javamail ‹↑›

Sending and receiving email can be done with the Javamail package javax.mail using an account on an smtp server, imap server or pop server.

Installing Javamail ‹↑›

The javamail api does not come, by default, with the Java SE developer kit (only with the enterprise edition).

If you are using java 1.5 or less then you have to install the java beans framework or something like that. But really, just upgrade.

download the zip file from oracle

 javamail1_4_5.zip

unzip the file

 unzip javamail*

find out where your java extensions folder is with something like ---- public class ExtensionPath { public static void main(String[] args) { System.out.println(System.getProperty("java.ext.dirs")); } } ,,,

copy the ./javamail*/mail.jar to an extensions folder

 sudo cp javamail-1.4.5/mail.jar /usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/ext

Or you could copy it to a user extensions folder which doesnt require administrator priviledges.

Sending Email ‹↑›

http://java.sun.com/developer/onlineTraining/JavaMail/contents.html A javamail howto

send email using a tls connection

   import java.util.Properties;
   import javax.mail.Message;
   import javax.mail.MessagingException;
   import javax.mail.PasswordAuthentication;
   import javax.mail.Session;
   import javax.mail.Transport;
   import javax.mail.internet.InternetAddress;
   import javax.mail.internet.MimeMessage;
   public class SendMailTLS {
     public static void main(String[] args) {
       final String username = "username@gmail.com";
       final String password = "password";
       Properties props = new Properties();
       props.put("mail.smtp.auth", "true");
       props.put("mail.smtp.starttls.enable", "true");
       props.put("mail.smtp.host", "smtp.gmail.com");
       props.put("mail.smtp.port", "587");
   
       Session session = Session.getInstance(props,
       new javax.mail.Authenticator() {
         protected PasswordAuthentication getPasswordAuthentication() {
           return new PasswordAuthentication(username, password);
         }
       });
   
       try {
         Message message = new MimeMessage(session);
         message.setFrom(new InternetAddress("from-email@gmail.com"));
         message.setRecipients(Message.RecipientType.TO,
                               InternetAddress.parse("to-email@gmail.com"));
         message.setSubject("Testing Subject");
         message.setText("Dear Mail Crawler,"
                         + "\n\n No spam to my email, please!");
         Transport.send(message);
         System.out.println("Done");
       } catch (MessagingException e) {
         throw new RuntimeException(e);
       }
     }
   }

It worked!!

settings for connecting to a gmail account to send mail via smtp

    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class",
              "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");

send an email via smtp and an ssl connection

   import java.util.Properties;
   import javax.mail.*;
   import java.io.*;
   import javax.mail.internet.InternetAddress;
   import javax.mail.internet.MimeMessage;
   
   public class SendMailSSL {
     public static void main(String[] args) {
       Properties props = new Properties();
   
       // fastmail settings
       props.put("mail.smtp.host", "mail.messagingengine.com");
       props.put("mail.smtp.socketFactory.port", "465");
       props.put("mail.smtp.socketFactory.class",
                 "javax.net.ssl.SSLSocketFactory");
       props.put("mail.smtp.auth", "true");
       props.put("mail.smtp.port", "465");
   
       Session session = Session.getDefaultInstance(props,
       new javax.mail.Authenticator() {
         protected PasswordAuthentication getPasswordAuthentication() {
           String password = JOptionPane.showInputDialog(
               "Enter mail password'");
           return new PasswordAuthentication(
                    "mjbishop@fastmail.fm", password);
         }
       });
   
       try {
         Message message = new MimeMessage(session);
         message.setFrom(new InternetAddress("me@fastmail.fm"));
         message.setRecipients(Message.RecipientType.TO,
            InternetAddress.parse("shop@fastmail.fm"));
         message.setSubject("Testing Javamail");
         message.setText("Dear Javamail,\n\n Send this now!");
         Transport.send(message);
         System.out.println("Sent");
       } catch (MessagingException e) {
         throw new RuntimeException(e);
       }
     }
   }

reply to a message

   MimeMessage reply = (MimeMessage)message.reply(false);
   reply.setFrom(new InternetAddress("president@whitehouse.gov"));
   reply.setText("Thanks");
   Transport.send(reply);

Email App ‹↑›

The example below is supposed to be a minimalist form for sending email with the javamail classes and smtp. But it requires an account on an smtp server. Currently using a fastmail account.

Ideas: an image search to insert an image in the mail. Clear fields function. Insert symbol glyphs in the message text (but using what font?). An action to make the font bigger and smaller.

a simple interface to send an email

   import java.util.Properties;
   import javax.mail.*;
   import java.io.*;
   import java.net.URL; import java.net.MalformedURLException;
   import javax.mail.internet.*;
   import javax.swing.*;
   import javax.swing.border.*;
   import javax.swing.plaf.*;
   import java.awt.*;
   import java.awt.event.*;
   import java.util.*;
   public class MailForm extends JPanel implements ActionListener {
     JTextField fromField; JComboBox toField; 
     JTextField subjectField; JButton sendButton;
     JTextArea mailArea;
     JPanel headPanel;
     public MailForm() {
        super(new BorderLayout(10, 10));
        Font f = new Font("Georgia", Font.ITALIC, 20);
        Font g = new Font("FreeSerif", Font.PLAIN, 30);
        UIManager.put("TextField.font", new FontUIResource(f));
        UIManager.put("ComboBox.font", new FontUIResource(f));
        UIManager.put("TextArea.font", new FontUIResource(g));
        UIManager.put("Label.font", new FontUIResource(g));
        UIManager.put("Button.font", new FontUIResource(g));
        this.fromField = new JTextField("mjbishop <at> fastmail.fm"); 
        this.toField = new JComboBox(this.getAddresses()); 
        this.toField.setEditable(true);
        this.subjectField = new JTextField(); 
        this.sendButton = new JButton("send \u2709");
        this.sendButton.addActionListener(this);
        this.headPanel = new JPanel(new GridLayout(0,2,10,10));

        headPanel.add(new JLabel("From \u269c", JLabel.RIGHT)); 
        headPanel.add(fromField); 
        headPanel.add(new JLabel("To \u269c", JLabel.RIGHT)); 
        headPanel.add(toField);
        headPanel.add(new JLabel("Subject \u269c", JLabel.RIGHT)); 
        headPanel.add(subjectField);
        headPanel.add(new JLabel());
        headPanel.add(sendButton);
        headPanel.setBorder(BorderFactory.createEmptyBorder(20,0,20,160));
        this.mailArea = new JTextArea(20, 60);
        this.mailArea.setBorder(new EtchedBorder()); 
        this.add(headPanel, BorderLayout.NORTH);
        this.add(mailArea, BorderLayout.CENTER);
     }
     public void actionPerformed(ActionEvent e) { this.send(); }

     /** get email address from a text file 'address.txt' */
     public String[] getAddresses() {
       java.util.List<String> emails = new ArrayList<String>();
       try {
         String abook = String.format(
           "file:%s/sf/htdocs/books/java/address.txt", 
           System.getProperty("user.home"));
         System.out.println(abook); 
         //URL url = new URL("file:address.txt");
         URL url = new URL(abook);
         BufferedReader in = new BufferedReader(
           new InputStreamReader(url.openStream()));
         /*
         InputStream is = 
           this.getClass().getResourceAsStream("../address.txt");
         BufferedReader in = new BufferedReader(new InputStreamReader(is));
         */
         String line;
         while ((line = in.readLine()) != null) {
           if (line.matches(".*@.*")) {
             emails.add(line.trim());
           }
         }
         in.close();
       }
       catch (MalformedURLException e) { e.printStackTrace(); }
       catch (IOException e) { e.printStackTrace(); }
       return emails.toArray(new String[emails.size()]);
     }

     /** send an email */
     public void send() {
       Properties props = new Properties();
       // fastmail settings
       props.put("mail.smtp.host", "mail.messagingengine.com");
       props.put("mail.smtp.socketFactory.port", "465");
       props.put("mail.smtp.socketFactory.class",
                 "javax.net.ssl.SSLSocketFactory");
       props.put("mail.smtp.auth", "true");
       props.put("mail.smtp.port", "465");

       String subject = this.subjectField.getText();
       String messageText = this.mailArea.getText();
       String toAddress = (String) toField.getSelectedItem();
       final String fromAddress = 
         fromField.getText().replace(" <at> ", "@");
       System.out.format(
         "subject:%s \ntoAddress:%s \nfromAddress:%s \nmessageText:%s\n",
         subject, toAddress, fromAddress, messageText);

       if (subject.equals("") || messageText.equals("")) {
         JOptionPane.showMessageDialog(null,
           "write a subject and a message");
         return;
       }

       Session session = Session.getDefaultInstance(props,
        new javax.mail.Authenticator() {
          protected PasswordAuthentication getPasswordAuthentication() {
            String password = JOptionPane.showInputDialog(
                "Enter mail password'");
            return new javax.mail.PasswordAuthentication(
              fromAddress, password);
          }
        });
    
       try {
         Message message = new MimeMessage(session);
         //message.setFrom(new InternetAddress("me@fastmail.fm"));
         message.setFrom(new InternetAddress(fromAddress));
         message.setRecipients(Message.RecipientType.TO,
            InternetAddress.parse(toAddress));
         message.setSubject(subject);
         message.setText(messageText);
         Transport.send(message);
         System.out.println("Sent");
       }
       catch (AuthenticationFailedException e) {
         JOptionPane.showMessageDialog(this, 
          "Incorrect name or password? \n\n" + e);
       }
       catch (MessagingException e) {
         if (e.getMessage().startsWith("Unknown SMTP host:")) {
           JOptionPane.showMessageDialog(this, 
             "No net connection? or bad smtp host \n\n" + e);
         }
         e.printStackTrace();
       }
     }
     public static void main(String[] args) {
       JFrame f = new JFrame("Simple Mail Form");
       f.add(new MailForm()); f.pack();
       f.setExtendedState(JFrame.MAXIMIZED_BOTH);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setVisible(true);
     }
   }

Sending Email Without Javamail ‹↑›

Another way to send email via smtp is to 'speak' the smtp protocol directly using a socket connection on the appropriate port. This has the advantage of avoiding the ~2megabyte javamail dependency

Attachments ‹↑›

To send an attachment you create a message with several mime body parts

send a message with an attachment

   
   // Define message
   Message message = new MimeMessage(session);
   message.setFrom(new InternetAddress(from));
   message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(to));
   message.setSubject("JavaMail Attachment");
   // Create the message part
   BodyPart textPart = new MimeBodyPart();
   textPart.setText("Please see the file attached");
   
   // create the attachment
   BodyPart attachPart = new MimeBodyPart();
   DataSource source = new FileDataSource(filename);
   attachPart.setDataHandler(new DataHandler(source));
   attachPart.setFileName(filename);

   Multipart multipart = new MimeMultipart();
   multipart.addBodyPart(textPart);
   multipart.addBodyPart(attachPart);
   
   // Put parts in message
   message.setContent(multipart);
   
   // Send the message
   Transport.send(message);

Html Email Messages ‹↑›

send an html email message

    String htmlText = "<H1>Hello</H1>" + 
      "<img src=\"http://www.jguru.com/images/logo.gif\">";
      message.setContent(htmlText, "text/html"));

The images above are fetched by the receivers email client (they are not embedded in the message)

display an html email message using a JEditorPane

    String content = (String) message.getContent();
    JEditorPane text = new JEditorPane("text/html", content);
    text.setEditable(false);
    JScrollPane pane = new JScrollPane(text);

send an embedded image in an html email message

   String file = "picnic.jpg";
   Message message = new MimeMessage(session);
   message.setSubject("Embedded Image");
   message.setFrom(new InternetAddress(from));
   message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(to));
   
   // Create your new message part
   BodyPart htmlPart = new MimeBodyPart();
   String htmlText = "<H1>Hello</H1>" +
                     "<img src=\"cid:memememe\">";
   htmlPart.setContent(htmlText, "text/html");
   
   // Create a related multi-part to combine the parts
   MimeMultipart multipart = new MimeMultipart("related");
   multipart.addBodyPart(htmlPart);
   
   // Fetch the image and associate to part
   BodyPart imagePart = new MimeBodyPart();
   DataSource fds = new FileDataSource(file);
   imagePart.setDataHandler(new DataHandler(fds));
   imagePart.setHeader("Content-ID","<memememe>");
   
   multipart.addBodyPart(imagePart);
   message.setContent(multipart);

In the example above the "related" parameter to the MultiPart constructor is necessary to advice the Multipart that the two parts of the message are related. The id string for the image can be anything.

get an attachment from a url

 DataSource fds = new URLDataSource(url);
 imagePart.setDataHandler(new DataHandler(fds));

Connecting To The Mail Box ‹↑›

connect using a javax.mail.URLName

    javax.mail.Session session = javax.mail.Session.getInstance(props);
    javax.mail.Store store = 
      session.getStore(new javax.mail.URLName("imap://mailtest:mailtest@localhost/"));
    store.connec
 if (url.getRef() == null) {...}