Change the orientation of a JTextArea, eg. right to left

You can use the method setComponentOrientation defined in the Component class, so
you can invoke it on most Swing components.
It does not seem to work properly using JDK1.2, but does with JDK1.3.

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
   
public class Main extends JFrame
{
   public Main() throws Exception {
      JTextArea tf = new JTextArea();
      getContentPane().add(tf);
      pack();

      tf.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String args[]) throws Exception {
      Main main = new Main();
      main.show();
   }
}

For international applications, you can determine the orientation using
the Locale:

      Locale arabic = new Locale("ar", "SA");
      jcomponent.setComponentOrientation(ComponentOrientation.getOrientation(arabic));

Adding a background to a JTextArea

Make sure the opaqueness property of your JTextArea component is false. You can then override the paintComponent method that draws the background image and calls super.paintComponent. Here’s an example:

import javax.swing.*;
import java.awt.*;
 
public class Main {
   public static void main(String args[]) {
      JFrame frame = new JFrame("JTextArea Background Demonstration");
      final ImageIcon imageIcon = new ImageIcon("esuslogo.gif");
 
      JTextArea textArea = new JTextArea() {
         Image image = imageIcon.getImage();
         { 
            setOpaque(false);
            image = image.getScaledInstance(400, 300, Image.SCALE_DEFAULT);
         }
         public void paintComponent (Graphics g) {
            g.drawImage(image, 0, 0, this);
            setForeground(Color.blue);
            super.paintComponent(g);
         }
      };
      textArea.setFont(new Font("Helvetica", Font.BOLD, 16));
 
      frame.getContentPane().add(BorderLayout.CENTER, new JScrollPane(textArea));
      frame.setDefaultCloseOperation(3);
      frame.setSize(400, 300);
      frame.setVisible(true);
      frame.setResizable(false);
   }
}

Line numbers in a JTextArea

Here are two examples. The second was born from the first.

First Example: an extension to a component…

The first example LineNumberedPaper is a class that extends JTextArea and draws the line numbers in the paintComponent()
method. LineNumberedPaper artificially increases the size of the border by overriding the getInsets() methods and adding room for the “line numbers” (using the method lineNumberWidth()) to the left attribute of Insets.

paintComponent(), contains the logic for determining which line
numbers must be drawn based upon the the clip rectangle of the Graphics.

LineNumeredPaper can be modified to display the line numbers on the right side of the paper, this is left as an exercise for the reader. After, this idea was completed, the “border” increase forced the writing of the second example, LineNumberedBorder.

Second Example: a new border…

LineNumberedBorder is a border which draws a left (LEFT_JUSTIFY) or right (RIGHT_JUSTIFY) justified line number on either the left (LEFT_SIDE) or right side (RIGHT_SIDE) of the component. Currently, this only supports a JTextArea, due to the reliance on the getRows() and getLineCount() methods. paintBorder() contains the drawing of the line numbers and is very similar to LineNumberedPaper.paintComponent().

Summary

  • Each class has a main() which creates all possibilities for each class and can be easily removed.
  • The font of the line numbers is the same as the text.
    How would two different fonts play together? Which class/interface in javax.swing.text or subpackage should be used or extended?
  • paintComponent() and paintBorder() are very similar and speed is important, since each blink of the cursor causes a repaint.

LineNumberedPaper.java:

import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
 
import javax.swing.BorderFactory;
import javax.swing.JTextArea;
 
/**
 * Draws line numbers next to each line, in the same font as the text.
 * Based upon the comment in {@link #getInsets(Insets) getInsets} maybe the
 * "line numbering" could be a border?
 */
public class LineNumberedPaper extends JTextArea {
 
   public static void main(String[] args)
   {
      javax.swing.JFrame frame = new javax.swing.JFrame("Line Numbers...");
      frame.addWindowListener(new java.awt.event.WindowAdapter() {
         public void windowClosing(java.awt.event.WindowEvent ev) {
            System.exit(0);
         }
      });
 
      java.awt.Container contentPane = frame.getContentPane();
      contentPane.setLayout(new java.awt.GridLayout(0,2));
 
      javax.swing.JPanel subpanel;
      LineNumberedPaper lnp;
 
      int []justified = { LineNumberedBorder.LEFT_JUSTIFY,
                          LineNumberedBorder.RIGHT_JUSTIFY};
 
      String []labels = { "Left Justified",
                          "Right Justified"};
 
      for (int idx = 0; idx < labels.length; idx++) {
         lnp = new LineNumberedPaper(10,10);
         lnp.setLineNumberJustification(justified[idx]);
 
         subpanel = new javax.swing.JPanel(new java.awt.BorderLayout());
         subpanel.add(new javax.swing.JLabel(labels[idx]), java.awt.BorderLayout.NORTH);
         subpanel.add(new javax.swing.JScrollPane(lnp), java.awt.BorderLayout.CENTER);
         contentPane.add(subpanel);
      }
 
      frame.setSize(800,600);
      frame.show();
   } // main
 
   /**
    * The line number should be right justified.
    */
   public static int RIGHT_JUSTIFY = 0;
 
   /**
    * The line number should be left justified.
    */
   public static int LEFT_JUSTIFY = 1;
 
   /**
    * Indicates the justification of the text of the line number.
    */
   private int lineNumberJustification = RIGHT_JUSTIFY;
 
