Posterizing an image in Swing


Will reduce the number of colors used!

Main.java:

import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame {
   private boolean firstTime = true;
   private BufferedImage sourceBi;
   private BufferedImage destBi;
  
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      }); 
   } 
 
   public void paint(Graphics graphics) {
      Graphics2D g2d = (Graphics2D) graphics;
  
      if (firstTime) {
         Image img = new javax.swing.ImageIcon("djkrush.jpg").getImage(); 
         sourceBi = toBufferedImage(img);
         destBi = new BufferedImage(sourceBi.getWidth(), sourceBi.getHeight(), 
                                    BufferedImage.TYPE_INT_RGB);
         setSize(sourceBi.getWidth(), sourceBi.getHeight()*2);
 
         short[] posterize = new short[256];
         for(int i=0; i<256; i++) {
            posterize[i] = (short) (i - (i % 32));
         }
  
         ShortLookupTable slt = new ShortLookupTable(0, posterize);
         LookupOp op = new LookupOp(slt, null);
         destBi = op.filter(sourceBi, null);
 
         firstTime = false;
      }
 
      g2d.drawImage(sourceBi, 0, 0, this);
      g2d.drawImage(destBi, 0, sourceBi.getHeight(), this);
   }
 
   public static BufferedImage toBufferedImage(Image image) {
      BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), 
                                           BufferedImage.TYPE_INT_RGB); 
 
      // copy the original image
      Graphics g = bi.createGraphics();
    
      g.drawImage(image, 0, 0, null);
      g.dispose();
 
      return bi;
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
      main.setSize(300, 150);
   }
}

Example of an ImageIO transcoder

A transcoder is responsible for converting one particular image type to another and is designed in such a way that metadata specific to that image type is not lost.

The following example outputs all transcoders that are defined for converting gif to jpg. Currently there are none, but since ImageIO is pluggable, third-party transcoders should become available soon.

Main.java:

import javax.imageio.stream.*;
import javax.imageio.*;
import java.util.*;
  
public class Main
{
   public static void main(String []args) {
      Iterator readers = ImageIO.getImageReadersByFormatName("gif");
      ImageReader reader = (ImageReader) readers.next();
 
      Iterator writers = ImageIO.getImageWritersByFormatName("jpg");
      ImageWriter writer = (ImageWriter) writers.next();
 
      Iterator transcoders = ImageIO.getImageTranscoders(reader, writer);
      while (transcoders.hasNext()) {
         ImageTranscoder tc = (ImageTranscoder) transcoders.next();
         System.out.println(tc);
      }
   }
}

Having the Enter key activate the default button on a JDialog

Use getRootPane() and setDefaultButton to make a button on a JDialog respond to the ‘enter’ key. I’ve included code that allows which ever button has focus to be the default.

   ... begin snippet ...
   JButton ok = new JButton("OK");
   JButton cancel = new JButton("CANCEL");
 
   //kicks off when component gains focus
   ok.addFocusListener(new buttonfocusEventHandler());
 
   //kicks off when component gains focus
   cancel.addFocusListener(new buttonfocusEventHandler()); 
 
   ... end snippet ...

   class buttonfocusEventHandler extends FocusAdapter {

      /** Checks buttons on dialog for focus
       * and makes that button the default
       * 
       * @param evt Holds event
       */
      public void focusGained(FocusEvent evt) {
 
         JButton button = (JButton) evt.getSource();
           
         if (button == ok) {
            JRootPane root = getRootPane();
            root.setDefaultButton(button);
         } //end if
            
         if (button == cancel){
            JRootPane root = getRootPane();
            root.setDefaultButton(button);
         } // end if
      }             
}  //  end buttonfocusEventHandler

Creating a tooltip for the JFrame’s title bar

You can’t, with pure Java. JFrame extends from Frame, a heavy-weight component. The JFrame title bar is controlled in by native peers. For example, in Windows, to ensure a consistent look and feel, you can set title bar fonts and window colors via the Control Panel Display.

