Creating a sorted JList

This example shows you a method sortList that gets the JList data, puts them in an array, sorts them using Arrays.sort and updates the list model:

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
  
public class Main extends JFrame {
 
   public Main() {
      getContentPane().setLayout(new BorderLayout());
 
      final DefaultListModel listModel = new DefaultListModel();   
 
      // populate listmodel
      Random r = new Random();
      for (int i=0; i<50; i++) {
         listModel.addElement("list item # " + (Math.abs(r.nextInt()) % 100));
      }
 
      final JList list = new JList(listModel); 
 
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(list));    
      JButton sortButton = new JButton("Sort");
      sortButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            sortList(list);
         }
      });
      getContentPane().add(BorderLayout.SOUTH, sortButton);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      pack();
   }
 
   public void sortList(JList list) {
      ListModel model = list.getModel();
 
      int n = model.getSize();
      String[] data = new String[n]; 
 
      for (int i=0; i<n; i++) { 
         data[i] = (String) model.getElementAt(i); 
      }
 
      Arrays.sort(data); 
 
      list.setListData(data); 
   }
   
   public static void main(String[] args) {
      (new Main()).show();
   }
}

Creating a JMenuItem with an image

Two constructors of JMenuItem take an Icon as parameters. Try the following example with these animated! GIFs:

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
   
public class Main extends JFrame {
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("menu");
      JMenuItem menuItem1 = new JMenuItem("male", new ImageIcon("male.gif"));
      JMenuItem menuItem2 = new JMenuItem("female", new ImageIcon("female.gif"));
      menu.add(menuItem1);
      menu.add(menuItem2);
      menuBar.add(menu);
 
      this.setJMenuBar(menuBar); 
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      setSize(400, 400);
   }
 
   public static void main(String[] args) {
      (new Main()).show();
   }
}

Changing the orientation of a JTextField, 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 {
      JTextField tf = new JTextField();
      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));

Creating a JLabel with the icon on top and text below

Here’s a complete example:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   JLabel label;
 
   public Main() {
      label = new JLabel("The Logo", new ImageIcon("d:\ESUSLOGO.gif"), 

SwingConstants.CENTER);
      label.setVerticalTextPosition(SwingConstants.BOTTOM);
      label.setHorizontalTextPosition(SwingConstants.CENTER);
      getContentPane().add(BorderLayout.CENTER, label);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      setSize(300, 200);
   }
  
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
   }
}

Preventing the user from renaming files/directories in a JFileChooser

This is a hard task. I sat 3 hours to solve the problem for Jbuzzer. I do not know, if I solved the problem in a good way but it works.

Problem

The problem is, that deep inside of the UI of the JFileChooser – at the level of concrete implementation of the Look & Feel – the internal javax.swing.JList is instantiated without even keeping a member handle to it. It is done within a method that instantiates it, configures it (e.g.: with mouse listeners), adds it in a JPanel and returns that one.

The java jdk source code (1.4)

public class MetalFileChooserUI extends BasicFileChooserUI{
   private JPanel listViewPanel;
 
   public void installComponents(JFileChooser fc) {
      ...
      listViewPanel = createList(fc);
      ...
   }
 
   // A big don't: Hardcoded listeners 
   // in the UI implementation.
   protected JPanel createList(JFileChooser fc) {
      list = new JList() { <anonymous initialisation >};
      ...
      <b>list.addMouseListener(createSingleClickListener(fc,list));</b>
      ...
   }

   private MouseListener reateSingleClickListener(JFileChooser fc, JList list) 
   {
      return new SingleClickListener(list);
   }
 