   public LineNumberedPaper(int rows, int cols) {
      super(rows, cols);
      setOpaque(false);
      // if this is NOT opaque...then painting is a problem...
      // basically...this draws the line numbers...
      // but...super.paintComponent()...erases the background...and the
      // line numbers...what to do?
      //
      // "workaround": paint the background in this class...
   }
 
   public Insets getInsets() {
      return getInsets(new Insets(0,0,0,0));
   }
 
   /**
    * This modifies the insets, by adding space for the line number on the
    * left. Should be modified to add space on the right, depending upon
    * Locale.
    */
   public Insets getInsets(Insets insets) {
      insets = super.getInsets(insets);
      insets.left += lineNumberWidth();
      return insets;
   }
 
   public int getLineNumberJustification() {
      return lineNumberJustification;
   }
 
   public void setLineNumberJustification(int justify) {
      if (justify == RIGHT_JUSTIFY || justify == LEFT_JUSTIFY) {
         lineNumberJustification = justify;
      }
   }
 
   /**
    * Returns the width, in pixels, of the maximum line number, plus a
    * trailing space.
    */
   private int lineNumberWidth() {
      //
      // note: should this be changed to use all nines for the lineCount?
      // for example, if the number of rows is 111...999 could be wider
      // (in pixels) in a proportionally spaced font...
      //
      int lineCount = Math.max(getRows(), getLineCount() + 1);
      return getFontMetrics(getFont()).stringWidth(lineCount + " ");
   }
 
   //
   // NOTE: This method is called every time the cursor blinks...
   //       so...optimize (later and if possible) for speed...
   //
   public void paintComponent(Graphics g) {
      Insets insets = getInsets();
 
      Rectangle clip = g.getClipBounds();
 
      g.setColor(getBackground()); // see note in constructor about this...
      g.fillRect(clip.x, clip.y, clip.width, clip.height);
 
      // do the line numbers need redrawn?
      if (clip.x < insets.left) {
         FontMetrics fm = g.getFontMetrics();
         int fontHeight = fm.getHeight();
 
         // starting location at the "top" of the page...
         // y is the starting baseline for the font...
         // should "font leading" be applied?
         int y = fm.getAscent() + insets.top;
 
         //
         // now determine if it is the "top" of the page...or somewhere else
         //
         int startingLineNumber = ((clip.y + insets.top) / fontHeight) + 1;
 
         //
         // use any one of the following if's:
         //
         //			if (startingLineNumber != 1)
         if (y < clip.y) {
            //
            // not within the clip rectangle...move it...
            // determine how many fontHeight's there are between
            // y and clip.y...then add that many fontHeights
            //
 
            y = startingLineNumber * fontHeight - (fontHeight - fm.getAscent());
         }
 
         //
         // options:
         // . write the number rows in the document (current)
         // . write the number of existing lines in the document (to do)
         //   see getLineCount()
         //
         // determine which the "drawing" should end...
         // add fontHeight: make sure...part of the line number is drawn
         //
         // could also do this by determining what the last line
         // number to draw.
         // then the "while" loop whould change accordingly.
         //
         int	yend = y + clip.height + fontHeight;
 
         // base x position of the line number
         int lnxstart = insets.left;
         if (lineNumberJustification == LEFT_JUSTIFY) {
            // actual starting location of the string of a left
            // justified string...it's constant...
            // the right justified string "moves"...
            lnxstart -= lineNumberWidth();
         }
 
         g.setColor(getForeground());
         //
         // loop until out of the "visible" region...
         //
         int length = ("" + Math.max(getRows(), getLineCount() + 1)).length();
         while (y < yend) {
            //
            // options:
            // . left justify the line numbers (current)
            // . right justify the line number (to do)
            //
 
            if (lineNumberJustification == LEFT_JUSTIFY) {
               g.drawString(startingLineNumber + " ", lnxstart, y);
            } else { // right justify
               String label = padLabel(startingLineNumber, length, true);
               g.drawString(label, insets.left - fm.stringWidth(label), y);
            }
 
            y += fontHeight;
            startingLineNumber++;
         }
      } // draw line numbers?
 
      super.paintComponent(g);
   } // paintComponent
 
   /**
    * Create the string for the line number.
    * NOTE: The <tt>length</tt> param does not include the
    * <em>optional</em> space added after the line number.
    *
    * @param lineNumber to stringize
    * @param length     the length desired of the string
    * @param length     the length desired of the string
    *
    * @return the line number for drawing
    */
   private String padLabel(int lineNumber, int length, boolean addSpace) {
      StringBuffer buffer = new StringBuffer();
      buffer.append(lineNumber);
      for (int count = (length - buffer.length()); count > 0; count--) {
         buffer.insert(0, ' ');
      }
      if (addSpace) {
         buffer.append(' ');
      }
      return buffer.toString();
   }
} // LineNumberedPaper

LineNumberedBorder.java:

import java.awt.Component;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
 
import javax.swing.JTextArea;
import javax.swing.border.AbstractBorder;
 
/**
 *  Draws line numbers next to each line, in the same font as the text.
 *  Currently, this can only be used with a <tt>JTextArea</tt> , since it relies
 *  on the <tt>getRows()</tt> and <tt>getLineCount()</tt> methods. A possible
 *  extension, create an interface to return this rows/linecount.
 *
 *@author     Administrator
 *@created    January 29, 2002
 */