Adding a JButton inside my JSplitPane divider

Main.java:

import javax.swing.plaf.basic.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.awt.*;
 
public class Main extends JFrame
{
   JSplitPane splitPane;
  
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
                                 new JPanel(), new JPanel());
      splitPane.setDividerSize(20);
  
      JButton button = new JButton("Exit!");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            System.exit(0);
         }
      });
 
      setJMenuBar(getMainMenuBar());
 
      splitPane.setUI(new ButtonDividerUI(button));
 
      getContentPane().add(splitPane);
 
      addComponentListener(new ComponentAdapter() {
         public void componentShown(ComponentEvent event) {
            splitPane.setDividerLocation(0.5);  
                
            removeComponentListener(this);
         }
      });
   }
 
   public JMenuBar getMainMenuBar() {
      JMenuBar mainBar = new JMenuBar();
      JMenu menu = new JMenu("JSplitPane");
      JMenuItem item1 = new JMenuItem("HORIZONTAL_SPLIT");
      JMenuItem item2 = new JMenuItem("VERTICAL_SPLIT");
      menu.add(item1);
      menu.add(item2);
      mainBar.add(menu);
 
      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);
         }
      });
 
      return mainBar;
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(300, 300);
      main.setVisible(true);
   }
}
 
class ButtonDividerUI extends BasicSplitPaneUI
{
   protected JButton button;
 
   public ButtonDividerUI(JButton button) {
      this.button = button;
   }
 
   public BasicSplitPaneDivider createDefaultDivider() {
      BasicSplitPaneDivider divider = new BasicSplitPaneDivider(this) {
         public int getDividerSize() { 
            if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
               return button.getPreferredSize().width; 
            }
            return button.getPreferredSize().height;
         }
      };
 
      divider.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      divider.add(button);
 
      return divider;
   }
}

Adding a close (X) button to tabs in a JTabbedPane

Here’s a quick hack.

Main.java:

import javax.swing.plaf.metal.*;
import javax.swing.plaf.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
 
public class Main extends JFrame implements ActionListener {
   JTabbedPane tabbedPane;
   int ntabs = 0;
 
   public Main() {
      getContentPane().setLayout(new BorderLayout());
      tabbedPane = new JTabbedPane();
      tabbedPane.setUI(new CustomTabbedPaneUI());
      createTab();
 
      getContentPane().add(BorderLayout.CENTER, tabbedPane);
      setJMenuBar(createMenuBar());
  
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
   
      setTitle("JTabbedPane Orientation Demonstration");
      setSize(new Dimension(400, 400));
   }
 
   protected JMenuBar createMenuBar() {
      JMenuBar menuBar = new JMenuBar();
 
      JMenu menu1 = new JMenu("JTabbedPane");
      JMenuItem menuItem1 = new JMenuItem("Create new tab");
      menuItem1.addActionListener(this);
      menu1.add(menuItem1);
      JMenu menu2 = new JMenu("Change orientation");
      JMenuItem menuItem2 = new JMenuItem("TOP");
      menuItem2.addActionListener(this);
      menu2.add(menuItem2);
      JMenuItem menuItem3 = new JMenuItem("BOTTOM");
      menuItem3.addActionListener(this);
      menu2.add(menuItem3);
      JMenuItem menuItem4 = new JMenuItem("LEFT");
      menuItem4.addActionListener(this);
      menu2.add(menuItem4);
      JMenuItem menuItem5 = new JMenuItem("RIGHT");
      menuItem5.addActionListener(this);
      menu2.add(menuItem5);
      menuBar.add(menu1);
      menuBar.add(menu2);
 
      return menuBar;
   }
  