   protected class SingleClickListener extends MouseAdapter {
      JList list;
      public void mouseClicked(MouseEvent e) {
         if (SwingUtilities.isLeftMouseButton(e)) {
            if (e.getClickCount() == 1) {
               JFileChooser fc = getFileChooser();
               int index = list.locationToIndex(e.getPoint());
               if ((!fc.isMultiSelectionEnabled() 
                   || fc.getSelectedFiles().length <= 1)
                   && index >= 0 
                   && list.isSelectedIndex(index)
                   && getEditIndex() == index 
                   && editFile == null) {
                      editFileName(index);
                   } 
               else {
                   ...
               }
            }

Solution

  1. Create your JFileChooser.

  • Run a search for it’s Component child of type JList.
  • Get the MouseListener of this JList whose class name contains “SingleClick” (I did not search other plaf packages: they might do the same bad thing but add the MouseListener for editing the JList in another way. This bugfix will only work for javax.swing.plaf.metal).
  • Remove that MouseListener from the retrieved JList.

    Code

    import javax.swing.JList;
    import java.awt.Component;
    import java.awt.Container;
    import javax.swing.JFileChooser;
    import java.awt.event.MouseListener;
     
    public class somename {
       ...
       /**
       * <p>
       * Hack to get the {@link List} of the {@link JFileChooser} 
       * instance used for loading sounds: 
       * We have to remove the "Single Click" listener 
       * that allows renaming files.
       * </p>
       */
       private JList searchJList(Container fileChooser)
       {
          JList ret = null;
          // First check, wether i am a JList:
          if (fileChooser instanceof JList){
              ret = (JList)fileChooser;
          }
          // Ok, me not: let's ask the children.
          else {
             Component[] children = fileChooser.getComponents();
             for(int i=children.length-1;i>=0;i--) {
                if (children[i] instanceof Container) {
                   ret = searchJList((Container)children[i]);
                   if(ret != null) {
                      break;
                   }
                }
             }
          }
    
          return ret;
       }
     
       // Just demo code! 
       public static void main(String[]args){
          JFileChooser load = new JFileChooser("/home/user/...");
          JList list = searchJList(this.openDialog);
          if (list!=null) {
             String listenerClassName;
             MouseListener[] listeners = list.getMouseListeners();
             for (int i=0;i< listeners.length;i++) {
                listenerCName = listeners[i].getClass().getName();
                if(listenerCName.indexOf("SingleClick")!= -1) {      
                   list.removeMouseListener(mouseListeners[i]);
                   break;
                }
             }
          }
          // Show the file chooser.
       }
    }
    

    Further examinations of other L&F packages could require changes. This has only be tested with javax.swing.plaf.metal.

    See the working example in Jbuzzer, a small fun-application for mapping sounds to keystrokes: http://sourceforge.net/projects/jbuzzer/.

  • Creating a JTable with fixed columns

    You can call the following method:

       table.getTableHeader().setResizingAllowed(false);
    

    However, be aware that this will disable resizing for all columns, and will still resize the columns proportionally when resizing the container in which the JTable is hosted. To fix the size of one column, you have to think about what behavior you want and override the method sizeColumnsToFit().

    Main.java:

    import javax.swing.table.*;
    import java.awt.event.*;
    import javax.swing.*;
    import java.util.*;
    import java.awt.*;
     
    public class Main extends JFrame {
       public Main() {
          super("TableModel Demonstration");
     
          // create our own custom TableModel
          WineTableModel wineModel = new WineTableModel();
          JTable table = new JTable(wineModel);
     
          // add rows to our TableModel, each row is represented as a Wine object
          wineModel.addWine(new Wine("Chateau Meyney, St. Estephe", "1994", 18.75f, true));
          wineModel.addWine(new Wine("Chateau Montrose, St. Estephe", "1975", 54.25f, true));
          wineModel.addWine(new Wine("Chateau Gloria, St. Julien", "1993", 22.99f, false));
          wineModel.addWine(new Wine("Chateau Beychevelle, St. Julien", "1970", 61.63f, false));
          wineModel.addWine(new Wine("Chateau La Tour de Mons, Margeaux", "1975", 57.03f, true));
          wineModel.addWine(new Wine("Chateau Brane-Cantenac, Margeaux", "1978", 49.92f, false));
     
     
          // don't allow resizing columns
          table.getTableHeader().setResizingAllowed(false);
     
     
          // create the scroll pane and add the table to it. 
          JScrollPane scrollPane = new JScrollPane(table);
     
          // add the scroll pane to this window.
          getContentPane().add(scrollPane, BorderLayout.CENTER);
     
          addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                System.exit(0);
             }
          });
       }
     
       public static void main(String[] args) {
          Main main = new Main();
          main.pack();
          main.setVisible(true);
       }
    }
     
    // a simple object that holds data about a particular wine
    class Wine {
       private String  name;
       private String  vintage;
       private float   price;
       private boolean inStock;
     
       public Wine(String name, String vintage, float price, boolean inStock) {
          this.name = name;
          this.vintage = vintage;
          this.price = price;
          this.inStock = inStock;
       }
     
       public String getName()     { return name; }
       public String getVintage()  { return vintage; }
       public float  getPrice()    { return price; } 
       public boolean getInStock() { return inStock; }
     
       public String toString() { 
          return "[" + name + ", " + vintage + ", " + price + ", " + inStock + "]"; }
    }
     
    class WineTableModel extends AbstractTableModel {
       // holds the strings to be displayed in the column headers of our table
       final String[] columnNames = {"Name", "Vintage", "Price", "In stock?"};
     