public class LineNumberedBorder extends AbstractBorder {
   public static void main(String[] args) {
      javax.swing.JFrame frame = new javax.swing.JFrame("Line Numbers (as Borders)...");
      frame.addWindowListener(
         new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent ev) {
               System.exit(0);
            }
         });
 
      java.awt.Container contentPane = frame.getContentPane();
      contentPane.setLayout(new java.awt.GridLayout(0, 2));
 
      int[] sides = {
            LineNumberedBorder.LEFT_SIDE,
            LineNumberedBorder.LEFT_SIDE,
            LineNumberedBorder.RIGHT_SIDE,
            LineNumberedBorder.RIGHT_SIDE};
 
      int[] justified = {
            LineNumberedBorder.LEFT_JUSTIFY,
            LineNumberedBorder.RIGHT_JUSTIFY,
            LineNumberedBorder.LEFT_JUSTIFY,
            LineNumberedBorder.RIGHT_JUSTIFY};
 
      String[] labels = {
            "Left Side/Left Justified",
            "Left Side/Right Justified",
            "Right Side/Left Justified",
            "Right Side/Right Justified"};
 
      javax.swing.JPanel subpanel;
      JTextArea textArea;
 
      boolean useMultipleBorders = false;
      if (args.length > 0 && "multiple".equals(args[0])) {
         useMultipleBorders = true;
      }
 
      for (int idx = 0; idx < labels.length; idx++) {
         textArea = new JTextArea(10, 10);
         LineNumberedBorder lnb = new LineNumberedBorder(sides[idx], justified[idx]);
         if (useMultipleBorders) {
            textArea.setBorder(
                  javax.swing.BorderFactory.createCompoundBorder(
                  javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5),
                  javax.swing.BorderFactory.createCompoundBorder(
                  javax.swing.BorderFactory.createLineBorder(java.awt.Color.red, 1),
                  javax.swing.BorderFactory.createCompoundBorder(
                  lnb,
                  javax.swing.BorderFactory.createLineBorder(java.awt.Color.blue, 1)
                  )
                  )
                  )
                  );
         } else {
            textArea.setBorder(lnb);
         }
 
         subpanel = new javax.swing.JPanel(new java.awt.BorderLayout());
         subpanel.add(new javax.swing.JLabel(labels[idx]), java.awt.BorderLayout.NORTH);
         subpanel.add(new javax.swing.JScrollPane(textArea), java.awt.BorderLayout.CENTER);
         contentPane.add(subpanel);
      }
 
      frame.setSize(800, 600);
      frame.show();
   }
   // main
 
   /**
    *  The line numbers should be drawn on the left side of the component.
    */
   public static int LEFT_SIDE = -2;
 
   /**
    *  The line numbers should be drawn on the right side of the component.
    */
   public static int RIGHT_SIDE = -1;
 
   /**
    *  The line number should be right justified.
    */
   public static int RIGHT_JUSTIFY = 0;
 
   /**
    *  The line number should be left justified.
    */
   public static int LEFT_JUSTIFY = 1;
 
   /**
    *  Indicates the justification of the text of the line number.
    */
   private int lineNumberJustification = RIGHT_JUSTIFY;
 
   /**
    *  Indicates the location of the line numbers, w.r.t. the component.
    */
   private int location = LEFT_SIDE;
 
   public LineNumberedBorder(int location, int justify) {
      setLocation(location);
      setLineNumberJustification(justify);
   }
 
   public Insets getBorderInsets(Component c) {
      return getBorderInsets(c, new Insets(0, 0, 0, 0));
   }
 
   /**
    *  This modifies the insets, by adding space for the line number on the
    *  left. Should be modified to add space on the right, depending upon
    *  Locale.
    *
    *@param  c       Description of the Parameter
    *@param  insets  Description of the Parameter
    *@return         The borderInsets value
    */
   public Insets getBorderInsets(Component c, Insets insets) {
      // if c is not a JTextArea...nothing is done...
      if (c instanceof JTextArea) {
         int width = lineNumberWidth((JTextArea) c);
         if (location == LEFT_SIDE) {
            insets.left = width;
         } else {
            insets.right = width;
         }
      }
      return insets;
   }
 
   public int getLineNumberJustification() {
      return lineNumberJustification;
   }
 
   public void setLineNumberJustification(int justify) {
      if (justify == RIGHT_JUSTIFY || justify == LEFT_JUSTIFY) {
         lineNumberJustification = justify;
      }
   }
 
   public int getLocation() {
      return location;
   }
 
   public void setLocation(int loc) {
      if (loc == RIGHT_SIDE || loc == LEFT_SIDE) {
         location = loc;
      }
   }
 
   /**
    *  Returns the width, in pixels, of the maximum line number, plus a trailing
    *  space.
    *
    *@param  textArea  Description of the Parameter
    *@return           Description of the Return Value
    */
   private int lineNumberWidth(JTextArea textArea) {
      //
      // note: should this be changed to use all nines for the lineCount?
      // for example, if the number of rows is 111...999 could be wider
      // (in pixels) in a proportionally spaced font...
      //
      int lineCount =
            Math.max(textArea.getRows(), textArea.getLineCount() + 1);
      return textArea.getFontMetrics(
            textArea.getFont()).stringWidth(lineCount + " ");
   }
 
   //
   // NOTE: This method is called every time the cursor blinks...
   //       so...optimize (later and if possible) for speed...
   //
   public void paintBorder(Component c, Graphics g, int x, int y,
         int width, int height) {
 
      java.awt.Rectangle clip = g.getClipBounds();
 
      FontMetrics fm = g.getFontMetrics();
      int fontHeight = fm.getHeight();
 
      // starting location at the "top" of the page...
      // y is the starting baseline for the font...
      // should "font leading" be applied?
      int ybaseline = y + fm.getAscent();
 
      //
      // now determine if it is the "top" of the page...or somewhere else
      //
      int startingLineNumber = (clip.y / fontHeight) + 1;
 
      //
      // use any one of the following if's:
      //
//		if (startingLineNumber != 1)
      if (ybaseline < clip.y) {
         //
         // not within the clip rectangle...move it...
         // determine how many fontHeight's there are between
         // y and clip.y...then add that many fontHeights
         //
         ybaseline = y + startingLineNumber * fontHeight -
               (fontHeight - fm.getAscent());
      }
 
      //
      // options:
      // . write the number rows in the document (current)
      // . write the number of existing lines in the document (to do)
      //   see getLineCount()
      //
 
      // determine which the "drawing" should end...
      // add fontHeight: make sure...part of the line number is drawn
      //
      // could also do this by determining what the last line
      // number to draw.
      // then the "while" loop whould change accordingly.
      //
      //int	yend = y + clip.height + fontHeight;
      //int	yend = ybaseline + height + fontHeight; // original
      int yend = ybaseline + height;
      if (yend > (y + height)) {
         yend = y + height;
      }
 
      JTextArea jta = (JTextArea) c;
      int lineWidth = lineNumberWidth(jta);
 
      // base x position of the line number
      int lnxstart = x;
      if (location == LEFT_SIDE) {
         // x (LEFT) or (x + lineWidth) (RIGHT)
         // (depends upon justification)
         if (lineNumberJustification == LEFT_JUSTIFY) {
            lnxstart = x;
         } else {
            // RIGHT JUSTIFY
            lnxstart = x + lineWidth;
         }
      } else {
         // RIGHT SIDE
         // (y + width) - lineWidth (LEFT) or (y + width) (RIGHT)
         // (depends upon justification)
         if (lineNumberJustification == LEFT_JUSTIFY) {
            lnxstart = (y + width) - lineWidth;
         } else {
            // RIGHT JUSTIFY
            lnxstart = (y + width);
         }
      }
 
      g.setColor(c.getForeground());
      //
      // loop until out of the "visible" region...
      //
      int length = ("" + Math.max(jta.getRows(), jta.getLineCount() + 1)).length();
      while (ybaseline < yend) {
         //
         // options:
         // . left justify the line numbers
         // . right justify the line numbers
         //
 
         if (lineNumberJustification == LEFT_JUSTIFY) {
            g.drawString(startingLineNumber + " ", lnxstart, ybaseline);
         } else {
            // right justify
            String label = padLabel(startingLineNumber, length, true);
            g.drawString(label, lnxstart - fm.stringWidth(label), ybaseline);
         }
 
         ybaseline += fontHeight;
         startingLineNumber++;
      }
   }
   // paintComponent
 
   /**
    *  Create the string for the line number. NOTE: The <tt>length</tt> param
    *  does not include the <em>optional</em> space added after the line number.
    *
    *@param  lineNumber  to stringize
    *@param  length      the length desired of the string
    *@param  addSpace    Description of the Parameter
    *@return             the line number for drawing
    */
   private static String padLabel(int lineNumber, int length, boolean addSpace) {
      StringBuffer buffer = new StringBuffer();
      buffer.append(lineNumber);
      for (int count = (length - buffer.length()); count > 0; count--) {
         buffer.insert(0, ' ');
      }
      if (addSpace) {
         buffer.append(' ');
      }
      return buffer.toString();
   }
}
// LineNumberedBorder