   public void actionPerformed(ActionEvent e) {
      if (e.getActionCommand().equals("Create new tab")) {
         createTab();
      }
      else if (e.getActionCommand().equals("TOP")) {
         tabbedPane.setTabPlacement(JTabbedPane.TOP);
      }
      else if (e.getActionCommand().equals("BOTTOM")) {
         tabbedPane.setTabPlacement(JTabbedPane.BOTTOM);
      }
      else if (e.getActionCommand().equals("LEFT")) {
         tabbedPane.setTabPlacement(JTabbedPane.LEFT);
      }
      else if (e.getActionCommand().equals("RIGHT")) {
         tabbedPane.setTabPlacement(JTabbedPane.RIGHT);
      }
   }
 
   protected void createTab() {
      ntabs++;
      tabbedPane.addTab("Tab #" + ntabs + "   ", new JLabel("Tab #" + ntabs));
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
}
 
class CustomTabbedPaneUI extends MetalTabbedPaneUI 
{
   Rectangle xRect;
 
   protected void installListeners() {
      super.installListeners();
      tabPane.addMouseListener(new MyMouseHandler());
   }
 
   protected void paintTab(Graphics g, int tabPlacement,
                           Rectangle[] rects, int tabIndex, 
                           Rectangle iconRect, Rectangle textRect) {
      super.paintTab(g, tabPlacement, rects, tabIndex, iconRect, textRect);
 
      Font f = g.getFont();
      g.setFont(new Font("Courier", Font.BOLD, 10));
      FontMetrics fm = g.getFontMetrics(g.getFont());
      int charWidth = fm.charWidth('x');
      int maxAscent = fm.getMaxAscent();
      g.drawString("x", textRect.x + textRect.width - 3, textRect.y + textRect.height - 3);
      g.drawRect(textRect.x+textRect.width-5,
                 textRect.y+textRect.height-maxAscent, charWidth+2, maxAscent-1);
      xRect = new Rectangle(textRect.x+textRect.width-5, 
                 textRect.y+textRect.height-maxAscent, charWidth+2, maxAscent-1);
      g.setFont(f);
    }
 
    public class MyMouseHandler extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            System.out.println(e);
            if (xRect.contains(e.getPoint())) {
               JTabbedPane tabPane = (JTabbedPane)e.getSource();
               int tabIndex = tabForCoordinate(tabPane, e.getX(), e.getY());
               tabPane.remove(tabIndex);
            }
        }
    } 
}

Preventing a JInternalFrame from being moved

You can subclass the protected class BorderListener that is defined in BasicInternalFrameUI and provide an empty implementation for mouseDragged. In the following example, it is done so for the Metal look and feel.

Main.java:

import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.*;
import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.net.*;
 
public class Main extends JFrame {
   JDesktopPane desktop;
   int nframes = 0;
 
   JMenu internalFrameMenu;
 
   public Main() {
      desktop = new JDesktopPane(); 
      setContentPane(desktop);
      setJMenuBar(createMenuBar());
      createInternalFrame(); 
   }
 
   protected JMenuBar createMenuBar() {
      JMenuBar menuBar = new JMenuBar();
 
      JMenu createMenu = new JMenu("Create");
      createMenu.setMnemonic(KeyEvent.VK_C);
      JMenuItem newMenuItem = new JMenuItem("New");
      newMenuItem.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            createInternalFrame();
         }
      }); 
      newMenuItem.setMnemonic(KeyEvent.VK_N);
      createMenu.add(newMenuItem);
      menuBar.add(createMenu);
  
      return menuBar;
   }
 
   protected void createInternalFrame() {
      nframes++;
      String title = "JInternalFrame #" + nframes;
      JInternalFrame frame = new JInternalFrame(title,
         true,    // resizable
         true,    // closable
         true,    // maximizable
         true);   // iconifiable
      frame.setVisible(true); 
      desktop.add(frame);
      frame.setSize(200, 200);
      frame.setLocation(30*nframes, 30*nframes);
      try {
         frame.setSelected(true);
      } catch (java.beans.PropertyVetoException e) {}
 
      frame.setUI(new MyMetalInternalFrameUI(frame));
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(500, 300);
      main.setVisible(true);
   }
}
 
