Showing posts with label swing. Show all posts
Showing posts with label swing. Show all posts

Saturday, June 29, 2013

Java 7 Swing: Creating Translucent and Shaped Windows

Java 7 Swing supports windows with transparency and non-rectangular shapes.

The following screenshot shows a circular window created with 75% opacity.

You can create a translucent window by altering its opacity using the setOpacity method on a JFrame. Note that you can only create translucent windows if the underlying operating system supports them. Also, ensure that the window is undecorated by calling setUndecorated(true).

To change the shape of the window, call the setShape method inside the componentResized method, so that if the window is resized, the shape is recalculated as well.

Sample code to create a translucent, circular window is shown below:

import java.awt.Color;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Ellipse2D;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TranslucentCircularFrame extends JFrame {

  /**
   * Creates a frame containing a text area and a button. The frame has a
   * circular shape and a 75% opacity.
   */
  public TranslucentCircularFrame() {
    super("Translucent Circular Frame");
    setLayout(new GridBagLayout());
    final JTextArea textArea = new JTextArea(3, 50);
    textArea.setBackground(Color.GREEN);
    add(textArea);
    setUndecorated(true);

    // set the window's shape in the componentResized method, so
    // that if the window is resized, the shape will be recalculated
    addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        setShape(new Ellipse2D.Double(0, 0, getWidth(), getHeight()));
      }
    });

    // make the window translucent
    setOpacity(0.75f);

    setLocationRelativeTo(null);
    setSize(250, 250);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
  }

  public static void main(String[] args) {

    // Create the GUI on the event-dispatching thread
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        GraphicsEnvironment ge = GraphicsEnvironment
            .getLocalGraphicsEnvironment();

        // check if the OS supports translucency
        if (ge.getDefaultScreenDevice().isWindowTranslucencySupported(
            GraphicsDevice.WindowTranslucency.TRANSLUCENT)) {
          new TranslucentCircularFrame();
        }
      }
    });
  }
}

Saturday, January 08, 2011

A Paginated JList

If you have a large JList and don't want to scroll through it, it might be a better idea to "paginate" it i.e. display the list in "pages" of a few rows at a time and allow users to flip back and forth between them. To do this, I have written a Java Swing component called PaginatedList, which looks like this:

You pass in a JList and specify a page size (the page size is 10 in this example) and it returns a PaginatedList which you can add onto another JComponent as normal. The code is shown below:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListModel;


/**
 * A paginated JList. Only displays a specific number of rows
 * and allows you to page back and forth through the list.
 * with the help of a toolbar.
 */
public class PaginatedList extends JPanel {

  private final int pageSize;
  private final JList list;
  private final ListModel model;
  private final int lastPageNum;
  private int currPageNum;
  private JLabel countLabel ;
  private JButton first, prev, next, last;

  /**
   * @param list the source list
   * @param pageSize the number of rows visible
   */
  public PaginatedList(JList list, int pageSize) {
      super();
      this.pageSize = pageSize;
      this.list = list;
      this.model = list.getModel();

      //work out how many pages there are
      this.lastPageNum = model.getSize() / pageSize +
                        (model.getSize() % pageSize != 0 ? 1 : 0);
      this.currPageNum = lastPageNum > 0 ? 1 : 0;

      setLayout(new BorderLayout());
      countLabel = new JLabel() ;
      add(countLabel, BorderLayout.NORTH);
      add(list, BorderLayout.CENTER);
      add(createControls(), BorderLayout.SOUTH);
      updatePage();
  }

  private JPanel createControls() {
      first = new JButton(new AbstractAction("<<") {
          public void actionPerformed(ActionEvent e) {
              currPageNum = 1;
              updatePage();
          }
      });

      prev = new JButton(new AbstractAction("<") {
          public void actionPerformed(ActionEvent e) {
              if (--currPageNum <= 0)
                  currPageNum = 1;
              updatePage();
          }
      });

      next = new JButton(new AbstractAction(">") {
          public void actionPerformed(ActionEvent e) {
              if (++currPageNum > lastPageNum)
                  currPageNum = lastPageNum;
              updatePage();

          }
      });

      last = new JButton(new AbstractAction(">>") {
          public void actionPerformed(ActionEvent e) {
              currPageNum = lastPageNum;
              updatePage();
          }
      });

      JPanel bar = new JPanel(new GridLayout(1, 4));
      bar.add(first);
      bar.add(prev);
      bar.add(next);
      bar.add(last);
      return bar;
  }

  private void updatePage() {

      //replace the list's model with a new model containing
      //only the entries in the current page.
      if(model.getSize() != 0){
          final DefaultListModel page = new DefaultListModel();
          final int start = (currPageNum - 1) * pageSize;
          int end = start + pageSize;
          if (end >= model.getSize()) {
              end = model.getSize();
          }
          for (int i = start; i < end; i++) {
              page.addElement(model.getElementAt(i));
          }
          list.setModel(page);
      }

      //update the label
      countLabel.setText("Page " + currPageNum + "/" + lastPageNum);

      // update buttons
      final boolean canGoBack = currPageNum > 1;
      final boolean canGoFwd = currPageNum != lastPageNum;
      first.setEnabled(canGoBack);
      prev.setEnabled(canGoBack);
      next.setEnabled(canGoFwd);
      last.setEnabled(canGoFwd);
  }

  public static void main(String args[]) throws Exception {

      // create 100 elements of dummy data.
      String[] data = new String[101];
      for (int i = 0; i < data.length; i++) {
          data[i] = "Item "+ (i + 1);
      }

      // create a paginated list with page size 20
      PaginatedList list = new PaginatedList(new JList(data), 10);

      // add it to a frame
      JFrame f = new JFrame("Paginated List Demo");
      f.add(list);
      f.setSize(100, 100);
      f.pack();
      f.setVisible(true);
  }
}

Monday, December 28, 2009

Adding a JProgressBar to a JTable Cell

Create a cell TableCellRenderer which uses a JProgressBar as follows:
import java.awt.Component;

import javax.swing.JProgressBar;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class ProgressCellRenderer extends JProgressBar
                        implements TableCellRenderer {

  /**
   * Creates a JProgressBar with the range 0,100.
   */
  public ProgressCellRenderer(){
    super(0, 100);
    setValue(0);
    setString("0%");
    setStringPainted(true);
  }

  public Component getTableCellRendererComponent(
                                    JTable table,
                                    Object value,
                                    boolean isSelected,
                                    boolean hasFocus,
                                    int row,
                                    int column) {

    //value is a percentage e.g. 95%
    final String sValue = value.toString();
    int index = sValue.indexOf('%');
    if (index != -1) {
      int p = 0;
      try{
        p = Integer.parseInt(sValue.substring(0, index));
      }
      catch(NumberFormatException e){
      }
      setValue(p);
      setString(sValue);
    }
    return this;
  }
}
Apply the cell renderer to a specific column in the table:
JTable myTable = new JTable();
TableColumn myCol = myTable.getColumnModel().getColumn(1);
myCol.setCellRenderer(new ProgressCellRenderer());
Now whenever you update a value in that column, the JProgressBar will get updated accordingly.