Incorporating speech in a Swing application

1) First you need to download a speech engine. For example, you can download for free the Microsoft’s Speech SDK here. (Beware: version 5.1 is 68MB). Use the tools available to make sure the SDK is properly installed and trained to your voice.

2) Then get an implementation of Sun’s Java Speech API (JSAPI). The one I used in this example is from the CloudGarden. Follow the instructions on this page to find out how to install: copy the files jsapi.dll and jsapi.jar to JRE_HOME/lib/ext and adjust your classpath so that it includes jsapi.jar, necessary to compile following sample program.

3) This sample program was written by looking at the Cloud Garden examples. I dictated the following text to the app: “Last night, after a productive day of work, I joined my girlfriend in bed and quoted a very famous poet, who’s name escapes me. I said: ‘I feel great sexual desire for you right now.’. She said she’s not into poetry.”. The result (see window) was better than I expected.

Main.java:

import javax.speech.recognition.*;
import javax.speech.synthesis.*;
import javax.speech.*;
 
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{ 
   TextComponentSpeechEnabler tcse;
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            tcse.deallocate();
            System.exit(1);
         }
      });
 
      getContentPane().setLayout(new BorderLayout(10, 10));
      JTextArea textArea = new JTextArea();
      textArea.setLineWrap(true);
 
      try {
         tcse = new TextComponentSpeechEnabler(textArea);
         getContentPane().add(BorderLayout.CENTER, tcse.getPanel());
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(500, 500);
      main.setVisible(true);
   }
}
 
class TextComponentSpeechEnabler
{
   static Recognizer recognizer;
 
   JPanel         textComponentPanel;
   JTextComponent textComponent;
   JTextField     speakerName;
   JTextArea      statusArea;
 
