Moving the database resultset cursor backward and forward

With JDBC 2.0, you can use scrollable resultsets.

The following example operates on this table and will read the resultset backwards.

mysql> select * from customers;
+--------+-----------------------+-------------------------------+
| custid | name                  | email                         |
+--------+-----------------------+-------------------------------+
|      1 | Joris Van den Bogaert | joris_vandenbogaert@yahoo.com |
|      2 | Alicia Kolesnikova    | alicia@esus.com               |
+--------+-----------------------+-------------------------------+

Main.java:

import java.util.*;
import java.text.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) throws Exception {
      try {
         Class.forName("org.gjt.mm.mysql.Driver").newInstance();
         Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.1/esus", 
                                                       "joris",
                                                       "mypass");
 
         Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                                               ResultSet.CONCUR_READ_ONLY);
 
         ResultSet rs = stmt.executeQuery("SELECT * FROM customers"); 
         rs.afterLast();
         while (rs.previous()) {
            System.out.print(rs.getInt("custid"));
            System.out.print("  " + rs.getString("name"));
            System.out.println("  " + rs.getString("email"));
         }
 
         stmt.close();
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

outputs:

2  Alicia Kolesnikova  alicia@esus.com
1  Joris Van den Bogaert  joris_vandenbogaert@yahoo.com

Capturing an area of the native screen

Use the Robot class, introduced in JDK1.3. The method createScreenCapture creates a BufferedImage containing pixels read from the native screen.

This example reads the top left corner of my Win2000 screen and displays it inside a JFrame.

Main.java:

import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   BufferedImage background;
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      try {
         Robot robot = new Robot();
         background = robot.createScreenCapture(
                         new Rectangle(0, 0, 100, 200)); 
      }
      catch(AWTException e) {
         e.printStackTrace();
      }
   }
 
   public void paint(Graphics g) {      
      if (background != null) {
         g.drawImage(background, 0, 0, getWidth(), getHeight(), this);   
      }
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(100, 200);
      main.setVisible(true);
   }
}

What is an NIO Buffer?

A buffer is used to transfer data between channels.

Internal state

Internally, a buffer is an array of data, where the type is determined by the subclass of java.nio.Buffer that is used: ShortBuffer, IntBuffer, FloatBuffer, DoubleBuffer, LongBuffer, CharBuffer and ByteBuffer.