class MyMetalInternalFrameUI extends MetalInternalFrameUI {
   public MyMetalInternalFrameUI(JInternalFrame b) { super(b); }
 
   protected MouseInputAdapter createBorderListener(JInternalFrame w) {
      return new MyBorderListener();
   }
 
   protected class MyBorderListener extends BasicInternalFrameUI.BorderListener {
      public void mouseDragged(MouseEvent e) {  }
   }
}

Putting a Image on a JButton

Check out the API! You’ll see that there is a constructor taking an Icon object as parameter. Here’s an example showing two buttons with the following animated gifs on them:

Main.java:

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
  
public class Main extends JFrame implements ActionListener {
   JList list; 
 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      JButton mbutton = new JButton("female", new ImageIcon("male.gif"));
      JButton fbutton = new JButton("male", new ImageIcon("female.gif"));
      mbutton.addActionListener(this);
      fbutton.addActionListener(this);
      getContentPane().add(mbutton);
      getContentPane().add(fbutton);
  
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      pack();
   }
 
   public void actionPerformed(ActionEvent ae) {
      System.out.println("Your pressed the " + ae.getActionCommand() + " button");
   }
   
   public static void main(String[] args) {
      (new Main()).show();
   }
}

Changing the color of the check of my JCheckBox

This is all tied into the particular L and F implementation of the JCheckBox. The check color is always black (or gray, if disabled). If your background happens to be black, you can’t see the check. This is a bug (http://developer.java.sun.com/developer/bugParade/bugs/4449413.html) in progress.

This example shows you a bit of a workaround by implementing another version of CheckBoxIcon, the UI class used to paint the rectangle and the checkmark. I defined a couple new properties: MyCheckBox.checkBackground, MyCheckBox.checkClickBackground, MyCheckBox.checkForeground, MyCheckBox.checkDisabled. They all take a Color object.

Main.java:

import javax.swing.plaf.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.io.*; 
  
public class Main extends JFrame
{
   public Main() throws Exception {
      UIManager.put("CheckBox.icon", new MyCheckBoxIcon());
 
      UIManager.put("MyCheckBox.checkBackground", Color.orange); 
      UIManager.put("MyCheckBox.checkClickBackground", Color.orange); 
      UIManager.put("MyCheckBox.checkForeground", Color.red); 
      UIManager.put("MyCheckBox.checkDisabled", Color.gray); 
 
      JCheckBox cbox = new JCheckBox("This checkbox has a colored check");

      getContentPane().setLayout(null); 
      getContentPane().add(cbox);
      cbox.setBounds(10, 20, 250, 30);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String args[]) throws Exception {
      Main main = new Main();
      main.setSize(300, 100);
      main.setVisible(true);
   }
}
  
class MyCheckBoxIcon implements Icon, UIResource, Serializable {
   protected int getControlSize() { return 13; }
 
   public void paintIcon(Component c, Graphics g, int x, int y) {
      JCheckBox cb = (JCheckBox)c;
      ButtonModel model = cb.getModel();
      int controlSize = getControlSize();
 
      boolean drawCheck = model.isSelected();
 
      if (model.isEnabled()) {
         if (model.isPressed() && model.isArmed()) {
            g.setColor(UIManager.getColor("MyCheckBox.checkClickBackground"));
	    g.fillRect( x, y, controlSize-1, controlSize-1);
         } else {
            g.setColor(UIManager.getColor("MyCheckBox.checkBackground"));
            g.fillRect( x, y, controlSize-1, controlSize-1);
         }
 
         g.setColor(UIManager.getColor("MyCheckBox.checkForeground"));
 
      } else {
         g.setColor(UIManager.getColor("MyCheckBox.checkDisabled"));
         g.drawRect( x, y, controlSize-1, controlSize-1);
      }
 
      if (model.isSelected()) {
         drawCheck(c, g, x, y);
      }
   }
 
   protected void drawCheck(Component c, Graphics g, int x, int y) {
      int controlSize = getControlSize();
      g.fillRect( x+3, y+5, 2, controlSize-8 );
      g.drawLine( x+(controlSize-4), y+3, x+5, y+(controlSize-6) );
      g.drawLine( x+(controlSize-4), y+4, x+5, y+(controlSize-5) );
   }
 
   public int getIconWidth() {
      return getControlSize();
   }
       
   public int getIconHeight() {
      return getControlSize();
   }
 }

Refreshing the contents of a JList

JListExample.java:

 
// Created with JBuilder (c) Philip Craiger
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 
/**
 * Title:        A JList Programming Example
 * Description:
 * Copyright:    Copyright (c) 2001
 * Company:
 * @author Dr. Philip Craiger
 * @version 1.0
 */
 
public class JListExample extends JFrame {
  private JButton btnMove = new JButton();
  private JButton bthRemove = new JButton();
 
  // Model View Controller: We change contents of the JList through
  // manipulation of a MODEL, not the actual JList.
  
 
  private DefaultListModel model_1 = new DefaultListModel();
  private DefaultListModel model_2 = new DefaultListModel();
 
  private JList jList1 = new JList(model_2);
  private JList jList2 = new JList(model_1);
  
  // JLists do not scroll by default.  We need to add them to
  // an encompassing JScrollPane
  private JScrollPane jScrollPane1 = new JScrollPane();
  private JScrollPane jScrollPane2 = new JScrollPane();
 
  public JListExample() {     // our constructor
    super("A JList Example"); // call to super constructor
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
 
  public static void main(String[] args) {
    JListExample foo = new JListExample();
    foo.setSize(new Dimension(450,200));
    foo.show();
  }
 
  private void jbInit() throws Exception {
 
  // Note we are adding and removing JList items from the MODEL
  // NOT directly from the JList.  Because JList is associated with the
  // model, the JList contents are updated automatically
 
    model_1.addElement("Java");
    model_1.addElement("Visual Basic");
    model_1.addElement("C++");
    model_1.addElement("C");
    model_1.addElement("Common LISP");
    model_1.addElement("Fortran");
    model_1.addElement("Pascal");
    model_1.addElement("Python");
    this.getContentPane().setLayout(null);
 
    btnMove.setText("Move >>");
    btnMove.setBounds(new Rectangle(150, 35, 98, 36));
    btnMove.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        btnMove_actionPerformed(e);
      }
    });
 
    bthRemove.setText("<< Remove");
    bthRemove.setBounds(new Rectangle(152, 87, 97, 36));
    bthRemove.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        bthRemove_actionPerformed(e);
      }
    });
 
    jScrollPane1.setBounds(new Rectangle(286, 15, 109, 133));
    jScrollPane2.setBounds(new Rectangle(14, 15, 106, 136));
 
    // Allow user to select a single item from JList
    jList1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    jList2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 
    this.getContentPane().add(jScrollPane2, null);
    jScrollPane2.getViewport().add(jList2, null); // Must add JList
    this.getContentPane().add(jScrollPane1, null); // to a JScrollPane
    this.getContentPane().add(btnMove, null);
    this.getContentPane().add(bthRemove, null);
    jScrollPane1.getViewport().add(jList1, null); // JList to JScrollPane
    jList2.setSelectedIndex(0);
  }
 
  void btnMove_actionPerformed(ActionEvent e) {
    model_2.addElement(jList2.getSelectedValue());  // change the MODEL
    model_1.removeElement(jList2.getSelectedValue());  // change the MODEL
    jList2.setSelectedIndex(0);       // Highlight first item in JList
  }
 
  void bthRemove_actionPerformed(ActionEvent e) {
    model_1.addElement(jList1.getSelectedValue());  // change the MODEL
    model_2.removeElement(jList1.getSelectedValue()); // change the MODEL
    jList2.setSelectedIndex(0);       // Highlight first item in JList
  }
}