   public TextComponentSpeechEnabler(JTextComponent textComponent) throws Exception {
      this.textComponent = textComponent;
      
      createPanel();
      initializeRecognizer();
   }
  
   public void initializeRecognizer() throws Exception {
      recognizer = Central.createRecognizer(null);
      recognizer.addResultListener(new MyResultListener());
      recognizer.allocate();
      recognizer.waitEngineState(Recognizer.ALLOCATED);
 
      SpeakerManager speakerManager = recognizer.getSpeakerManager();
      SpeakerProfile[] speakers = speakerManager.listKnownSpeakers();
      for (int i=0; i<speakers.length; i++) {
         addStatusText("Found profile of " + speakers[i].getName());
      }
 
      addStatusText("Current profile is " +
                                   speakerManager.getCurrentSpeaker().getName());
      speakerName.setText(speakerManager.getCurrentSpeaker().getName());
      speakerManager.setCurrentSpeaker(speakers[0]);
 
      DictationGrammar dictation = recognizer.getDictationGrammar("dictation");
      dictation.setEnabled(true);
 
      recognizer.commitChanges();
 
      recognizer.requestFocus();
      recognizer.resume(); 
   }
 
   public void deallocate() {
      System.out.println("deallocated!");
      try {
         recognizer.deallocate();
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   }
 
   private void createPanel() {
      textComponentPanel = new JPanel(new BorderLayout(10, 10));
      JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
      northPanel.add(new JLabel("Speaker name:  "));
      speakerName = new JTextField(25);
      northPanel.add(speakerName);
      textComponentPanel.add(BorderLayout.NORTH, northPanel);
      textComponentPanel.add(BorderLayout.CENTER, new JScrollPane(textComponent));
 
      statusArea = new JTextArea(10, 50);
      textComponentPanel.add(BorderLayout.SOUTH, new JScrollPane(statusArea));   
   }
  
   public JPanel getPanel() {
      return textComponentPanel;
   }
 
   public void addStatusText(final String s) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            statusArea.append(s + "n");
            statusArea.setCaretPosition(statusArea.getDocument().getLength());
         }
      });
   }
 
   public void addText(final String s) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            textComponent.setText(textComponent.getText() + s);
            textComponent.setCaretPosition(textComponent.getDocument().getLength());
         }
      });
   }
  
   class MyResultListener extends ResultAdapter {
      public void resultRejected(ResultEvent e) {
      }
 
      public void resultCreated(ResultEvent e) {
      }
 
      public void resultUpdated(ResultEvent e) {
      }
 
      public void resultAccepted(ResultEvent e) {
         FinalResult finalResult = (FinalResult)(e.getSource());
         ResultToken tokens[] = null;
         tokens = finalResult.getBestTokens();
 
         StringBuffer sb = new StringBuffer();
         for (int i=0; i<tokens.length; i++) {
            sb.append(tokens[i].getSpokenText() + " ");  
         }
         addText(sb.toString());
         addStatusText("" + finalResult);
      }
   }
}

Feel free to mail me any improvements!

A Swing drag and drop code example

Drag and Drop is a powerful feature you should consider adding to your Java applications. When you check out the available tutorials on Java dnd, it may look fairly complex to you. Though it’s not all that hard, the hard part is remembering all the steps, objects and listeners involved. Here is a small example that shows you a basic drag and drop application (implemented with Swing).

A custom Drag and Drop (source) JList appears to the right and contains a file list of your root directory. Files with .txt extensions can be dragged upon our Drag and Drop JTextArea (target). The object transferred (Transferable) is a filename. When the drop occurs (you release the mouse button) the public void drop(DropTargetDropEvent event) is called. You can extract the filename from the Transferable object and go from there.

Main.java

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
 
public class Main extends JFrame
{
   private DNDJList list;
   private DNDJTextArea textarea;
 
   public static void main(String []args) {
      Main frame = new Main();
      frame.show();
   }
 
   public Main() {
      getContentPane().setLayout(new BorderLayout());
      list = new DNDJList(new DefaultListModel());
      getContentPane().add(BorderLayout.EAST, new JScrollPane(list));
      textarea = new DNDJTextArea();
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(textarea));
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
 
      fillUpList(&quot;c:\&quot;);
 
      setSize(700, 300);
   }

   /**
    *  Fills up the JList with the entries in the specified directory
    */
   private void fillUpList(String directory) {
      File dir = new File(directory);
      File []files = dir.listFiles();
 
      DefaultListModel dlm = (DefaultListModel) list.getModel();
      for (int i=0; i&lt;files.length; i++) {
         dlm.addElement(directory + files[i].getName());
      }
   }
}

Our drag and drop JTextArea: DNDJTextArea.java

import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;

import java.io.*;
import java.io.IOException;
 
import javax.swing.JTextArea;
 
public class DNDJTextArea extends JTextArea implements DropTargetListener
{
   DropTarget dropTarget = null;
  
   public DNDJTextArea() {
      // create a drop target
      dropTarget = new DropTarget(this, this);
   }
 
   public void dragEnter(DropTargetDragEvent event) { 
      event.acceptDrag(DnDConstants.ACTION_MOVE);
   }
 