A buffer maintains three essential properties: capacity, limit and position. Look at the example below for how these properties behave.

  • capacity: is the number of elements the buffer can contain. Once a buffer is allocated, its capacity never changes.

  • limit: the index of the first element that should not be read or written. In other words, elements are usable and can be read up to the index limit-1. For writing, the limit is typically equal to the capacity of the Buffer.
  • position: the index of the next element to be read or written. It is never greater than the limit.

    Creating Buffers

    You can’t directly create Buffers using a constructor.

    Example:

       // allocates memory that can contain 128 bytes
       ByteBuffer byteBuffer = ByteBuffer.allocate(128);
       // prints out 128
       System.out.println(byteBuffer.capacity());
     
       // allocates memory that can contain 128 integers
       IntBuffer intBuffer = IntBuffer.allocate(128);
       // prints out 128
       System.out.println(intBuffer.capacity());
    
  • You can also create a view on an existing ByteBuffer. The two buffers, the original and the view will operate on the same memory, so changing in one buffer will have direct effect in the other one.

    Example:

       // allocates memory that can contain 128 bytes
       ByteBuffer byteBuffer = ByteBuffer.allocate(128);
       // prints out 128
       System.out.println(byteBuffer.capacity());
    
       // Create an intBuffer view on the byteBuffer
       IntBuffer intBuffer = byteBuffer.asIntBuffer();
       // prints out 32, because 128 bytes is 32 integers of 4 bytes each
       System.out.println(intBuffer.capacity());
    
  • To create a Buffer from an existing array, use the wrap method. Changing the original array will change the Buffer.

    WrapExample.java:

    import java.nio.*;
     
    public class WrapExample
    {
       public static void main(String []args) {
          long la[] = { 10, 20, 30, 40 };  
          LongBuffer lb = LongBuffer.wrap(la);
     
          System.out.println("LongBuffer before changing original array");
          printBuffer(lb);
     
          // change the original array
          la[2] = 123456;
     
          System.out.println("LongBuffer after changing original array");
          printBuffer(lb);
       }
       
       public static void printBuffer(LongBuffer lb) {
          for (int i=0; i<lb.limit(); i++) {
             System.out.print(lb.get(i) + " ");
          }
          System.out.println();
       }
    }
    

    Reading/writing from and to a Buffer

    To read and write values from a buffer, you use that buffer’s specific get and put methods, that you can use in relative or absolute mode.

    The following example creates a CharBuffer and writes data to it.

    CharBufferTest.java:

    import java.nio.*;
     
    public class CharBufferTest 
    {
       public static void main(String []args) {
          CharBuffer cb = CharBuffer.allocate(10);
     
          cb.put('a'); 	// use relative put
          cb.put(3, 'b');	// use absolute put
          cb.put('c');	// use relative put
    
          printBuffer(cb);
       }
      
       public static void printBuffer(CharBuffer cb) {
          for (int i=0; i<cb.limit(); i++) {
             System.out.print(cb.get(i) + " ");
          }
          System.out.println();
       }
    } 
    

    outputs:

    a c   b
    

    Buffer Operations

    • flip(): Sets the limit to the current position and the position to zero. This method is typically used after a channel-read (put-operations in Buffer terms) and before a channel-write (get-operations in Buffer terms).

    Example buffer:
     
                          position     limit
                             |           |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
     
    After flip():
     
          position         limit
             |               |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
     
    Typical usage:
     
       inChannel.read(buffer);      // transfers data from the channel to the buffer
       flip();                      // prepares buffer for relative get-operations
       outChannel.write(buffer);    // transfers data from the buffer to the channel
    
  • clear(): Sets the limit to the Buffer’s capacity and the position to zero. This method is typically used after a channel-write (get-operations in Buffer terms) and before a channel-read (put-operations in Buffer terms).
    Example buffer that was just used by an out channel:
     
                          position
                           limit
                             |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
     
    After clear():
     
         position                      limit
             |                           |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
      
    Typical usage:
      
       outChannel.write(buffer);    // transfers data from the buffer to the channel
       clear();                     // prepares buffer for relative put-operations
       inChannel.read(buffer);      // transfers data from the channel to the buffer
    
  • rewind(): Sets the position to zero
  • position(int): with this method, you can assign a new index to the position. If the position is larger than the current limit, an IllegalArgumentException is thrown.
  • limit(int): with this method, you can assign a new index to the limit. The position is set to this limit if it is larger (the position is never larger than the limit).

    Here is an example of the different operations.

    Main.java:

    import java.nio.*;
     
    public class Main
    {
       public static void main(String []args) {
          ByteBuffer bb = ByteBuffer.allocate(10);
     
          printVars("Initial state", bb);
     
          bb.put((byte) 1);
          printVars("bb.put((byte) 1)", bb);
     
          bb.putFloat(3.4f);
          printVars("bb.putFloat(3.4f)", bb);
     
          bb.flip();
          printVars("flip()", bb);
     
          bb.put((byte) 2);
          printVars("bb.put((byte) 2)", bb);
     
          bb.position(5);
          printVars("bb.position(5)", bb);
     
          bb.clear();
          printVars("clear()", bb);
       }
     
       public static void printVars(String state, ByteBuffer bb) {
          System.out.println(state);
          printTag("limit", bb.limit());
          printTag("position", bb.position());
          printLine(bb);
          System.out.print("t| ");
          for (int i=0; i<bb.capacity(); i++) {
             String hexValue = getHexValue(bb, i);
             System.out.print(" " + hexValue.toUpperCase() + " | ");
          }
          System.out.println();
          printLine(bb);
          System.out.println("tCapacity: " + bb.capacity() + 
                             ", remaining: " + bb.remaining());
          System.out.println();
       }
     
       public static void printLine(ByteBuffer bb) {
          System.out.print("t+");
          for (int i=0; i<bb.capacity(); i++) {
             System.out.print("-----+");
          }
          System.out.println();
       }
     
       public static void printTag(String tag, int pos) {
          System.out.print("t   ");
          for (int i=0; i<pos; i++) {
             System.out.print("      ");
          }
          System.out.println(tag);
          System.out.print("t   ");
          for (int i=0; i<pos; i++) {
             System.out.print("      ");
          }
          System.out.println("|");
       }
     
       public static String getHexValue(ByteBuffer bb, int pos) {
          String hexValue = "??";
          if (pos >= bb.limit()) {
             hexValue = "??";
          }
          else {
             hexValue = Integer.toHexString(bb.get(pos));
          }
          if (hexValue.length() > 2) {
             hexValue = hexValue.substring(hexValue.length()-2);
          }
          else if (hexValue.length() == 1) {
             hexValue = "0" + hexValue;
          }
          return hexValue;
       }
    }
    

    outputs:

    Initial state
    	                                                               limit
    	                                                               |
    	   position
    	   |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 10
     
    bb.put((byte) 1)
    	                                                               limit
    	                                                               |
    	         position
    	         |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  01 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 9
     
    bb.putFloat(3.4f)
    	                                                               limit
    	                                                               |
    	                                 position
    	                                 |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  01 |  40 |  59 |  99 |  9A |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 5
     
    flip()
    	                                 limit
    	                                 |
    	   position
    	   |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  01 |  40 |  59 |  99 |  9A |  ?? |  ?? |  ?? |  ?? |  ?? | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 5
     
    bb.put((byte) 2)
    	                                 limit
    	                                 |
    	         position
    	         |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  02 |  40 |  59 |  99 |  9A |  ?? |  ?? |  ?? |  ?? |  ?? | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 4
     
    bb.position(5)
    	                                 limit
    	                                 |
    	                                 position
    	                                 |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  02 |  40 |  59 |  99 |  9A |  ?? |  ?? |  ?? |  ?? |  ?? | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 0
     
    clear()
    	                                                               limit
    	                                                               |
    	   position
    	   |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  02 |  40 |  59 |  99 |  9A |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 10
    

  • Adding a JMenuBar to the two components of a JSplitPane

    Main.java:

    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
     
    public class Main extends JFrame
    {
       JSplitPane splitPane;
      
       public Main() {
          addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent we) {
                System.exit(0);
             }
          });
     
          JPanel firstPanel = createPanel();
          JPanel secondPanel = createPanel();
          splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, firstPanel, secondPanel);
     
          createMainMenuBar();
     
          getContentPane().add(splitPane);
          setSize(300, 300);
          setVisible(true);
     
          splitPane.setDividerLocation(0.5); 
       }
     
       public void createMainMenuBar() {
          JMenuBar mainBar = new JMenuBar();
          JMenu menu = new JMenu(&amp;quot;JSplitPane&amp;quot;);
          JMenuItem item1 = new JMenuItem(&amp;quot;HORIZONTAL_SPLIT&amp;quot;);
          JMenuItem item2 = new JMenuItem(&amp;quot;VERTICAL_SPLIT&amp;quot;);
          menu.add(item1);
          menu.add(item2);
          mainBar.add(menu);
          setJMenuBar(mainBar);
     
          item1.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent ae) {
                splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
             }
          });
     
          item2.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent ae) {
                splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
             }
          });
       }
     
       public JPanel createPanel() {
          JPanel panel = new JPanel();
          panel.setLayout(new BorderLayout());
          JMenuBar menuBar = new JMenuBar();
          for (int i=0; i&amp;lt;3; i++) {
             JMenu menu = new JMenu(&amp;quot;JMenu &amp;quot; + (i+1));
             for (int j=0; j&amp;lt;3; j++) {
                JMenuItem item = new JMenuItem(&amp;quot;JMenuItem &amp;quot; + (j+1));
                menu.add(item);
             }
             menuBar.add(menu);
          }
          panel.add(BorderLayout.NORTH, menuBar);
     
          return panel;
       }
     
       public static void main(String []args) {
          Main main = new Main();
       }
    }
    

    Creating a simple JFace ApplicationWindow

    Make sure your classpath and library path includes the correct SWT and JFace libraries.

    In my case:

       org.eclipse.ui_2.0.1/workbench.jar
       org.eclipse.swt.win32_2.0.1/ws/win32/swt.jar
       org.eclipse.core.runtime_2.0.1/runtime.jar
    

    Main.java:

    import org.eclipse.jface.window.*;
    import org.eclipse.swt.widgets.*;
    import org.eclipse.swt.*;
     
    public class Main extends ApplicationWindow {
       public Main(Shell parent) {
          super(parent);
          setBlockOnOpen(true);
       }
       
       public static void main(String []args) {
          Display display = new Display();
          Shell shell = new Shell(display);
          
          Main main = new Main(shell);
          main.open();
       }
    }
    

    Using a simple combobox in SWT

    Main.java:

    import org.eclipse.swt.SWT;
    import org.eclipse.swt.events.SelectionAdapter;
    import org.eclipse.swt.events.SelectionEvent;
    import org.eclipse.swt.events.SelectionListener;
    import org.eclipse.swt.layout.GridData;
    import org.eclipse.swt.layout.GridLayout;
    import org.eclipse.swt.widgets.Button;
    import org.eclipse.swt.widgets.Combo;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Group;
    import org.eclipse.swt.widgets.Shell;
     
    public class Main {
       public static void main(String[] args) {
          Display display = new Display();
          Shell shell = new Shell(display);
     
          // pos x, pos y, width, height
          shell.setBounds(200, 200, 300, 200);
          shell.setText("SWT Simple Editable Combobox Demonstration");
          shell.setLayout(new GridLayout());
     
          String[] comboData = { "one", "two", "three", "four", "five",
                                 "six", "seven", "eight", "nine", "ten",
                                 "eleven", "twelve", "thirtheen", "fourteen",
                                 "fifteen", "sixteen", "seventeen", "eighteen",
                                 "nineteen", "twinty" };
     
          Group comboGroup = new Group(shell, SWT.NULL);
          GridLayout gridLayout = new GridLayout();
          gridLayout.numColumns = 1;
          comboGroup.setLayout(gridLayout);
          comboGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
          comboGroup.setText("Editable Combo");
           
          Combo combo = new Combo(comboGroup, SWT.SIMPLE);
          SelectionListener selectionListener = new SelectionAdapter () {
             public void widgetSelected(SelectionEvent event) {
                Combo combo = ((Combo) event.widget);
                System.out.print(combo.getText());
                System.out.println(" selected = " + combo.getSelection());
             };
          };
          combo.addSelectionListener(selectionListener);
          combo.setItems(comboData);
           
          shell.open();
     
          while (!shell.isDisposed()) {
             if (!display.readAndDispatch()) {
                display.sleep();
             }
          }
          display.dispose();
       }
    }
    

    Creating an SWT table

    Main.java:

    import org.eclipse.swt.SWT;
    import org.eclipse.swt.layout.GridData;
    import org.eclipse.swt.layout.GridLayout;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Group;
    import org.eclipse.swt.widgets.Shell;
    import org.eclipse.swt.widgets.Table;
    import org.eclipse.swt.widgets.TableColumn;
    import org.eclipse.swt.widgets.TableItem;
     
    public class Main {
       public static void main(String[] args) {
          Display display = new Display();
          Shell shell = new Shell(display);
     
          // pos x, pos y, width, height
          shell.setBounds(200, 200, 300, 200);
          shell.setText("SWT Table Demonstration");
          shell.setLayout(new GridLayout());
     
          Table table;
          String[] columnTitles = { "Wine", "Vintage", "Price" };
    
          Object[][] tabledata = {
                { "Chateau Meyney, St. Estephe",       new Integer(1994), "$18.75"},
                { "Chateau Montrose, St. Estephe",     new Integer(1975), "$54.25" },
                { "Chateau Gloria, St. Julien",     new Integer(1993), "$22.99" },
                { "Chateau Beychevelle, St. Julien",   new Integer(1970), "$61.63" },
                { "Chateau La Tour de Mons, Margeaux", new Integer(1975), "$57.03" },
                { "Chateau Brane-Cantenac, Margeaux",  new Integer(1978), "$49.92" },
          };
     
          Group tableGroup = new Group(shell, SWT.NULL);
          GridLayout gridLayout = new GridLayout();
          gridLayout.numColumns = 1;
          tableGroup.setLayout(gridLayout);
          tableGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
          tableGroup.setText("Table");
     
          table = new Table(tableGroup, SWT.FULL_SELECTION);
          table.setHeaderVisible(true);
           
          for (int i=0; i<columnTitles.length; i++) {
             TableColumn tableColumn = new TableColumn(table, SWT.NULL);
             tableColumn.setText(columnTitles[i]);
          }  
           
          for (int i=0; i<tabledata.length; i++) {
             TableItem tableItem = new TableItem (table, SWT.NULL);
             for (int j=0; j<columnTitles.length; j++) {
                tableItem.setText(j, ""+tabledata[i][j]);
             }
          }
     
          for (int i=0; i<columnTitles.length; i++) {
             TableColumn tableColumn = table.getColumn(i);
             tableColumn.pack();
          }      
           
          shell.open();
     
          while (!shell.isDisposed()) {
             if (!display.readAndDispatch()) {
                display.sleep();
             }
          }
          display.dispose();
       }
    }
    

    Creating a ProgressBar in SWT

    Main.java:

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
     
    import org.eclipse.swt.SWT;
    import org.eclipse.swt.events.SelectionAdapter;
    import org.eclipse.swt.events.SelectionEvent;
    import org.eclipse.swt.events.ShellAdapter;
    import org.eclipse.swt.events.ShellEvent;
    import org.eclipse.swt.layout.FormAttachment;
    import org.eclipse.swt.layout.FormData;
    import org.eclipse.swt.layout.FormLayout;
    import org.eclipse.swt.widgets.Button;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Label;
    import org.eclipse.swt.widgets.ProgressBar;
    import org.eclipse.swt.widgets.Shell;
    import org.eclipse.swt.widgets.Text;
     
    public class Main {
       private DownloadThread downloadThread = null;
       private boolean disposed = false;
        
       public Main() {
          final Display display = new Display();
          Shell shell = new Shell(display);
          shell.setText("SWT ProgressBar Demonstration");
    
          shell.setLayout(new FormLayout());
          shell.setBounds(200, 200, 700, 200);
           
          Label downloadLabel = new Label(shell, SWT.NONE);
          FormData data0 = new FormData();
          data0.left = new FormAttachment(0, 0);
          downloadLabel.setLayoutData(data0);
          downloadLabel.setText("FTP file: ");
     
          final Text downloadField = new Text(shell, SWT.SINGLE | SWT.BORDER);
          FormData data1 = new FormData();
          data1.left = new FormAttachment(downloadLabel, 15);
          data1.right = new FormAttachment(100, -100);
          downloadField.setLayoutData(data1);
          downloadField.setText("ftp://ftp.mozilla.org/pub/mozilla/moz-sol/1.2a-02-09-25/mozilla-sparc-sun-solaris2.7.tar.gz");
                
          Label localLabel = new Label(shell, SWT.NONE);
          FormData data2 = new FormData();
          data2.left = new FormAttachment(0, 0);
          data2.top = new FormAttachment(localLabel, 15);
          localLabel.setLayoutData(data2);
          localLabel.setText("Save As: ");
          
          final Text localField = new Text(shell, SWT.SINGLE | SWT.BORDER);
          FormData data3 = new FormData();
          data3.left = new FormAttachment(localLabel, 15);
          data3.top = new FormAttachment(downloadField, 5);
          data3.right = new FormAttachment(100, -400);
          localField.setLayoutData(data3);
          localField.setText("c:\temp\tmp.bin");
          
          final Button downloadButton = new Button(shell, SWT.NONE);
          FormData data4 = new FormData();
          data4.left = new FormAttachment(downloadField, 5);
          data4.right = new FormAttachment(100, -5);
          downloadButton.setLayoutData(data4);
          downloadButton.setText("Download");
          
          Label progressLabel = new Label(shell, SWT.NONE);
          progressLabel.setText("Download progress:");
          FormData data5 = new FormData();
          data5.top = new FormAttachment(localField, 15);
          data5.left = new FormAttachment(10, 15);      
          data5.right = new FormAttachment(90, -15);
          progressLabel.setLayoutData(data5);      
                 
          final ProgressBar progressBar = new ProgressBar(shell, SWT.NONE);
          FormData data6 = new FormData();
          data6.top = new FormAttachment(localField, 35);
          data6.left = new FormAttachment(10, 15);      
          data6.right = new FormAttachment(90, -15);
          progressBar.setLayoutData(data6);
     
          shell.open();
     
          final DownloadListener downloadListener = new DownloadListener() {
             public void setMinimum(final int min) {
                display.asyncExec(new Runnable() {
                   public void run() {
                      if (!disposed) {
                         progressBar.setMinimum(min);
                      }
                   }
                });
             }
             
             public void setMaximum(final int max) {
                display.asyncExec(new Runnable() {
                   public void run() {
                      if (!disposed) {
                         progressBar.setMaximum(max);
                      }
                   }
                });
             }
             
             public void setSelection(final int selection) {
                display.asyncExec(new Runnable() {
                   public void run() {
                      if (!disposed) {
                         progressBar.setSelection(selection);
                      }
                   }
                });
             }
             
             public void downloadEnded() {
                if (!disposed) {
                   display.asyncExec(new Runnable() {
                      public void run() {
                         System.out.println("disposed = " + disposed);
                         if (!disposed) {                  
                            downloadButton.setText("Download");  
                         }
                      }
                   });
                }
             }
          };
          
          downloadButton.addSelectionListener(new SelectionAdapter() {
             public void widgetSelected(SelectionEvent event) {
                try {
                   Button button = (Button) event.getSource();
                   if (button.getText().equalsIgnoreCase("download")) {
                      if (downloadField.getText().trim().equals("")) return;
                      
                      File localFile = new File(localField.getText());
                      downloadThread = new DownloadThread(downloadListener, 
                                                          localFile,
                                                          new URL(downloadField.getText()));
                      downloadThread.start();
                      downloadButton.setText("Stop");
                   }
                   else {
                      downloadThread.terminate();
                   }
                }
                catch(MalformedURLException e) {
                   e.printStackTrace();
                }
             };
          });
     
          shell.addShellListener(new ShellAdapter() {
             public void shellClosed(ShellEvent se) {
                disposed = true;     
                if (downloadThread != null) {         
                   downloadThread.terminate();
                }
             }
          });        
          
          while (!shell.isDisposed()) {
             if (!display.readAndDispatch()) {
                display.sleep();
             }
          }
          
          display.dispose();
       }
       
       public static void main(String[] args) {
          new Main();
       }
    }
     
    interface DownloadListener {
       public void setMinimum(int min);
       public void setMaximum(int max);
       public void setSelection(int selection);
       public void downloadEnded();
    }
     
    class DownloadThread extends Thread
    {
       private int length = 0;
       private URL url = null;
       private File localFile = null;
       private DownloadListener listener = null;
       private boolean terminated = false;
       
       public DownloadThread(DownloadListener listener, File localFile, URL url) {
          this.url = url;
          this.localFile = localFile;
          this.listener = listener;
       }
       
       public void terminate() {
          terminated = true;
       }
       
       public void run() {
          try {
             System.out.println(url);
             URLConnection con = url.openConnection();
             System.out.println("Connecting...");
             con.connect();
             System.out.println("Connected!");
             int length = con.getContentLength();
     
             listener.setMinimum(0);
             listener.setMaximum(length);
              
             int block = 4096;
             int count = 0;
             FileOutputStream fos = new FileOutputStream(localFile);
             InputStream is = con.getInputStream();
             byte[] buff = new byte[block];
             int read = 0;
     
             listener.setSelection(0);
             while((read = is.read(buff, 0, block)) != -1) {
                byte[] bytes;
                if(read != buff.length) {
                   bytes = new byte[read];
                   System.arraycopy(buff, 0, bytes, 0, read);
                } 
                else {
                   bytes = buff;
                }
                fos.write(bytes);
                count += read;
               
                if (terminated) {
                   break;
                }
     
                listener.setSelection(count);
             }
             fos.flush();
             fos.close();
             
             listener.downloadEnded();
          } catch(Exception e) {
             System.out.println("Error downloading file " + url);
             e.printStackTrace();
          }
       }
    }
    

    Using a DigestOutputStream

    With a DigestOutputStream, you can calculate a digest (SHA, MD5) while you are passing data through the stream. The process of calculating the digest can be turned off and on with the method DigestOutputStream.on(boolean).

    In the following example, Main.java is read in and written to Main.java.digest. In the process, every other byte is taken into account to update the digest. In the end, the digest is appended to Main.java.digest.

    Main.java:

    import java.security.*;
    import java.io.*;
     
    public class Main
    {
       public static void main(String []args) {
          try {
             FileInputStream fis = new FileInputStream("Main.java");
             FileOutputStream fos = new FileOutputStream("Main.java.digest");
     
             MessageDigest md = MessageDigest.getInstance("SHA");
             DigestOutputStream dos = new DigestOutputStream(fos, md);
     
             int b;
             boolean state = true;
             while ((b = fis.read()) != -1) {
                dos.write(b);
     
                state = !state;
                dos.on(state);
             }
     
             // turn of digest calculation
             // and write digest to end of file
             dos.on(false);
             byte[] buffer = md.digest();
             dos.write(buffer, 0, buffer.length);
             dos.close();
          }
          catch(Exception e) {
             e.printStackTrace();
          }
       }
    } 
    

    Changing the traversal keys that control focus

    In 1.4, you can use the following method.

    Main.java:

    import javax.swing.*;
    import java.util.*;
    import java.awt.*;
     
    public class Main extends JFrame
    {
       JLabel label = new JLabel("Forward: TAB or alt-f, Backward: SHIFT-TAB or alt-b");
       JButton button = new JButton("Button");
       JTextField textfield1 = new JTextField();
       JTextField textfield2 = new JTextField();
     
       public Main() {
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
          Container contentPane = getContentPane();
          contentPane.setLayout(new BorderLayout());
          JPanel panel = new JPanel(new GridLayout(4, 1, 10, 10));
          panel.add(label);
          panel.add(textfield1);   
          panel.add(textfield2);   
          panel.add(button);
          contentPane.add(BorderLayout.NORTH, panel);
     
          // add "alt f" as an alternative to TAB 
          Set set = contentPane.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
          KeyStroke altf = KeyStroke.getKeyStroke("alt F");
          set = new HashSet(set);
          set.add(altf);
          contentPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);
     
          // add "alt b" as an alternative to SHIFT-TAB 
          set = contentPane.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
          KeyStroke altb = KeyStroke.getKeyStroke("alt B");
          set = new HashSet(set);
          set.add(altb);
          contentPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set);
       } 
     
       public static void main(String []args) {
          Main main = new Main();
          main.setSize(350, 200);
          main.setVisible(true);
       }
    }