       // holds the data types for all our columns
       final Class[] columnClasses = {String.class, String.class, Float.class, Boolean.class};
     
       // holds our data
       final Vector data = new Vector();
      
       // adds a row
       public void addWine(Wine w) {
          data.addElement(w);
          fireTableRowsInserted(data.size()-1, data.size()-1);
       }
     
       public int getColumnCount() {
          return columnNames.length;
       }
             
       public int getRowCount() {
          return data.size();
       }
     
       public String getColumnName(int col) {
          return columnNames[col];
       }
     
       public Class getColumnClass(int c) {
          return columnClasses1;
       }
     
       public Object getValueAt(int row, int col) {
          Wine wine = (Wine) data.elementAt(row);
          if (col == 0)      return wine.getName();
          else if (col == 1) return wine.getVintage();
          else if (col == 2) return new Float(wine.getPrice());
          else if (col == 3) return new Boolean(wine.getInStock());
          else return null;
       }
     
       public boolean isCellEditable(int row, int col) {
          return false;
       }
    }

    Creating a JTable with a multi-line header

    Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples1.html)



    MultiLineHeaderExample.java:

    import java.util.*;
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
      
    /**
     * @version 1.0 11/09/98
     */
    public class MultiLineHeaderExample extends JFrame {
      MultiLineHeaderExample() {
        super( "Multi-Line Header Example" );
     
        DefaultTableModel dm = new DefaultTableModel();
        dm.setDataVector(new Object[][]{{"a","b","c"},
                                        {"A","B","C"}},
                         new Object[]{"1stnalpha","2ndnbeta","3rdngamma"});
     
        JTable table = new JTable( dm );
        MultiLineHeaderRenderer renderer = new MultiLineHeaderRenderer();
        Enumeration enum = table.getColumnModel().getColumns();
        while (enum.hasMoreElements()) {
          ((TableColumn)enum.nextElement()).setHeaderRenderer(renderer);
        }   
        JScrollPane scroll = new JScrollPane( table );
        getContentPane().add( scroll );
        setSize( 400, 110 );
        setVisible(true);
      }
     
      public static void main(String[] args) {
        MultiLineHeaderExample frame = new MultiLineHeaderExample();
        frame.addWindowListener( new WindowAdapter() {
          public void windowClosing( WindowEvent e ) {
            System.exit(0);
          }
        });
      }
    }
    

    MultiLineHeaderRenderer.java:

    import java.io.*;
    import java.util.*;
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.table.*;
    
    
    /**
     * @version 1.0 11/09/98
     */
    public class MultiLineHeaderRenderer extends JList implements TableCellRenderer {
      public MultiLineHeaderRenderer() {
        setOpaque(true);
        setForeground(UIManager.getColor("TableHeader.foreground"));
        setBackground(UIManager.getColor("TableHeader.background"));
        setBorder(UIManager.getBorder("TableHeader.cellBorder"));
        ListCellRenderer renderer = getCellRenderer();
        ((JLabel)renderer).setHorizontalAlignment(JLabel.CENTER);
        setCellRenderer(renderer);
      }
     
      public Component getTableCellRendererComponent(JTable table, Object value,
                       boolean isSelected, boolean hasFocus, int row, int column) {
        setFont(table.getFont());
        String str = (value == null) ? "" : value.toString();
        BufferedReader br = new BufferedReader(new StringReader(str));
        String line;
        Vector v = new Vector();
        try {
          while ((line = br.readLine()) != null) {
            v.addElement(line);
          }
        } catch (IOException ex) {
          ex.printStackTrace();
        }
        setListData(v);
        return this;
      }
    }
    

    Preventing a particular JTable column from being edited

    Decide what column should not be editable using the method isCellEditable.
    This example allows you to modify any of the cells except the column Vintage.

    Main.java:

    import javax.swing.table.*;
    import java.awt.event.*;
    import javax.swing.*;
    import java.util.*;
    import java.awt.*;
     
    public class Main extends JFrame {
       public Main() {
          super("Color Row Demonstration");
      
          // create our own custom TableModel
          WineTableModel wineModel = new WineTableModel();
          JTable table = new JTable(wineModel);
      
          // add rows to our TableModel, each row is represented as a Wine object
          wineModel.addWine(new Wine("Chateau Meyney, St. Estephe", "1994", 18.75f, true));
          wineModel.addWine(new Wine("Chateau Montrose, St. Estephe", "1975", 54.25f, true));
          wineModel.addWine(new Wine("Chateau Gloria, St. Julien", "1993", 22.99f, false));
          wineModel.addWine(new Wine("Chateau Beychevelle, St. Julien", "1970", 61.63f, false));
          wineModel.addWine(new Wine("Chateau La Tour de Mons, Margeaux", "1975", 57.03f, true));
          wineModel.addWine(new Wine("Chateau Brane-Cantenac, Margeaux", "1978", 49.92f, false));
     
          // create the scroll pane and add the table to it. 
          JScrollPane scrollPane = new JScrollPane(table);
     
          // add the scroll pane to this window.
          getContentPane().add(scrollPane, BorderLayout.CENTER);
     
          addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                System.exit(0);
             }
          });
       }
     
       public static void main(String[] args) {
          Main main = new Main();
          main.pack();
          main.setVisible(true);
       }
    }
     
    // a simple object that holds data about a particular wine
    class Wine {
       private String  name;
       private String  vintage;
       private float   price;
       private boolean inStock;
     
       public Wine(String name, String vintage, float price, boolean inStock) {
          this.name = name;
          this.vintage = vintage;
          this.price = price;
          this.inStock = inStock;
       }
     
       public String getName()     { return name; }
       public String getVintage()  { return vintage; }
       public float  getPrice()    { return price; } 
       public boolean getInStock() { return inStock; }
     
       public void setName(String name)        { this.name = name; }
       public void setVintage(String vintage)  { this.vintage = vintage; }
       public void setPrice(float price)       { this.price = price; }
       public void setInStock(boolean inStock) { this.inStock = inStock; }
     
       public String toString() { 
          return "[" + name + ", " + vintage + ", " + price + ", " + inStock + "]"; }
    }
     
    class WineTableModel extends AbstractTableModel {
       // holds the strings to be displayed in the column headers of our table
       final String[] columnNames = {"Name", "Vintage", "Price", "In stock?"};
     
       // holds the data types for all our columns
       final Class[] columnClasses = {String.class, String.class, Float.class, Boolean.class};
     
       // holds our data
       final Vector data = new Vector();
      
       // adds a row
       public void addWine(Wine w) {
          data.addElement(w);
          fireTableRowsInserted(data.size()-1, data.size()-1);
       }
     
       public int getColumnCount() {
          return columnNames.length;
       }
             
       public int getRowCount() {
          return data.size();
       }
     
       public String getColumnName(int col) {
          return columnNames[col];
       }
     
       public Class getColumnClass(int c) {
          return columnClasses1;
       }
     
       public Object getValueAt(int row, int col) {
          Wine wine = (Wine) data.elementAt(row);
          if (col == 0)      return wine.getName();
          else if (col == 1) return wine.getVintage();
          else if (col == 2) return new Float(wine.getPrice());
          else if (col == 3) return new Boolean(wine.getInStock());
          else return null;
       }
     
       public void setValueAt(Object value, int row, int col) {
          Wine wine = (Wine) data.elementAt(row);
          if (col ==0)       wine.setName(""+value);
          else if (col == 1) wine.setVintage(""+value);
          else if (col == 2) wine.setPrice(new Float(""+value).floatValue());
          else if (col == 3) wine.setInStock(((Boolean) value).booleanValue());
       }
     
       public boolean isCellEditable(int row, int col) {
          if (col == 1) return false;
     
          return true;
       }
    }
    

    Creating a JTree without node icons

    Set the OpenIcon, ClosedIcon and LeafIcon to null in a DefaultTreeCellRenderer.

    Main.java:

    import javax.swing.*;
    import javax.swing.tree.*;
    import javax.swing.event.*;
    import java.awt.*;
    import java.net.*;
    import java.awt.event.*;
     
    public class Main extends JFrame
    {
       public Main() {
          DefaultMutableTreeNode root = createNodes();
          JTree tree = new JTree(root);
     
          DefaultTreeCellRenderer cr = new DefaultTreeCellRenderer();
          cr.setOpenIcon(null);
          cr.setClosedIcon(null);
          cr.setLeafIcon(null);
      
          tree.setCellRenderer(cr);
     
          getContentPane().add(new JScrollPane(tree));
     
          addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent we) {
                System.exit(0);
             }
          });
       }
     
       public static DefaultMutableTreeNode createNodes() {
          DefaultMutableTreeNode root = new DefaultMutableTreeNode("Java");
          
          DefaultMutableTreeNode j2se = new DefaultMutableTreeNode("J2SE");
          DefaultMutableTreeNode j2ee = new DefaultMutableTreeNode("J2EE");
          DefaultMutableTreeNode j2me = new DefaultMutableTreeNode("J2ME");
     
          j2se.add(new DefaultMutableTreeNode("http://java.sun.com/j2se/"));
          j2ee.add(new DefaultMutableTreeNode("http://java.sun.com/j2ee/"));
          j2me.add(new DefaultMutableTreeNode("http://java.sun.com/j2me/"));
     
          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);
       }
    }
    

    Creating an underlined JLabel without using HTML

    Main.java:

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
     
    public class Main extends JFrame
    {
       public Main() {
          getContentPane().setLayout(new GridLayout(1, 2));
          JPanel panel1 = new JPanel();
          panel1.setLayout(new GridLayout(5, 1));
          panel1.add(new JLabel(&quot;JLabel/icon/LEFT&quot;, 
                               new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.LEFT));
          panel1.add(new JLabel(&quot;JLabel/icon/CENTER&quot;, 
                               new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.CENTER));
          panel1.add(new JLabel(&quot;JLabel/icon/RIGHT&quot;, 
                               new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.RIGHT));
          panel1.add(new JLabel(&quot;JLabel/icon/LEADING&quot;, 
                               new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.LEADING));
          panel1.add(new JLabel(&quot;JLabel/icon/TRAILING&quot;, 
                               new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.TRAILING));
     
          getContentPane().add(new JScrollPane(panel1));
     
          JPanel panel2 = new JPanel();
          panel2.setLayout(new GridLayout(5, 1));
          panel2.add(new UnderlinedJLabel(&quot;JLabel/icon/LEFT&quot;, 
                                          new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.LEFT));
          panel2.add(new UnderlinedJLabel(&quot;JLabel/icon/CENTER&quot;, 
                                          new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.CENTER));
          panel2.add(new UnderlinedJLabel(&quot;JLabel/icon/RIGHT&quot;, 
                                          new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.RIGHT));
          panel2.add(new UnderlinedJLabel(&quot;JLabel/icon/LEADING&quot;, 
                                          new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.LEADING));
          panel2.add(new UnderlinedJLabel(&quot;JLabel/icon/TRAILING&quot;, 
                                          new ImageIcon(&quot;tiffIcon.gif&quot;), SwingConstants.TRAILING));
     
          getContentPane().add(new JScrollPane(panel2));
     
          addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent we) {
                System.exit(1);
             }
          });
       }
     
       public static void main(String []args) {
          Main main = new Main();
          main.setSize(300, 150);
          main.setVisible(true);   
       }
    }
     
    class UnderlinedJLabel extends JLabel
    {
       public UnderlinedJLabel() {
       }
     
       public UnderlinedJLabel(Icon image) {
          super(image);
       }
     
       public UnderlinedJLabel(Icon image, int horizontalAlignment) {
          super(image, horizontalAlignment);
       }
     
       public UnderlinedJLabel(String text) {
          super(text);
       }
    
       public UnderlinedJLabel(String text, Icon icon, int horizontalAlignment) {
          super(text, icon, horizontalAlignment);
       }
     
       public UnderlinedJLabel(String text, int horizontalAlignment) {
          super(text, horizontalAlignment);
       }
     
       public void paint(Graphics g) {
          super.paint(g);
          underline(g);
       }
     
       protected void underline(Graphics g) {
          Insets insets = getInsets();
          FontMetrics fm = g.getFontMetrics();
          Rectangle textR = new Rectangle();
          Rectangle viewR = new Rectangle(
                                      insets.left, 
                                      insets.top, 
                                      getWidth() - (insets.right + insets.left), 
                                      getHeight() - (insets.bottom + insets.top));
      
          // compute and return location of the icons origin,
          // the location of the text baseline, and a possibly clipped
          // version of the compound label string.  Locations are computed 
          // relative to the viewR rectangle.
          String text = SwingUtilities.layoutCompoundLabel(
                             this,                        // this JLabel
                             fm,                          // current FontMetrics
                             getText(),                   // text
                             getIcon(),                   // icon
                             getVerticalAlignment(),      
                             getHorizontalAlignment(),
                             getVerticalTextPosition(),
                             getHorizontalTextPosition(), 
                             viewR,                       
                             new Rectangle(),             // don't care about icon rectangle
                             textR,                       // resulting text locations
                             getText() == null ? 0 : 
                                ((Integer)UIManager.get(&quot;Button.textIconGap&quot;)).intValue());
     
          // draw line
          int textShiftOffset = ((Integer) UIManager.get(&quot;Button.textShiftOffset&quot;)).intValue();
          g.fillRect(textR.x +
                     textShiftOffset - 4,
                     textR.y + fm.getAscent() + textShiftOffset + 2,
                     textR.width, 
                     1);
       }
    }