   public void drop (DropTargetDropEvent event) {
      try {
         // get the object that is being transferred
         Transferable transferable = event.getTransferable();
       
         // DNDJTextArea accepts only Strings
         if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
            event.acceptDrop(DnDConstants.ACTION_MOVE);
 
            String filename = (String) transferable.getTransferData(DataFlavor.stringFlavor);
            setText(readFile(filename));

            event.getDropTargetContext().dropComplete(true);
         } 
         else {
            event.rejectDrop();
         }
      }
      catch (UnsupportedFlavorException e) {
         setText(&quot;&quot;+e);
         event.rejectDrop();
      }
      catch (Exception e) {
         setText(&quot;&quot;+e);
         event.rejectDrop();
      } 
   }
 
   public void dragExit (DropTargetEvent event) { }
   public void dragOver (DropTargetDragEvent event) { }
   public void dropActionChanged (DropTargetDragEvent event) { }
 
   public String readFile(String filename) throws Exception {
      String LINEEND = System.getProperties().getProperty(&quot;line.separator&quot;);      
      StringBuffer sb = new StringBuffer();
      BufferedReader br = new BufferedReader(new FileReader(filename));
 
      String line;
      while ((line = br.readLine()) != null) {
         sb.append(line + LINEEND);
      }         
 
      return sb.toString();
   }
}

A drag and drop JList:DNDJList.java

import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.io.IOException;
import java.io.*;
 
import javax.swing.*;
 
public class DNDJList extends JList implements DragSourceListener, DragGestureListener    
{
   DragSource dragSource = null;
 
   public DNDJList(ListModel lm) {
      super(lm);
 
      // create a dragsource
      dragSource = new DragSource();
 
      // create a drag gesture recognizer
      dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
   }    
 
   public void dragGestureRecognized( DragGestureEvent event) {  
      String fileSelected = (String) getSelectedValue();
 
      if (fileSelected != null) {
         if (fileSelected.endsWith(&quot;.txt&quot;)) {
            // StringSelection implements Transferable, wraps the data into a transferable object
            StringSelection text = new StringSelection(fileSelected.toString()); 
        
            // start the dragging
            dragSource.startDrag(event, DragSource.DefaultMoveDrop, text, this);
         }
         else {
            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  JOptionPane.showMessageDialog(SwingUtilities.getRootPane(DNDJList.this), 
                                                &quot;Only .txt files can be dragged!&quot;, &quot;Error&quot;,
                                                JOptionPane.ERROR_MESSAGE);
               } 
            });
         }
      } else {
         System.out.println( &quot;nothing was selected&quot;);   
      }
   }
 
   public void dragDropEnd (DragSourceDropEvent event) { }
   public void dragEnter (DragSourceDragEvent event) { }
   public void dragExit (DragSourceEvent event) { }
   public void dragOver (DragSourceDragEvent event) { }
   public void dropActionChanged ( DragSourceDragEvent event) { }
}

Having a JTextArea as a node of a JTree

Main.java:

import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
 
public class Main extends JFrame
{
   public Main() {
      DefaultMutableTreeNode root = createNodes();
      JTree tree = new JTree(root);
      //tree.setCellEditor(new DefaultCellEditor(new JTextField())); 
      tree.setCellRenderer(new DelegateDefaultCellRenderer());
      tree.setRowHeight(-1);
 
      getContentPane().add(new JScrollPane(tree));
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
   }
 
   public static DefaultMutableTreeNode createNodes() {
      DefaultMutableTreeNode root = new DefaultMutableTreeNode(&amp;amp;quot;Java&amp;amp;quot;);
      
      DefaultMutableTreeNode j2se = new DefaultMutableTreeNode(&amp;amp;quot;J2SE&amp;amp;quot;);
      DefaultMutableTreeNode j2ee = new DefaultMutableTreeNode(&amp;amp;quot;J2EE&amp;amp;quot;);
      DefaultMutableTreeNode j2me = new DefaultMutableTreeNode(&amp;amp;quot;J2ME&amp;amp;quot;);
 
      j2se.add(new DefaultMutableTreeNode(&amp;amp;quot;http://java.sun.com/j2se/&amp;amp;quot;));
      j2ee.add(new DefaultMutableTreeNode(&amp;amp;quot;http://java.sun.com/j2ee/&amp;amp;quot;));
      j2me.add(new DefaultMutableTreeNode(&amp;amp;quot;http://java.sun.com/j2me/&amp;amp;quot;));
 
      root.add(j2se);
      root.add(j2ee);
      root.add(j2me);
 
      return root;
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(400, 400);
      main.setVisible(true);
   }
}
 
class DelegateDefaultCellRenderer extends DefaultTreeCellRenderer 
{
   TextAreaRenderer taRenderer = new TextAreaRenderer();
 
   public DelegateDefaultCellRenderer() {
      taRenderer.setBackgroundNonSelectionColor(getBackgroundNonSelectionColor());
      taRenderer.setBackgroundSelectionColor(getBackgroundSelectionColor());
      taRenderer.setTextNonSelectionColor(getTextNonSelectionColor());  
      taRenderer.setTextSelectionColor(getTextSelectionColor()); 
   }
 
   public Component getTreeCellRendererComponent(JTree tree, Object value,
                                  boolean selected, boolean expanded, boolean leaf,
                                  int row, boolean hasFocus)
   {
      if (!leaf) {
         return super.getTreeCellRendererComponent(tree, value, selected, 
                                                   expanded, leaf, row, hasFocus);
      }
      else {
         return taRenderer.getTreeCellRendererComponent(tree, value, selected, 
                                                        expanded, leaf, row, hasFocus);
      }
   }
}   
 
class TextAreaRenderer extends JScrollPane implements TreeCellRenderer
{
   JTextArea textarea;
   Color backgroundNonSelectionColor;
   Color backgroundSelectionColor;
   Color textNonSelectionColor;
   Color textSelectionColor;
 
   public TextAreaRenderer() {
      textarea = new JTextArea(3, 40);
      textarea.setLineWrap(true);
      textarea.setWrapStyleWord(true);
      textarea.setBorder(new TitledBorder(&amp;amp;quot;This is a JTextArea&amp;amp;quot;));
      getViewport().add(textarea);
   }
 
   public void setBackgroundNonSelectionColor(Color c) {
      this.backgroundNonSelectionColor = c;
   }
 
   public void setBackgroundSelectionColor(Color c) {
      this.backgroundSelectionColor = c;
   }
  
   public void setTextNonSelectionColor(Color c) {
      this.textNonSelectionColor = c;
   }
  
   public void setTextSelectionColor(Color c) {
      this.textSelectionColor = c;
   }
 
   public Component getTreeCellRendererComponent(JTree tree, Object value,
                                  boolean selected, boolean expanded, boolean leaf,
                                  int row, boolean hasFocus)
   {
      if (selected) {
         setForeground(textSelectionColor);
         setBackground(backgroundSelectionColor);
         textarea.setForeground(textSelectionColor);
         textarea.setBackground(backgroundSelectionColor);
      } else {
         setForeground(textNonSelectionColor);
         setBackground(backgroundNonSelectionColor);
         textarea.setForeground(textNonSelectionColor);
         textarea.setBackground(backgroundNonSelectionColor);
      }
 
      textarea.setText(&amp;amp;quot;&amp;amp;quot;+((DefaultMutableTreeNode) value).getUserObject()); 
      textarea.setCaretPosition(0);
 
      return this;
   }
}

Compile Java contained in a String

A bit of hacking around lead to the following example. Create an instance of InMemorySourceCompiler and pass it the name of the program and the source code as a String. Any suggestions/improvements are appreciated as a comment to this answer.

The following example creates a JFrame that contains the output of the source.

Main.java:

import java.lang.reflect.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
  
import sun.tools.javac.*;  
import sun.tools.java.*;
   
public class Main extends JFrame
{
   public Main(String s) {
      getContentPane().add(new JTextArea(s, 3, 50));
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
   }
  
   public static void main(String args[]) throws Exception
   {
      // Save all data written to System.out to a byte array and display in frame
      PrintStream ps = System.out;
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      System.setOut(new PrintStream(baos));
 
      InMemorySourceCompiler imsCompiler = new InMemorySourceCompiler("Test",
          "public class Test {" +
          "   public static void main(String args[]) {" +
          "      System.out.println("Output of program:");" +
          "      for (int i=0; i<10; i++) {" +
          "         System.out.println(i);" +
          "      }" +
          "      System.out.println("End of output.");" + 
          "   }" +
          "}");
      imsCompiler.executeMain();
 
      byte[] b = baos.toByteArray();
 
      System.setOut(ps);
 
      String s = new String(b);
 
      Main main = new Main(s);
      main.setSize(200, 230);
      main.setVisible(true);  
   }
}
       
class InMemorySourceCompiler {
   protected String name;
   protected String source;
   protected Class compiledClass;
  
   public InMemorySourceCompiler(String name, String source) throws Exception {
      this.name = name;
      this.source = source;
      loadClass();
   }
 
   protected void loadClass() throws Exception {
      ClassPath cp = new ClassPath(System.getProperty("java.class.path"));
      OutputStream os = System.out;
      BatchEnvironment be = new BatchEnvironment(os, cp);
      be.flags = 0x41004;
      be.majorVersion = 45;
      be.minorVersion = 3;
      be.covFile = null;
      be.setCharacterEncoding(null);
 
      be.parseFile(new InMemorySourceClassFile(name+".java", source));
 
      ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
 
      be.flushErrors();
      Vector v = new Vector();
 
      for (Enumeration enum = be.getClasses(); enum.hasMoreElements();) {
         v.addElement(enum.nextElement());
      }
 
      for (int i=0; i<v.size(); i++) {
         ClassDeclaration cd = (ClassDeclaration) v.elementAt(i);
         Object object = cd.getClassDefinition(be);
 
         if (object instanceof SourceClass) {
            SourceClass sourceclass = (SourceClass) object;
            cd.setDefinition(sourceclass, 5);
            SourceClass sourceclass1 = (SourceClass) object;
            baos.reset();
            sourceclass.compile(baos);
         }
         else if (object instanceof BinaryClass) {
            BinaryClass binaryclass = (BinaryClass) object;
            binaryclass.write(be, baos);
         }
         byte[] b = baos.toByteArray();
 
         InMemorySourceCompilerClassLoader myClassLoader = new InMemorySourceCompilerClassLoader();
         compiledClass = myClassLoader.getClassFromBytes(name, b);
      }
   }
 
   public void executeMain() throws Exception {
      Method m = compiledClass.getMethod("main", new Class[]{ String[].class });
      m.invoke(null, new Object[]{null});
   }
 
   static class InMemorySourceCompilerClassLoader extends ClassLoader
   {
      public Class getClassFromBytes(String name, byte[] b) {
         return defineClass(name, b, 0, b.length);
      }
   }
}
 
class InMemorySourceClassFile extends ClassFile
{
   private String filename;
   private String text;
 
   public InMemorySourceClassFile(String filename, String text) {
      super(new File(filename));
      this.filename = filename;
      this.text = text;
   }
 
   public String getAbsoluteName() {
      return filename;
   }
 
   public boolean exists() {
      return true;
   }
 
   public InputStream getInputStream() {
      return new StringBufferInputStream(text);
   }
 
   public String getName() {
      return filename;
   }
 
   public String getPath() {
      return "";
   }
 
   public boolean isDirectory() {
      return false;
   }
 
   public boolean isZipped() {
      return false;
   }
  
   public long lastModified() {
      return new Date().getTime();
   }
 
   public long length() {
      return text.length();
   }
 
   public String toString() {
      return filename;
   }
}

Turn off copy/paste in a JTextArea

Main.java:

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   public Main() {
      JTextArea ta = new JTextArea();
      getContentPane().add(new JScrollPane(ta));
 
      ta.getInputMap().put(KeyStroke.getKeyStroke("control C"), "none");
      ta.getInputMap().put(KeyStroke.getKeyStroke("control V"), "none");
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(400, 400);
      main.setVisible(true);
   }
}

Force the JScrollPane to scroll to the next JTextField when I press the TAB-Key

There are three steps to this:

1. Listen for focus events coming from the components that you want to scroll to. (This works for most component classes, not just JTextField.)

2. In the event listener, find the location of the component that now has focus with getBounds().

3. Ask the scrolled component to make that location visible with scrollRectToVisible(). NOTE! The obvious thing to call scrollRectToVisible on is the JScrollPane, which will compile fine but won’t do what you want. You must call scrollRectToVisible on the object contained in viewport of the scrollpane.

This Forte-generated example shows how this works for a simple panel containing a number of JTextFields. Notice that scrollRectToVisible is called on the JPanel containing the text fields.

TestFocus.java:

public class TestFocus extends javax.swing.JFrame {
 
    /** Creates new form TestFocus */
    public TestFocus() {
        initComponents();
    }
 
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {
        scrollPane = new javax.swing.JScrollPane();
        panel = new javax.swing.JPanel();
        jTextField1 = new javax.swing.JTextField();
        jTextField2 = new javax.swing.JTextField();
        jTextField3 = new javax.swing.JTextField();
        jTextField4 = new javax.swing.JTextField();
         
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });
        
        scrollPane.setPreferredSize(new java.awt.Dimension(120, 80));
        panel.setLayout(new java.awt.GridLayout(0, 1, 0, 15));
        
        jTextField1.setFont(new java.awt.Font("Dialog", 0, 18));
        jTextField1.setText("jTextField1");
        jTextField1.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                jTextFieldFocusGained(evt);
            }
        });
         
        panel.add(jTextField1);
        
        jTextField2.setFont(new java.awt.Font("Dialog", 0, 18));
        jTextField2.setText("jTextField2");
        jTextField2.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                jTextFieldFocusGained(evt);
            }
        });
        
        panel.add(jTextField2);
        
        jTextField3.setFont(new java.awt.Font("Dialog", 0, 18));
        jTextField3.setText("jTextField3");
        jTextField3.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                jTextFieldFocusGained(evt);
            }
        });
        
        panel.add(jTextField3);
        
        jTextField4.setFont(new java.awt.Font("Dialog", 0, 18));
        jTextField4.setText("jTextField4");
        jTextField4.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                jTextFieldFocusGained(evt);
            }
        });
        
        panel.add(jTextField4);
        
        scrollPane.setViewportView(panel);
        
        getContentPane().add(scrollPane, java.awt.BorderLayout.CENTER);
        
        pack();
    }
 
    private void jTextFieldFocusGained(java.awt.event.FocusEvent evt) {
        java.awt.Component focusedComponent = evt.getComponent();
        panel.scrollRectToVisible(focusedComponent.getBounds(null));
        repaint();
    }
 
    /** Exit the Application */
    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }
 
    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        new TestFocus().show();
    }
 
    // Variables declaration - do not modify
    private javax.swing.JScrollPane scrollPane;
    private javax.swing.JPanel panel;
    private javax.swing.JTextField jTextField1;
    private javax.swing.JTextField jTextField2;
    private javax.swing.JTextField jTextField3;
    private javax.swing.JTextField jTextField4;
    // End of variables declaration

}

If your panel of components contains a JTextArea, or another JTextComponent subclass, then be aware that those components will absorb TABs into themselves instead of allowing the TAB to change focus. You can disable this behavior by creating a subclass that overrides isManagingFocus() to always return false.

Binding a control key to a JTextArea component

In the following example, the CTRL-L key is mapped to an Action when pressed in the JTextArea.

Main.java:

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   public Main() {
      JTextArea ta = new JTextArea();
      getContentPane().add(new JScrollPane(ta));
 
      Action gotoLineAction = new AbstractAction("gotoline") {
         public void actionPerformed(ActionEvent ae) {
            String value = JOptionPane.showInputDialog("Goto line no");
            System.out.println("Include functionality here to goto line " + value); 
         }
      };
 
      ta.getInputMap().put(KeyStroke.getKeyStroke("control L"), "gotoline");
      ta.getActionMap().put(gotoLineAction.getValue(Action.NAME), gotoLineAction);
  
      ta.setText("Press CTRL-L!");
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(400, 400);
      main.setVisible(true);
   }
}