Java Swing Components : Example
- A simple Clock
- Dual Lists Demo
- ItemChooser
- JSpinField is a numeric field with 2 spin buttons to increase or decrease the value.
- LayeredPane With Warning
- JTreeTable component
- Auto Complete TextField
- A button which paints on it one or more scaled arrows in one of the cardinal directions
- Arrow Button
- The various table charting classes
- A panel from where you can choose a color based on it's HTML name
- A JOutlookBar provides a component that is similar to a JTabbedPane, but instead of maintaining tabs
- Another Link button
- LinkButton
- Separator Sample 2
- Separator Sample
- A demonstration of the JSeparator() component used in a toolbar-like
- Thumb Slider Example
- Thumb Slider Example 1
- Thumb Slider Example 2
- Slider With ToolTip Example
- A dialog that presents the user with a sequence of steps for completing a task.
A simple Clock
import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.text.DecimalFormat; import java.util.Calendar; /** A simple Clock */ public class Clock extends javax.swing.JComponent { protected DecimalFormat tflz, tf; protected boolean done = false; public Clock() { new Thread(new Runnable() { public void run() { while (!done) { Clock.this.repaint(); // request a redraw try { Thread.sleep(1000); } catch (InterruptedException e) { /* do nothing */ } } } }).start(); tf = new DecimalFormat("#0"); tflz = new DecimalFormat("00"); } public void stop() { done = true; } /* paint() - get current time and draw (centered) in Component. */ public void paint(Graphics g) { Calendar myCal = Calendar.getInstance(); StringBuffer sb = new StringBuffer(); sb.append(tf.format(myCal.get(Calendar.HOUR))); sb.append(':'); sb.append(tflz.format(myCal.get(Calendar.MINUTE))); sb.append(':'); sb.append(tflz.format(myCal.get(Calendar.SECOND))); String s = sb.toString(); FontMetrics fm = getFontMetrics(getFont()); int x = (getSize().width - fm.stringWidth(s)) / 2; // System.out.println("Size is " + getSize()); g.drawString(s, x, 10); } public Dimension getPreferredSize() { return new Dimension(100, 30); } public Dimension getMinimumSize() { return new Dimension(50, 10); } }
Dual Lists Demo
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.AbstractListModel; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.ListModel; public class MainClass { public static void main(String args[]) { JFrame frame = new JFrame("Dual List Box Tester"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DualListBox dual = new DualListBox(); dual.addSourceElements(new String[] { "One", "Two", "Three" }); frame.add(dual, BorderLayout.CENTER); frame.setSize(400, 300); frame.setVisible(true); } } class DualListBox extends JPanel { private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0); private static final String ADD_BUTTON_LABEL = "Add >>"; private static final String REMOVE_BUTTON_LABEL = "<< Remove"; private static final String DEFAULT_SOURCE_CHOICE_LABEL = "Available Choices"; private static final String DEFAULT_DEST_CHOICE_LABEL = "Your Choices"; private JLabel sourceLabel; private JList sourceList; private SortedListModel sourceListModel; private JList destList; private SortedListModel destListModel; private JLabel destLabel; private JButton addButton; private JButton removeButton; public DualListBox() { initScreen(); } public String getSourceChoicesTitle() { return sourceLabel.getText(); } public void setSourceChoicesTitle(String newValue) { sourceLabel.setText(newValue); } public String getDestinationChoicesTitle() { return destLabel.getText(); } public void setDestinationChoicesTitle(String newValue) { destLabel.setText(newValue); } public void clearSourceListModel() { sourceListModel.clear(); } public void clearDestinationListModel() { destListModel.clear(); } public void addSourceElements(ListModel newValue) { fillListModel(sourceListModel, newValue); } public void setSourceElements(ListModel newValue) { clearSourceListModel(); addSourceElements(newValue); } public void addDestinationElements(ListModel newValue) { fillListModel(destListModel, newValue); } private void fillListModel(SortedListModel model, ListModel newValues) { int size = newValues.getSize(); for (int i = 0; i < size; i++) { model.add(newValues.getElementAt(i)); } } public void addSourceElements(Object newValue[]) { fillListModel(sourceListModel, newValue); } public void setSourceElements(Object newValue[]) { clearSourceListModel(); addSourceElements(newValue); } public void addDestinationElements(Object newValue[]) { fillListModel(destListModel, newValue); } private void fillListModel(SortedListModel model, Object newValues[]) { model.addAll(newValues); } public Iterator sourceIterator() { return sourceListModel.iterator(); } public Iterator destinationIterator() { return destListModel.iterator(); } public void setSourceCellRenderer(ListCellRenderer newValue) { sourceList.setCellRenderer(newValue); } public ListCellRenderer getSourceCellRenderer() { return sourceList.getCellRenderer(); } public void setDestinationCellRenderer(ListCellRenderer newValue) { destList.setCellRenderer(newValue); } public ListCellRenderer getDestinationCellRenderer() { return destList.getCellRenderer(); } public void setVisibleRowCount(int newValue) { sourceList.setVisibleRowCount(newValue); destList.setVisibleRowCount(newValue); } public int getVisibleRowCount() { return sourceList.getVisibleRowCount(); } public void setSelectionBackground(Color newValue) { sourceList.setSelectionBackground(newValue); destList.setSelectionBackground(newValue); } public Color getSelectionBackground() { return sourceList.getSelectionBackground(); } public void setSelectionForeground(Color newValue) { sourceList.setSelectionForeground(newValue); destList.setSelectionForeground(newValue); } public Color getSelectionForeground() { return sourceList.getSelectionForeground(); } private void clearSourceSelected() { Object selected[] = sourceList.getSelectedValues(); for (int i = selected.length - 1; i >= 0; --i) { sourceListModel.removeElement(selected[i]); } sourceList.getSelectionModel().clearSelection(); } private void clearDestinationSelected() { Object selected[] = destList.getSelectedValues(); for (int i = selected.length - 1; i >= 0; --i) { destListModel.removeElement(selected[i]); } destList.getSelectionModel().clearSelection(); } private void initScreen() { setBorder(BorderFactory.createEtchedBorder()); setLayout(new GridBagLayout()); sourceLabel = new JLabel(DEFAULT_SOURCE_CHOICE_LABEL); sourceListModel = new SortedListModel(); sourceList = new JList(sourceListModel); add(sourceLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, EMPTY_INSETS, 0, 0)); add(new JScrollPane(sourceList), new GridBagConstraints(0, 1, 1, 5, .5, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, EMPTY_INSETS, 0, 0)); addButton = new JButton(ADD_BUTTON_LABEL); add(addButton, new GridBagConstraints(1, 2, 1, 2, 0, .25, GridBagConstraints.CENTER, GridBagConstraints.NONE, EMPTY_INSETS, 0, 0)); addButton.addActionListener(new AddListener()); removeButton = new JButton(REMOVE_BUTTON_LABEL); add(removeButton, new GridBagConstraints(1, 4, 1, 2, 0, .25, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0)); removeButton.addActionListener(new RemoveListener()); destLabel = new JLabel(DEFAULT_DEST_CHOICE_LABEL); destListModel = new SortedListModel(); destList = new JList(destListModel); add(destLabel, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, EMPTY_INSETS, 0, 0)); add(new JScrollPane(destList), new GridBagConstraints(2, 1, 1, 5, .5, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, EMPTY_INSETS, 0, 0)); } private class AddListener implements ActionListener { public void actionPerformed(ActionEvent e) { Object selected[] = sourceList.getSelectedValues(); addDestinationElements(selected); clearSourceSelected(); } } private class RemoveListener implements ActionListener { public void actionPerformed(ActionEvent e) { Object selected[] = destList.getSelectedValues(); addSourceElements(selected); clearDestinationSelected(); } } } class SortedListModel extends AbstractListModel { SortedSet<Object> model; public SortedListModel() { model = new TreeSet<Object>(); } public int getSize() { return model.size(); } public Object getElementAt(int index) { return model.toArray()[index]; } public void add(Object element) { if (model.add(element)) { fireContentsChanged(this, 0, getSize()); } } public void addAll(Object elements[]) { Collection<Object> c = Arrays.asList(elements); model.addAll(c); fireContentsChanged(this, 0, getSize()); } public void clear() { model.clear(); fireContentsChanged(this, 0, getSize()); } public boolean contains(Object element) { return model.contains(element); } public Object firstElement() { return model.first(); } public Iterator iterator() { return model.iterator(); } public Object lastElement() { return model.last(); } public boolean removeElement(Object element) { boolean removed = model.remove(element); if (removed) { fireContentsChanged(this, 0, getSize()); } return removed; } }
ItemChooser
import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Iterator; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; /** * This class is a Swing component that presents a choice to the user. It allows * the choice to be presented in a JList, in a JComboBox, or with a bordered * group of JRadioButton components. Additionally, it displays the name of the * choice with a JLabel. It allows an arbitrary value to be associated with each * possible choice. Note that this component only allows one item to be selected * at a time. Multiple selections are not supported. */ public class ItemChooser extends JPanel { // These fields hold property values for this component String name; // The overall name of the choice String[] labels; // The text for each choice option Object[] values; // Arbitrary values associated with each option int selection; // The selected choice int presentation; // How the choice is presented // These are the legal values for the presentation field public static final int LIST = 1; public static final int COMBOBOX = 2; public static final int RADIOBUTTONS = 3; // These components are used for each of the 3 possible presentations JList list; // One type of presentation JComboBox combobox; // Another type of presentation JRadioButton[] radiobuttons; // Yet another type // The list of objects that are interested in our state ArrayList listeners = new ArrayList(); // The constructor method sets everything up public ItemChooser(String name, String[] labels, Object[] values, int defaultSelection, int presentation) { // Copy the constructor arguments to instance fields this.name = name; this.labels = labels; this.values = values; this.selection = defaultSelection; this.presentation = presentation; // If no values were supplied, use the labels if (values == null) this.values = labels; // Now create content and event handlers based on presentation type switch (presentation) { case LIST: initList(); break; case COMBOBOX: initComboBox(); break; case RADIOBUTTONS: initRadioButtons(); break; } } // Initialization for JList presentation void initList() { list = new JList(labels); // Create the list list.setSelectedIndex(selection); // Set initial state // Handle state changes list.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { ItemChooser.this.select(list.getSelectedIndex()); } }); // Lay out list and name label vertically this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // vertical this.add(new JLabel(name)); // Display choice name this.add(new JScrollPane(list)); // Add the JList } // Initialization for JComboBox presentation void initComboBox() { combobox = new JComboBox(labels); // Create the combo box // combobox.setSelectedIndex(selection); // Set initial state // Handle changes to the state combobox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { ItemChooser.this.select(combobox.getSelectedIndex()); } }); // Lay out combo box and name label horizontally this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); this.add(new JLabel(name)); this.add(combobox); } // Initialization for JRadioButton presentation void initRadioButtons() { // Create an array of mutually exclusive radio buttons radiobuttons = new JRadioButton[labels.length]; // the array ButtonGroup radioButtonGroup = new ButtonGroup(); // used for exclusion ChangeListener listener = new ChangeListener() { // A shared listener public void stateChanged(ChangeEvent e) { JRadioButton b = (JRadioButton) e.getSource(); if (b.isSelected()) { // If we received this event because a button was // selected, then loop through the list of buttons to // figure out the index of the selected one. for (int i = 0; i < radiobuttons.length; i++) { if (radiobuttons[i] == b) { ItemChooser.this.select(i); return; } } } } }; // Display the choice name in a border around the buttons this.setBorder(new TitledBorder(new EtchedBorder(), name)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // Create the buttons, add them to the button group, and specify // the event listener for each one. for (int i = 0; i < labels.length; i++) { radiobuttons[i] = new JRadioButton(labels[i]); if (i == selection) radiobuttons[i].setSelected(true); radiobuttons[i].addChangeListener(listener); radioButtonGroup.add(radiobuttons[i]); this.add(radiobuttons[i]); } } // These simple property accessor methods just return field values // These are read-only properties. The values are set by the constructor // and may not be changed. public String getName() { return name; } public int getPresentation() { return presentation; } public String[] getLabels() { return labels; } public Object[] getValues() { return values; } /** Return the index of the selected item */ public int getSelectedIndex() { return selection; } /** Return the object associated with the selected item */ public Object getSelectedValue() { return values[selection]; } /** * Set the selected item by specifying its index. Calling this method * changes the on-screen display but does not generate events. */ public void setSelectedIndex(int selection) { switch (presentation) { case LIST: list.setSelectedIndex(selection); break; case COMBOBOX: combobox.setSelectedIndex(selection); break; case RADIOBUTTONS: radiobuttons[selection].setSelected(true); break; } this.selection = selection; } /** * This internal method is called when the selection changes. It stores the * new selected index, and fires events to any registered listeners. The * event listeners registered on the JList, JComboBox, or JRadioButtons all * call this method. */ protected void select(int selection) { this.selection = selection; // Store the new selected index if (!listeners.isEmpty()) { // If there are any listeners registered // Create an event object to describe the selection ItemChooser.Event e = new ItemChooser.Event(this, selection, values[selection]); // Loop through the listeners using an Iterator for (Iterator i = listeners.iterator(); i.hasNext();) { ItemChooser.Listener l = (ItemChooser.Listener) i.next(); l.itemChosen(e); // Notify each listener of the selection } } } // These methods are for event listener registration and deregistration public void addItemChooserListener(ItemChooser.Listener l) { listeners.add(l); } public void removeItemChooserListener(ItemChooser.Listener l) { listeners.remove(l); } /** * This inner class defines the event type generated by ItemChooser objects * The inner class name is Event, so the full name is ItemChooser.Event */ public static class Event extends java.util.EventObject { int selectedIndex; // index of the selected item Object selectedValue; // the value associated with it public Event(ItemChooser source, int selectedIndex, Object selectedValue) { super(source); this.selectedIndex = selectedIndex; this.selectedValue = selectedValue; } public ItemChooser getItemChooser() { return (ItemChooser) getSource(); } public int getSelectedIndex() { return selectedIndex; } public Object getSelectedValue() { return selectedValue; } } /** * This inner interface must be implemented by any object that wants to be * notified when the current selection in a ItemChooser component changes. */ public interface Listener extends java.util.EventListener { public void itemChosen(ItemChooser.Event e); } public static void main(String[] args) { // Create a window, arrange to handle close requests final JFrame frame = new JFrame("ItemChooser Demo"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); // A "message line" to display results in final JLabel msgline = new JLabel(" "); args = new String[]{"a","b","c"}; // Create a panel holding three ItemChooser components JPanel chooserPanel = new JPanel(); final ItemChooser c1 = new ItemChooser("Choice #1", args, null, 0, ItemChooser.LIST); final ItemChooser c2 = new ItemChooser("Choice #2", args, null, 0, ItemChooser.COMBOBOX); final ItemChooser c3 = new ItemChooser("Choice #3", args, null, 0, ItemChooser.RADIOBUTTONS); // An event listener that displays changes on the message line ItemChooser.Listener l = new ItemChooser.Listener() { public void itemChosen(ItemChooser.Event e) { msgline.setText(e.getItemChooser().getName() + ": " + e.getSelectedIndex() + ": " + e.getSelectedValue()); } }; c1.addItemChooserListener(l); c2.addItemChooserListener(l); c3.addItemChooserListener(l); // Instead of tracking every change with a ItemChooser.Listener, // applications can also just query the current state when // they need it. Here's a button that does that. JButton report = new JButton("Report"); report.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Note the use of multi-line italic HTML text // with the JOptionPane message dialog box. String msg = "<html><i>" + c1.getName() + ": " + c1.getSelectedValue() + "<br>" + c2.getName() + ": " + c2.getSelectedValue() + "<br>" + c3.getName() + ": " + c3.getSelectedValue() + "</i>"; JOptionPane.showMessageDialog(frame, msg); } }); // Add the 3 ItemChooser objects, and the Button to the panel chooserPanel.add(c1); chooserPanel.add(c2); chooserPanel.add(c3); chooserPanel.add(report); // Add the panel and the message line to the window Container contentPane = frame.getContentPane(); contentPane.add(chooserPanel, BorderLayout.CENTER); contentPane.add(msgline, BorderLayout.SOUTH); // Set the window size and pop it up. frame.pack(); frame.show(); } }
JSpinField is a numeric field with 2 spin buttons to increase or decrease the value.
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * JSpinField is a numeric field with 2 spin buttons to increase or decrease the * value. It has the same interface as the "old" JSpinField but uses a JSpinner * internally (since J2SE SDK 1.4) rather than a scrollbar for emulating the * spin buttons. * * @author Kai Toedter * @version $LastChangedRevision: 85 $ * @version $LastChangedDate: 2006-04-28 13:50:52 +0200 (Fr, 28 Apr 2006) $ */ public class JSpinField extends JPanel implements ChangeListener, CaretListener, ActionListener, FocusListener { private static final long serialVersionUID = 1694904792717740650L; protected JSpinner spinner; /** the text (number) field */ protected JTextField textField; protected int min; protected int max; protected int value; protected Color darkGreen; /** * Default JSpinField constructor. The valid value range is between * Integer.MIN_VALUE and Integer.MAX_VALUE. The initial value is 0. */ public JSpinField() { this(Integer.MIN_VALUE, Integer.MAX_VALUE); } /** * JSpinField constructor with given minimum and maximum vaues and initial * value 0. */ public JSpinField(int min, int max) { super(); setName("JSpinField"); this.min = min; if (max < min) max = min; this.max = max; value = 0; if (value < min) value = min; if (value > max) value = max; darkGreen = new Color(0, 150, 0); setLayout(new BorderLayout()); textField = new JTextField(); textField.addCaretListener(this); textField.addActionListener(this); textField.setHorizontalAlignment(SwingConstants.RIGHT); textField.setBorder(BorderFactory.createEmptyBorder()); textField.setText(Integer.toString(value)); textField.addFocusListener(this); spinner = new JSpinner() { private static final long serialVersionUID = -6287709243342021172L; private JTextField textField = new JTextField(); public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); return new Dimension(size.width, textField.getPreferredSize().height); } }; spinner.setEditor(textField); spinner.addChangeListener(this); // spinner.setSize(spinner.getWidth(), textField.getHeight()); add(spinner, BorderLayout.CENTER); } public void adjustWidthToMaximumValue() { JTextField testTextField = new JTextField(Integer.toString(max)); int width = testTextField.getPreferredSize().width; int height = testTextField.getPreferredSize().height; textField.setPreferredSize(new Dimension(width, height)); textField.revalidate(); } /** * Is invoked when the spinner model changes * * @param e * the ChangeEvent */ public void stateChanged(ChangeEvent e) { SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel(); int value = model.getNumber().intValue(); setValue(value); } /** * Sets the value attribute of the JSpinField object. * * @param newValue * The new value * @param updateTextField * true if text field should be updated */ protected void setValue(int newValue, boolean updateTextField, boolean firePropertyChange) { int oldValue = value; if (newValue < min) { value = min; } else if (newValue > max) { value = max; } else { value = newValue; } if (updateTextField) { textField.setText(Integer.toString(value)); textField.setForeground(Color.black); } if (firePropertyChange) { firePropertyChange("value", oldValue, value); } } /** * Sets the value. This is a bound property. * * @param newValue * the new value * * @see #getValue */ public void setValue(int newValue) { setValue(newValue, true, true); spinner.setValue(new Integer(value)); } /** * Returns the value. * * @return the value value */ public int getValue() { return value; } /** * Sets the minimum value. * * @param newMinimum * the new minimum value * * @see #getMinimum */ public void setMinimum(int newMinimum) { min = newMinimum; } /** * Returns the minimum value. * * @return the minimum value */ public int getMinimum() { return min; } /** * Sets the maximum value and adjusts the preferred width. * * @param newMaximum * the new maximum value * * @see #getMaximum */ public void setMaximum(int newMaximum) { max = newMaximum; } /** * Sets the horizontal alignment of the displayed value. * * @param alignment * the horizontal alignment */ public void setHorizontalAlignment(int alignment) { textField.setHorizontalAlignment(alignment); } /** * Returns the maximum value. * * @return the maximum value */ public int getMaximum() { return max; } /** * Sets the font property. * * @param font * the new font */ public void setFont(Font font) { if (textField != null) { textField.setFont(font); } } /** * Sets the foreground * * @param fg * the foreground */ public void setForeground(Color fg) { if (textField != null) { textField.setForeground(fg); } } /** * After any user input, the value of the textfield is proofed. Depending on * being an integer, the value is colored green or red. * * @param e * the caret event */ public void caretUpdate(CaretEvent e) { try { int testValue = Integer.valueOf(textField.getText()).intValue(); if ((testValue >= min) && (testValue <= max)) { textField.setForeground(darkGreen); setValue(testValue, false, true); } else { textField.setForeground(Color.red); } } catch (Exception ex) { if (ex instanceof NumberFormatException) { textField.setForeground(Color.red); } // Ignore all other exceptions, e.g. illegal state exception } textField.repaint(); } /** * After any user input, the value of the textfield is proofed. Depending on * being an integer, the value is colored green or red. If the textfield is * green, the enter key is accepted and the new value is set. * * @param e * Description of the Parameter */ public void actionPerformed(ActionEvent e) { if (textField.getForeground().equals(darkGreen)) { setValue(Integer.valueOf(textField.getText()).intValue()); } } /** * Enable or disable the JSpinField. * * @param enabled * The new enabled value */ public void setEnabled(boolean enabled) { super.setEnabled(enabled); spinner.setEnabled(enabled); textField.setEnabled(enabled); /* * Fixes the background bug * 4991597 and sets the background explicitely to a * TextField.inactiveBackground. */ if (!enabled) { textField.setBackground(UIManager.getColor("TextField.inactiveBackground")); } } /** * Returns the year chooser's spinner (which allow the focus to be set to * it). * * @return Component the spinner or null, if the month chooser has no * spinner */ public Component getSpinner() { return spinner; } /** * Creates a JFrame with a JSpinField inside and can be used for testing. * * @param s * The command line arguments */ public static void main(String[] s) { JFrame frame = new JFrame("JSpinField"); frame.getContentPane().add(new JSpinField()); frame.pack(); frame.setVisible(true); } /* * (non-Javadoc) * * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent) */ public void focusGained(FocusEvent e) { } /** * The value of the text field is checked against a valid (green) value. If * valid, the value is set and a property change is fired. */ public void focusLost(FocusEvent e) { actionPerformed(null); } }
LayeredPane With Warning
import java.awt.Graphics; import java.awt.Point; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.HashSet; import java.util.Set; import javax.imageio.ImageIO; import javax.swing.JComponent; import javax.swing.JViewport; import javax.swing.SwingUtilities; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.JLayeredPane; import javax.swing.JTextField; import javax.swing.OverlayLayout; import javax.swing.text.JTextComponent; /** * * @author Romain Guy */ public class Layers extends javax.swing.JFrame { /** Creates new form Layers */ public Layers() { initComponents(); addLayeredValidator(); addValidations(); } /** 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. */ // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents private void initComponents() { javax.swing.JLabel jLabel1; javax.swing.JLabel jLabel2; javax.swing.JLabel jLabel3; javax.swing.JLabel jLabel4; javax.swing.JLabel jLabel5; javax.swing.JList jList1; javax.swing.JScrollPane jScrollPane1; javax.swing.JScrollPane jScrollPane2; jScrollPane1 = new javax.swing.JScrollPane(); jList1 = new javax.swing.JList(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); jLabel5 = new javax.swing.JLabel(); firstName = new javax.swing.JTextField(); lastName = new javax.swing.JTextField(); phoneNumber = new javax.swing.JTextField(); email = new javax.swing.JTextField(); jScrollPane2 = new javax.swing.JScrollPane(); address = new javax.swing.JTextArea(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("Layered Panes"); jList1.setModel(new javax.swing.AbstractListModel() { String[] strings = { "Jeff Dinkins", "Richard Bair", "Amy Fowler", "Scott Violet", "Hans Muller", "Chris Campbell", "Chet Haase" }; public int getSize() { return strings.length; } public Object getElementAt(int i) { return strings[i]; } }); jScrollPane1.setViewportView(jList1); jLabel1.setText("First Name"); jLabel2.setText("Last Name"); jLabel3.setText("Phone"); jLabel4.setText("Email"); jLabel5.setText("Address"); address.setColumns(15); address.setRows(5); jScrollPane2.setViewportView(address); org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 152, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel5) .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel4) .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel3) .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel2) .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel1)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(firstName, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE) .add(lastName, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE) .add(phoneNumber, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE) .add(email, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE) .add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel1) .add(firstName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel2) .add(lastName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel3) .add(phoneNumber, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel4) .add(email, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jLabel5) .add(jScrollPane2)) .add(6, 6, 6)) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)) .addContainerGap()) ); java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); setBounds((screenSize.width-489)/2, (screenSize.height-266)/2, 489, 266); }// </editor-fold>//GEN-END:initComponents /** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new Layers().setVisible(true); } }); } private void addLayeredValidator() { validator = new Validator(); JLayeredPane layeredPane = getRootPane().getLayeredPane(); layeredPane.setLayout(new OverlayLayout(layeredPane)); layeredPane.add(validator, (Integer) (JLayeredPane.DEFAULT_LAYER + 50)); //validator.setBounds(0, 0, getWidth(), getHeight()); } private void addValidations() { addValidationForText(address); addValidationForText(firstName); addValidationForText(lastName); addValidationForNumber(phoneNumber); addValidationForEmail(email); } private void addValidationForText(JTextComponent field) { field.addFocusListener(new FocusListener() { public void focusGained(FocusEvent focusEvent) { } public void focusLost(FocusEvent focusEvent) { JTextComponent field = (JTextComponent) focusEvent.getComponent(); String text = field.getText(); if (text.matches("[-A-Za-z ]*")) { validator.addWarning(field); } else { validator.removeWarning(field); } } }); } private void addValidationForNumber(JTextComponent field) { field.addFocusListener(new FocusListener() { public void focusGained(FocusEvent focusEvent) { } public void focusLost(FocusEvent focusEvent) { JTextField field = (JTextField) focusEvent.getComponent(); String text = field.getText(); if (text.matches("[-()0-9 ]*")) { validator.addWarning(field); } else { validator.removeWarning(field); } } }); } private void addValidationForEmail(JTextComponent field) { field.addFocusListener(new FocusListener() { public void focusGained(FocusEvent focusEvent) { } public void focusLost(FocusEvent focusEvent) { JTextComponent field = (JTextComponent) focusEvent.getComponent(); String text = field.getText(); if (text.matches("[^@]+@([^.]+\\.)+[^.]+")) { validator.addWarning(field); } else { validator.removeWarning(field); } } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextArea address; private javax.swing.JTextField email; private javax.swing.JTextField firstName; private javax.swing.JTextField lastName; private javax.swing.JTextField phoneNumber; // End of variables declaration//GEN-END:variables private Validator validator; } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * * @author Romain Guy <romain.guy@mac.com> */ class Validator extends JComponent { private Set<JComponent> invalidFields = new HashSet<JComponent>(); private BufferedImage warningIcon; /** Creates a new instance of Validator */ public Validator() { loadImages(); } public void addWarning(JComponent field) { if (invalidFields.contains(field)) { invalidFields.remove(field); repaintBadge(field); } } public void removeWarning(JComponent field) { invalidFields.add(field); repaintBadge(field); } private void repaintBadge(JComponent field) { Point p = field.getLocationOnScreen(); SwingUtilities.convertPointFromScreen(p, this); int x = p.x - warningIcon.getWidth() / 2; int y = (int) (p.y + field.getHeight() - warningIcon.getHeight() / 1.5); repaint(x, y, warningIcon.getWidth(), warningIcon.getHeight()); } private void loadImages() { try { warningIcon = ImageIO.read(getClass().getResource("dialog-warning.png")); } catch (IOException ex) { ex.printStackTrace(); } } @Override protected void paintComponent(Graphics g) { for (JComponent invalid : invalidFields) { if (invalid.getParent() instanceof JViewport) { JViewport viewport = (JViewport) invalid.getParent(); // the parent of the viewport is a JScrollPane invalid = (JComponent) viewport.getParent(); } Point p = invalid.getLocationOnScreen(); SwingUtilities.convertPointFromScreen(p, this); int x = p.x - warningIcon.getWidth() / 2; int y = (int) (p.y + invalid.getHeight() - warningIcon.getHeight() / 1.5); if (g.getClipBounds().intersects(x, y, warningIcon.getWidth(), warningIcon.getHeight())) { g.drawImage(warningIcon, x, y, null); } } } }
JTreeTable component
import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.util.EventObject; import javax.swing.AbstractCellEditor; import javax.swing.JTable; import javax.swing.JTree; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; /** * This example shows how to create a simple JTreeTable component, * by using a JTree as a renderer (and editor) for the cells in a * particular column in the JTable. * * @version 1.2 10/27/98 * * @author Philip Milne * @author Scott Violet */ public class JTreeTable extends JTable { /** A subclass of JTree. */ protected TreeTableCellRenderer tree; public JTreeTable(TreeTableModel treeTableModel) { super(); // Create the tree. It will be used as a renderer and editor. tree = new TreeTableCellRenderer(treeTableModel); // Install a tableModel representing the visible rows in the tree. super.setModel(new TreeTableModelAdapter(treeTableModel, tree)); // Force the JTable and JTree to share their row selection models. ListToTreeSelectionModelWrapper selectionWrapper = new ListToTreeSelectionModelWrapper(); tree.setSelectionModel(selectionWrapper); setSelectionModel(selectionWrapper.getListSelectionModel()); // Install the tree editor renderer and editor. setDefaultRenderer(TreeTableModel.class, tree); setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor()); // No grid. setShowGrid(false); // No intercell spacing setIntercellSpacing(new Dimension(0, 0)); // And update the height of the trees row to match that of // the table. if (tree.getRowHeight() < 1) { // Metal looks better like this. setRowHeight(18); } } /** * Overridden to message super and forward the method to the tree. * Since the tree is not actually in the component hieachy it will * never receive this unless we forward it in this manner. */ public void updateUI() { super.updateUI(); if(tree != null) { tree.updateUI(); } // Use the tree's default foreground and background colors in the // table. LookAndFeel.installColorsAndFont(this, "Tree.background", "Tree.foreground", "Tree.font"); } /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to * paint the editor. The UI currently uses different techniques to * paint the renderers and editors and overriding setBounds() below * is not the right thing to do for an editor. Returning -1 for the * editing row in this case, ensures the editor is never painted. */ public int getEditingRow() { return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 : editingRow; } /** * Overridden to pass the new rowHeight to the tree. */ public void setRowHeight(int rowHeight) { super.setRowHeight(rowHeight); if (tree != null && tree.getRowHeight() != rowHeight) { tree.setRowHeight(getRowHeight()); } } /** * Returns the tree that is being shared between the model. */ public JTree getTree() { return tree; } /** * A TreeCellRenderer that displays a JTree. */ public class TreeTableCellRenderer extends JTree implements TableCellRenderer { /** Last table/tree row asked to renderer. */ protected int visibleRow; public TreeTableCellRenderer(TreeModel model) { super(model); } /** * updateUI is overridden to set the colors of the Tree's renderer * to match that of the table. */ public void updateUI() { super.updateUI(); // Make the tree's cell renderer use the table's cell selection // colors. TreeCellRenderer tcr = getCellRenderer(); if (tcr instanceof DefaultTreeCellRenderer) { DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr); // For 1.1 uncomment this, 1.2 has a bug that will cause an // exception to be thrown if the border selection color is // null. // dtcr.setBorderSelectionColor(null); dtcr.setTextSelectionColor(UIManager.getColor ("Table.selectionForeground")); dtcr.setBackgroundSelectionColor(UIManager.getColor ("Table.selectionBackground")); } } /** * Sets the row height of the tree, and forwards the row height to * the table. */ public void setRowHeight(int rowHeight) { if (rowHeight > 0) { super.setRowHeight(rowHeight); if (JTreeTable.this != null && JTreeTable.this.getRowHeight() != rowHeight) { JTreeTable.this.setRowHeight(getRowHeight()); } } } /** * This is overridden to set the height to match that of the JTable. */ public void setBounds(int x, int y, int w, int h) { super.setBounds(x, 0, w, JTreeTable.this.getHeight()); } /** * Sublcassed to translate the graphics such that the last visible * row will be drawn at 0,0. */ public void paint(Graphics g) { g.translate(0, -visibleRow * getRowHeight()); super.paint(g); } /** * TreeCellRenderer method. Overridden to update the visible row. */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if(isSelected) setBackground(table.getSelectionBackground()); else setBackground(table.getBackground()); visibleRow = row; return this; } } /** * TreeTableCellEditor implementation. Component returned is the * JTree. */ class TreeTableCellEditor extends AbstractCellEditor implements TableCellEditor { public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int r, int c) { return tree; } /** * Overridden to return false, and if the event is a mouse event * it is forwarded to the tree.<p> * The behavior for this is debatable, and should really be offered * as a property. By returning false, all keyboard actions are * implemented in terms of the table. By returning true, the * tree would get a chance to do something with the keyboard * events. For the most part this is ok. But for certain keys, * such as left/right, the tree will expand/collapse where as * the table focus should really move to a different column. Page * up/down should also be implemented in terms of the table. * By returning false this also has the added benefit that clicking * outside of the bounds of the tree node, but still in the tree * column will select the row, whereas if this returned true * that wouldn't be the case. * <p>By returning false we are also enforcing the policy that * the tree will never be editable (at least by a key sequence). */ public boolean isCellEditable(EventObject e) { if (e instanceof MouseEvent) { for (int counter = getColumnCount() - 1; counter >= 0; counter--) { if (getColumnClass(counter) == TreeTableModel.class) { MouseEvent me = (MouseEvent)e; MouseEvent newME = new MouseEvent(tree, me.getID(), me.getWhen(), me.getModifiers(), me.getX() - getCellRect(0, counter, true).x, me.getY(), me.getClickCount(), me.isPopupTrigger()); tree.dispatchEvent(newME); break; } } } return false; } public Object getCellEditorValue() { // TODO Auto-generated method stub return null; } } /** * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel * to listen for changes in the ListSelectionModel it maintains. Once * a change in the ListSelectionModel happens, the paths are updated * in the DefaultTreeSelectionModel. */ class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { /** Set to true when we are updating the ListSelectionModel. */ protected boolean updatingListSelectionModel; public ListToTreeSelectionModelWrapper() { super(); getListSelectionModel().addListSelectionListener (createListSelectionListener()); } /** * Returns the list selection model. ListToTreeSelectionModelWrapper * listens for changes to this model and updates the selected paths * accordingly. */ ListSelectionModel getListSelectionModel() { return listSelectionModel; } /** * This is overridden to set <code>updatingListSelectionModel</code> * and message super. This is the only place DefaultTreeSelectionModel * alters the ListSelectionModel. */ public void resetRowSelection() { if(!updatingListSelectionModel) { updatingListSelectionModel = true; try { super.resetRowSelection(); } finally { updatingListSelectionModel = false; } } // Notice how we don't message super if // updatingListSelectionModel is true. If // updatingListSelectionModel is true, it implies the // ListSelectionModel has already been updated and the // paths are the only thing that needs to be updated. } /** * Creates and returns an instance of ListSelectionHandler. */ protected ListSelectionListener createListSelectionListener() { return new ListSelectionHandler(); } /** * If <code>updatingListSelectionModel</code> is false, this will * reset the selected paths from the selected rows in the list * selection model. */ protected void updateSelectedPathsFromSelectedRows() { if(!updatingListSelectionModel) { updatingListSelectionModel = true; try { // This is way expensive, ListSelectionModel needs an // enumerator for iterating. int min = listSelectionModel.getMinSelectionIndex(); int max = listSelectionModel.getMaxSelectionIndex(); clearSelection(); if(min != -1 && max != -1) { for(int counter = min; counter <= max; counter++) { if(listSelectionModel.isSelectedIndex(counter)) { TreePath selPath = tree.getPathForRow (counter); if(selPath != null) { addSelectionPath(selPath); } } } } } finally { updatingListSelectionModel = false; } } } /** * Class responsible for calling updateSelectedPathsFromSelectedRows * when the selection of the list changse. */ class ListSelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { updateSelectedPathsFromSelectedRows(); } } } } /* * The contents of this file are subject to the Sapient Public License * Version 1.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://carbon.sf.net/License.html. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is The Carbon Component Framework. * * The Initial Developer of the Original Code is Sapient Corporation * * Copyright (C) 2003 Sapient Corporation. All Rights Reserved. */ /* * TreeTableModel.java * * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * */ /** * TreeTableModel is the model used by a JTreeTable. It extends TreeModel * to add methods for getting inforamtion about the set of columns each * node in the TreeTableModel may have. Each column, like a column in * a TableModel, has a name and a type associated with it. Each node in * the TreeTableModel can return a value for each of the columns and * set that value if isCellEditable() returns true. * * @author Philip Milne * @author Scott Violet */ interface TreeTableModel extends TreeModel { /** * Returns the number ofs availible column. */ public int getColumnCount(); /** * Returns the name for column number <code>column</code>. */ public String getColumnName(int column); /** * Returns the type for column number <code>column</code>. */ public Class getColumnClass(int column); /** * Returns the value to be displayed for node <code>node</code>, * at column number <code>column</code>. */ public Object getValueAt(Object node, int column); /** * Indicates whether the the value for node <code>node</code>, * at column number <code>column</code> is editable. */ public boolean isCellEditable(Object node, int column); /** * Sets the value for node <code>node</code>, * at column number <code>column</code>. */ public void setValueAt(Object aValue, Object node, int column); } /* * The contents of this file are subject to the Sapient Public License * Version 1.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://carbon.sf.net/License.html. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is The Carbon Component Framework. * * The Initial Developer of the Original Code is Sapient Corporation * * Copyright (C) 2003 Sapient Corporation. All Rights Reserved. */ /* * @(#)TreeTableModelAdapter.java 1.2 98/10/27 * * Copyright 1997, 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ /** * This is a wrapper class takes a TreeTableModel and implements * the table model interface. The implementation is trivial, with * all of the event dispatching support provided by the superclass: * the AbstractTableModel. * * @version 1.2 10/27/98 * * @author Philip Milne * @author Scott Violet */ class TreeTableModelAdapter extends AbstractTableModel { JTree tree; TreeTableModel treeTableModel; public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) { this.tree = tree; this.treeTableModel = treeTableModel; tree.addTreeExpansionListener(new TreeExpansionListener() { // Don't use fireTableRowsInserted() here; the selection model // would get updated twice. public void treeExpanded(TreeExpansionEvent event) { fireTableDataChanged(); } public void treeCollapsed(TreeExpansionEvent event) { fireTableDataChanged(); } }); // Install a TreeModelListener that can update the table when // tree changes. We use delayedFireTableDataChanged as we can // not be guaranteed the tree will have finished processing // the event before us. treeTableModel.addTreeModelListener(new TreeModelListener() { public void treeNodesChanged(TreeModelEvent e) { delayedFireTableDataChanged(); } public void treeNodesInserted(TreeModelEvent e) { delayedFireTableDataChanged(); } public void treeNodesRemoved(TreeModelEvent e) { delayedFireTableDataChanged(); } public void treeStructureChanged(TreeModelEvent e) { delayedFireTableDataChanged(); } }); } // Wrappers, implementing TableModel interface. public int getColumnCount() { return treeTableModel.getColumnCount(); } public String getColumnName(int column) { return treeTableModel.getColumnName(column); } public Class getColumnClass(int column) { return treeTableModel.getColumnClass(column); } public int getRowCount() { return tree.getRowCount(); } protected Object nodeForRow(int row) { TreePath treePath = tree.getPathForRow(row); return treePath.getLastPathComponent(); } public Object getValueAt(int row, int column) { return treeTableModel.getValueAt(nodeForRow(row), column); } public boolean isCellEditable(int row, int column) { return treeTableModel.isCellEditable(nodeForRow(row), column); } public void setValueAt(Object value, int row, int column) { treeTableModel.setValueAt(value, nodeForRow(row), column); } /** * Invokes fireTableDataChanged after all the pending events have been * processed. SwingUtilities.invokeLater is used to handle this. */ protected void delayedFireTableDataChanged() { SwingUtilities.invokeLater(new Runnable() { public void run() { fireTableDataChanged(); } }); } } /* * The contents of this file are subject to the Sapient Public License * Version 1.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://carbon.sf.net/License.html. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is The Carbon Component Framework. * * The Initial Developer of the Original Code is Sapient Corporation * * Copyright (C) 2003 Sapient Corporation. All Rights Reserved. */ package org.sape.carbon.services.swing.treetable; /* * @(#)AbstractTreeTableModel.java 1.2 98/10/27 * * Copyright 1997, 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ import javax.swing.event.EventListenerList; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreePath; /** * @version 1.2 10/27/98 * An abstract implementation of the TreeTableModel interface, handling the list * of listeners. * @author Philip Milne */ public abstract class AbstractTreeTableModel implements TreeTableModel { protected Object root; protected EventListenerList listenerList = new EventListenerList(); public AbstractTreeTableModel(Object root) { this.root = root; } // // Default implmentations for methods in the TreeModel interface. // public Object getRoot() { return root; } public boolean isLeaf(Object node) { return getChildCount(node) == 0; } public void valueForPathChanged(TreePath path, Object newValue) {} // This is not called in the JTree's default mode: use a naive implementation. public int getIndexOfChild(Object parent, Object child) { for (int i = 0; i < getChildCount(parent); i++) { if (getChild(parent, i).equals(child)) { return i; } } return -1; } public void addTreeModelListener(TreeModelListener l) { listenerList.add(TreeModelListener.class, l); } public void removeTreeModelListener(TreeModelListener l) { listenerList.remove(TreeModelListener.class, l); } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==TreeModelListener.class) { // Lazily create the event: if (e == null) e = new TreeModelEvent(source, path, childIndices, children); ((TreeModelListener)listeners[i+1]).treeNodesChanged(e); } } } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==TreeModelListener.class) { // Lazily create the event: if (e == null) e = new TreeModelEvent(source, path, childIndices, children); ((TreeModelListener)listeners[i+1]).treeNodesInserted(e); } } } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==TreeModelListener.class) { // Lazily create the event: if (e == null) e = new TreeModelEvent(source, path, childIndices, children); ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e); } } } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==TreeModelListener.class) { // Lazily create the event: if (e == null) e = new TreeModelEvent(source, path, childIndices, children); ((TreeModelListener)listeners[i+1]).treeStructureChanged(e); } } } // // Default impelmentations for methods in the TreeTableModel interface. // public Class getColumnClass(int column) { return Object.class; } /** By default, make the column with the Tree in it the only editable one. * Making this column editable causes the JTable to forward mouse * and keyboard events in the Tree column to the underlying JTree. */ public boolean isCellEditable(Object node, int column) { return getColumnClass(column) == TreeTableModel.class; } public void setValueAt(Object aValue, Object node, int column) {} // Left to be implemented in the subclass: /* * public Object getChild(Object parent, int index) * public int getChildCount(Object parent) * public int getColumnCount() * public String getColumnName(Object node, int column) * public Object getValueAt(Object node, int column) */ } /* * The contents of this file are subject to the Sapient Public License * Version 1.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://carbon.sf.net/License.html. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is The Carbon Component Framework. * * The Initial Developer of the Original Code is Sapient Corporation * * Copyright (C) 2003 Sapient Corporation. All Rights Reserved. */ import java.util.EventObject; import javax.swing.CellEditor; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.EventListenerList; public class AbstractCellEditor implements CellEditor { protected EventListenerList listenerList = new EventListenerList(); public Object getCellEditorValue() { return null; } public boolean isCellEditable(EventObject e) { return true; } public boolean shouldSelectCell(EventObject anEvent) { return false; } public boolean stopCellEditing() { return true; } public void cancelCellEditing() {} public void addCellEditorListener(CellEditorListener l) { listenerList.add(CellEditorListener.class, l); } public void removeCellEditorListener(CellEditorListener l) { listenerList.remove(CellEditorListener.class, l); } /* * Notify all listeners that have registered interest for * notification on this event type. * @see EventListenerList */ protected void fireEditingStopped() { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==CellEditorListener.class) { ((CellEditorListener)listeners[i+1]).editingStopped(new ChangeEvent(this)); } } } /* * Notify all listeners that have registered interest for * notification on this event type. * @see EventListenerList */ protected void fireEditingCanceled() { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==CellEditorListener.class) { ((CellEditorListener)listeners[i+1]).editingCanceled(new ChangeEvent(this)); } } } }
Auto Complete TextField
import java.awt.Color; import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collections; import javax.swing.JComboBox; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.plaf.basic.BasicComboBoxEditor; /** * A JTextField that will display a whole word as the user types a portion of * it. A better example would be, as the user types the first letter in the * word "text" the AutoCompleteTextField will display the letter "t" in the * components current foreground color and display the rest of the word "ext" * in the specified incomplete color (default is Color.GRAY.brighter()). The * displayed text changes as the user types "e" so now getText() would return * the string "te" and the incomplete portion displayed by the editor will be * "xt." If Enter is pressed while an incomplete word is being processes, then * the AutoCompleteTextField will replace what he user has typed with the * completed word and consider itself "finished," and if Enter is pressed a * second time, then it will fire a KeyEvent normally. * @author Brandon Buck * @version 1.0 */ public class AutoCompleteTextField extends JTextField implements KeyListener, DocumentListener { private ArrayList<String> possibilities; private int currentGuess; private Color incompleteColor; private boolean areGuessing; private boolean caseSensitive; /** * Constructs a new AutoCompleteTextField with the 5 columns by default and * no case sensitivity on comparisons of guesses to entered text. */ public AutoCompleteTextField() { this(5, false); } /** * Constructs a new AutoCompleteTextField with the specified number of * columns with no case sensitivity when comparing the current guess to the * text entered. * @param columns The number of columns you wish for the width of this AutoCompleteTextField. */ public AutoCompleteTextField(int columns) { this(columns, false); } /** * Creates a new AutoCompleteTextField with the given number of columns in * width and the setting for case sensitivity when comparing the current * guess to the entered text. * @param columns The number of columns of text for this component. * @param caseSensitive <code>true</code> or <code>false</code> depending on if you want comparisons to be case sensitive or not. */ public AutoCompleteTextField(int columns, boolean caseSensitive) { super.setColumns(columns); this.possibilities = new ArrayList<String>(); this.incompleteColor = Color.GRAY.brighter(); this.currentGuess = -1; this.areGuessing = false; this.caseSensitive = caseSensitive; this.addKeyListener(this); this.getDocument().addDocumentListener(this); } /** Add a new possibility to the list of possibilities. * Add a new possibility to the list of possibilities for the * AutoCommpleteTextField to process. * @param possibility The new possibility to add. */ public void addPossibility(String possibility) { this.possibilities.add(possibility); Collections.sort(possibilities); } /** Removes a possibility from the list of possibilities. * Removes the given possibility from the list of possibilities so that it * will no longer be matched. * @param possibility The possibility to remove. */ public void removePossibility(String possibility) { this.possibilities.remove(possibility); } /** Removes all possibilities in the list. * Removes every possibility in the list and starts over with an empty list * ready for new possibilities to be added. */ public void removeAllPossibilities() { this.possibilities = new ArrayList<String>(); } /** Sets the color to draw the incomplete guess in. * This sets the color that the incomplete guess text is drawn in. * @param incompleteColor The new color to draw the incomplete guess with. */ public void setIncompleteColor(Color incompleteColor) { this.incompleteColor = incompleteColor; } /** Returns the current guess from the list of possibilities. * Returns the string at the location of the current guess in the list of * possibilities. * @return The current guess as a String. */ private String getCurrentGuess() { if (this.currentGuess != -1) return this.possibilities.get(this.currentGuess); return this.getText(); } /** * Changes the current case sensitive setting to the given setting. * @param caseSensitive <code>true</code> or <code>false</code> depending on if you want comparisons to be case sensitive or not. */ public void setCaseSensitive(boolean caseSensitive) { this.caseSensitive = caseSensitive; } private void findCurrentGuess() { String entered = this.getText(); if (!this.caseSensitive) entered = entered.toLowerCase(); for (int i = 0; i < this.possibilities.size(); i++) { currentGuess = -1; String possibility = this.possibilities.get(i); if (!this.caseSensitive) possibility = possibility.toLowerCase(); if (possibility.startsWith(entered)) { this.currentGuess = i; break; } } } @Override public void setText(String text) { super.setText(text); this.areGuessing = false; this.currentGuess = -1; } @Override public void paintComponent(Graphics g) { String guess = this.getCurrentGuess(); String drawGuess = guess; super.paintComponent(g); String entered = this.getText(); Rectangle2D enteredBounds = g.getFontMetrics().getStringBounds(entered, g); if (!(this.caseSensitive)) { entered = entered.toLowerCase(); guess = guess.toLowerCase(); } if (!(guess.startsWith(entered))) this.areGuessing = false; if (entered != null && !(entered.equals("")) && this.areGuessing) { String subGuess = drawGuess.substring(entered.length(), drawGuess.length()); Rectangle2D subGuessBounds = g.getFontMetrics().getStringBounds(drawGuess, g); int centeredY = ((getHeight() / 2) + (int)(subGuessBounds.getHeight() / 2)); g.setColor(this.incompleteColor); g.drawString(subGuess + " press ENTER to send or \u2192 to fill", (int)(enteredBounds.getWidth()) + 2, centeredY - 2); } } public void keyTyped(KeyEvent e) { } public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { if (this.areGuessing) { this.setText(this.getCurrentGuess()); this.areGuessing = false; } } if (e.getKeyCode() == KeyEvent.VK_RIGHT) { if (this.areGuessing) { this.setText(this.getCurrentGuess()); this.areGuessing = false; e.consume(); } } } public void keyReleased(KeyEvent e) { } public void insertUpdate(DocumentEvent e) { String temp = this.getText(); if (temp.length() == 1) this.areGuessing = true; if (this.areGuessing) this.findCurrentGuess(); } public void removeUpdate(DocumentEvent e) { String temp = this.getText(); if (!(this.areGuessing)) this.areGuessing = true; if (temp.length() == 0) this.areGuessing = false; else if (this.areGuessing) { this.findCurrentGuess(); } } public void changedUpdate(DocumentEvent e) { } }
A button which paints on it one or more scaled arrows in one of the cardinal directions
//Revised from greef ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Graphics; import javax.swing.Icon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumnModel; /** * A button which paints on it one or more scaled arrows in one of the cardinal directions. * @author Adrian BER */ public class ArrowIcon implements Icon { /** The cardinal direction of the arrow(s). */ private int direction; /** The number of arrows. */ private int arrowCount; /** The arrow size. */ private int arrowSize; public ArrowIcon(int direction, int arrowCount, int arrowSize) { this.direction = direction; this.arrowCount = arrowCount; this.arrowSize = arrowSize; } /** Returns the cardinal direction of the arrow(s). * @see #setDirection(int) */ public int getDirection() { return direction; } /** Sets the cardinal direction of the arrow(s). * @param direction the direction of the arrow(s), can be SwingConstants.NORTH, * SwingConstants.SOUTH, SwingConstants.WEST or SwingConstants.EAST * @see #getDirection() */ public void setDirection(int direction) { this.direction = direction; } /** Returns the number of arrows. */ public int getArrowCount() { return arrowCount; } /** Sets the number of arrows. */ public void setArrowCount(int arrowCount) { this.arrowCount = arrowCount; } /** Returns the arrow size. */ public int getArrowSize() { return arrowSize; } /** Sets the arrow size. */ public void setArrowSize(int arrowSize) { this.arrowSize = arrowSize; } public void paintIcon(Component c, Graphics g, int x, int y) { // paint the arrows int w = getIconWidth(); int h = getIconHeight(); for (int i = 0; i < arrowCount; i++) { paintArrow(g, (x + w - arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? arrowCount : 1)) / 2 + arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? i : 0), (y + h - arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? 1 : arrowCount)) / 2 + arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? 0 : i) ); } } public int getIconWidth() { return arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? arrowCount : 3); } public int getIconHeight() { return arrowSize * (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH ? arrowCount : 3); } private void paintArrow(Graphics g, int x, int y) { int mid, i, j; j = 0; arrowSize = Math.max(arrowSize, 2); mid = (arrowSize / 2) - 1; g.translate(x, y); switch (direction) { case SwingConstants.NORTH: for (i = 0; i < arrowSize; i++) { g.drawLine(mid - i, i, mid + i, i); } break; case SwingConstants.SOUTH: j = 0; for (i = arrowSize - 1; i >= 0; i--) { g.drawLine(mid - i, j, mid + i, j); j++; } break; case SwingConstants.WEST: for (i = 0; i < arrowSize; i++) { g.drawLine(i, mid - i, i, mid + i); } break; case SwingConstants.EAST: j = 0; for (i = arrowSize - 1; i >= 0; i--) { g.drawLine(j, mid - i, j, mid + i); j++; } break; } g.translate(-x, -y); } }
Arrow Button
import javax.swing.*; import java.awt.*; /** * A button which paints on it one or more scaled arrows in one of the cardinal directions. * @author Adrian BER */ public class ArrowButton extends JButton { /** The cardinal direction of the arrow(s). */ private int direction; /** The number of arrows. */ private int arrowCount; /** The arrow size. */ private int arrowSize; public ArrowButton(int direction, int arrowCount, int arrowSize) { setMargin(new Insets(0, 2, 0, 2)); setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); this.direction = direction; this.arrowCount = arrowCount; this.arrowSize = arrowSize; } /** Returns the cardinal direction of the arrow(s). * @see #setDirection(int) */ public int getDirection() { return direction; } /** Sets the cardinal direction of the arrow(s). * @param direction the direction of the arrow(s), can be SwingConstants.NORTH, * SwingConstants.SOUTH, SwingConstants.WEST or SwingConstants.EAST * @see #getDirection() */ public void setDirection(int direction) { this.direction = direction; } /** Returns the number of arrows. */ public int getArrowCount() { return arrowCount; } /** Sets the number of arrows. */ public void setArrowCount(int arrowCount) { this.arrowCount = arrowCount; } /** Returns the arrow size. */ public int getArrowSize() { return arrowSize; } /** Sets the arrow size. */ public void setArrowSize(int arrowSize) { this.arrowSize = arrowSize; } public Dimension getPreferredSize() { return getMinimumSize(); } public Dimension getMinimumSize() { return new Dimension( arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? arrowCount : 3) + getBorder().getBorderInsets(this).left + getBorder().getBorderInsets(this).right , arrowSize * (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH ? arrowCount : 3) + getBorder().getBorderInsets(this).top + getBorder().getBorderInsets(this).bottom ); } public Dimension getMaximumSize() { return getMinimumSize(); } protected void paintComponent(Graphics g) { // this will paint the background super.paintComponent(g); Color oldColor = g.getColor(); g.setColor(isEnabled() ? getForeground() : getForeground().brighter()); // paint the arrows int w = getSize().width; int h = getSize().height; for (int i = 0; i < arrowCount; i++) { paintArrow(g, (w - arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? arrowCount : 1)) / 2 + arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? i : 0), (h - arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? 1 : arrowCount)) / 2 + arrowSize * (direction == SwingConstants.EAST || direction == SwingConstants.WEST ? 0 : i), g.getColor()); } g.setColor(oldColor); } private void paintArrow(Graphics g, int x, int y, Color highlight) { int mid, i, j; Color oldColor = g.getColor(); boolean isEnabled = isEnabled(); j = 0; arrowSize = Math.max(arrowSize, 2); mid = (arrowSize / 2) - 1; g.translate(x, y); switch (direction) { case NORTH: for (i = 0; i < arrowSize; i++) { g.drawLine(mid - i, i, mid + i, i); } if(!isEnabled) { g.setColor(highlight); g.drawLine(mid-i+2, i, mid+i, i); } break; case SOUTH: if (!isEnabled) { g.translate(1, 1); g.setColor(highlight); for (i = arrowSize - 1; i >= 0; i--) { g.drawLine(mid - i, j, mid + i, j); j++; } g.translate(-1, -1); g.setColor(oldColor); } j = 0; for (i = arrowSize - 1; i >= 0; i--) { g.drawLine(mid - i, j, mid + i, j); j++; } break; case WEST: for (i = 0; i < arrowSize; i++) { g.drawLine(i, mid - i, i, mid + i); } if(!isEnabled) { g.setColor(highlight); g.drawLine(i, mid-i+2, i, mid+i); } break; case EAST: if(!isEnabled) { g.translate(1, 1); g.setColor(highlight); for(i = arrowSize-1; i >= 0; i--) { g.drawLine(j, mid-i, j, mid+i); j++; } g.translate(-1, -1); g.setColor(oldColor); } j = 0; for (i = arrowSize - 1; i >= 0; i--) { g.drawLine(j, mid - i, j, mid + i); j++; } break; } g.translate(-x, -y); g.setColor(oldColor); } }
The various table charting classes
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.plaf.ComponentUI; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; public class ChartTester extends JFrame { public ChartTester() { super("Simple JTable Test"); setSize(300, 200); setDefaultCloseOperation(EXIT_ON_CLOSE); TableModel tm = new AbstractTableModel() { String data[][] = { { "Ron", "0.00", "68.68", "77.34", "78.02" }, { "Ravi", "0.00", "70.89", "64.17", "75.00" }, { "Maria", "76.52", "71.12", "75.68", "74.14" }, { "James", "70.00", "15.72", "26.40", "38.32" }, { "Ellen", "80.32", "78.16", "83.80", "85.72" } }; String headers[] = { "", "Q1", "Q2", "Q3", "Q4" }; public int getColumnCount() { return headers.length; } public int getRowCount() { return data.length; } public String getColumnName(int col) { return headers[col]; } public Class getColumnClass(int col) { return (col == 0) ? String.class : Number.class; } public boolean isCellEditable(int row, int col) { return true; } public Object getValueAt(int row, int col) { return data[row][col]; } public void setValueAt(Object value, int row, int col) { data[row][col] = (String) value; fireTableRowsUpdated(row, row); } }; JTable jt = new JTable(tm); JScrollPane jsp = new JScrollPane(jt); getContentPane().add(jsp, BorderLayout.CENTER); final TableChartPopup tcp = new TableChartPopup(tm); JButton button = new JButton("Show me a chart of this table"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { tcp.setVisible(true); } }); getContentPane().add(button, BorderLayout.SOUTH); } public static void main(String args[]) { ChartTester ct = new ChartTester(); ct.setVisible(true); } } //TableChartPopup.java //A popup framework for showing a chart of table data. This class also //turns on tooltips for the chart. // class TableChartPopup extends JFrame { public TableChartPopup(TableModel tm) { super("Table Chart"); setSize(300, 200); TableChart tc = new TableChart(tm); getContentPane().add(tc, BorderLayout.CENTER); // Use the next line to turn on tooltips: ToolTipManager.sharedInstance().registerComponent(tc); } } //TableChart.java //A chart-generating class that uses the TableModel interface to get //its data. // class TableChart extends JComponent implements TableModelListener { protected TableModel model; protected ChartPainter cp; protected double[] percentages; // pie slices protected String[] labels; // labels for slices protected String[] tips; // tooltips for slices protected java.text.NumberFormat formatter = java.text.NumberFormat .getPercentInstance(); public TableChart(TableModel tm) { setUI(cp = new PieChartPainter()); setModel(tm); } public void setTextFont(Font f) { cp.setTextFont(f); } public Font getTextFont() { return cp.getTextFont(); } public void setTextColor(Color c) { cp.setTextColor(c); } public Color getTextColor() { return cp.getTextColor(); } public void setColor(Color[] clist) { cp.setColor(clist); } public Color[] getColor() { return cp.getColor(); } public void setColor(int index, Color c) { cp.setColor(index, c); } public Color getColor(int index) { return cp.getColor(index); } public String getToolTipText(MouseEvent me) { if (tips != null) { int whichTip = cp.indexOfEntryAt(me); if (whichTip != -1) { return tips[whichTip]; } } return null; } public void tableChanged(TableModelEvent tme) { // Rebuild the arrays only if the structure changed. updateLocalValues(tme.getType() != TableModelEvent.UPDATE); } public void setModel(TableModel tm) { // get listener code correct. if (tm != model) { if (model != null) { model.removeTableModelListener(this); } model = tm; model.addTableModelListener(this); updateLocalValues(true); } } public TableModel getModel() { return model; } // Run through the model and count every cell (except the very first column, // which we assume is the slice label column). protected void calculatePercentages() { double runningTotal = 0.0; for (int i = model.getRowCount() - 1; i >= 0; i--) { percentages[i] = 0.0; for (int j = model.getColumnCount() - 1; j >= 0; j--) { // First try the cell as a Number object. Object val = model.getValueAt(i, j); if (val instanceof Number) { percentages[i] += ((Number) val).doubleValue(); } else if (val instanceof String) { // oops, it wasn't numeric... // Ok, so try it as a string try { percentages[i] += Double.valueOf(val.toString()) .doubleValue(); } catch (Exception e) { // not a numeric string...give up. } } } runningTotal += percentages[i]; } // Make each entry a percentage of the total. for (int i = model.getRowCount() - 1; i >= 0; i--) { percentages[i] /= runningTotal; } } // This method just takes the percentages and formats them for use as // tooltips. protected void createLabelsAndTips() { for (int i = model.getRowCount() - 1; i >= 0; i--) { labels[i] = (String) model.getValueAt(i, 0); tips[i] = formatter.format(percentages[i]); } } // Call this method to update the chart. We try to be a bit efficient here // in that we allocate new storage arrays only if the new table has a // different number of rows. protected void updateLocalValues(boolean freshStart) { if (freshStart) { int count = model.getRowCount(); if ((tips == null) || (count != tips.length)) { percentages = new double[count]; labels = new String[count]; tips = new String[count]; } } calculatePercentages(); createLabelsAndTips(); // Now that everything's up-to-date, reset the chart painter with the // new // values. cp.setValues(percentages); cp.setLabels(labels); // Finally, repaint the chart. repaint(); } } //PieChartPainter.java //A pie chart implementation of the ChartPainter class. // class PieChartPainter extends ChartPainter { protected static PieChartPainter chartUI = new PieChartPainter(); protected int originX, originY; protected int radius; private static double piby2 = Math.PI / 2.0; private static double twopi = Math.PI * 2.0; private static double d2r = Math.PI / 180.0; // Degrees to radians. private static int xGap = 5; private static int inset = 40; public int indexOfEntryAt(MouseEvent me) { int x = me.getX() - originX; int y = originY - me.getY(); // Upside-down coordinate system. // Is (x,y) in the circle? if (Math.sqrt(x * x + y * y) > radius) { return -1; } double percent = Math.atan2(Math.abs(y), Math.abs(x)); if (x >= 0) { if (y <= 0) { // (IV) percent = (piby2 - percent) + 3 * piby2; // (IV) } } else { if (y >= 0) { // (II) percent = Math.PI - percent; } else { // (III) percent = Math.PI + percent; } } percent /= twopi; double t = 0.0; if (values != null) { for (int i = 0; i < values.length; i++) { if (t + values[i] > percent) { return i; } t += values[i]; } } return -1; } public void paint(Graphics g, JComponent c) { Dimension size = c.getSize(); originX = size.width / 2; originY = size.height / 2; int diameter = (originX < originY ? size.width - inset : size.height - inset); radius = (diameter / 2) + 1; int cornerX = (originX - (diameter / 2)); int cornerY = (originY - (diameter / 2)); int startAngle = 0; int arcAngle = 0; for (int i = 0; i < values.length; i++) { arcAngle = (int) (i < values.length - 1 ? Math .round(values[i] * 360) : 360 - startAngle); g.setColor(colors[i % colors.length]); g.fillArc(cornerX, cornerY, diameter, diameter, startAngle, arcAngle); drawLabel(g, labels[i], startAngle + (arcAngle / 2)); startAngle += arcAngle; } g.setColor(Color.black); g.drawOval(cornerX, cornerY, diameter, diameter); // Cap the circle. } public void drawLabel(Graphics g, String text, double angle) { g.setFont(textFont); g.setColor(textColor); double radians = angle * d2r; int x = (int) ((radius + xGap) * Math.cos(radians)); int y = (int) ((radius + xGap) * Math.sin(radians)); if (x < 0) { x -= SwingUtilities.computeStringWidth(g.getFontMetrics(), text); } if (y < 0) { y -= g.getFontMetrics().getHeight(); } g.drawString(text, x + originX, originY - y); } public static ComponentUI createUI(JComponent c) { return chartUI; } } //ChartPainter.java //A simple chart-drawing UI base class. This class tracks the basic fonts //and colors for various types of charts including pie and bar. The paint() //method is abstract and must be implemented by subclasses for each type. // abstract class ChartPainter extends ComponentUI { protected Font textFont = new Font("Serif", Font.PLAIN, 12); protected Color textColor = Color.black; protected Color colors[] = new Color[] { Color.red, Color.blue, Color.yellow, Color.black, Color.green, Color.white, Color.gray, Color.cyan, Color.magenta, Color.darkGray }; protected double values[] = new double[0]; protected String labels[] = new String[0]; public void setTextFont(Font f) { textFont = f; } public Font getTextFont() { return textFont; } public void setColor(Color[] clist) { colors = clist; } public Color[] getColor() { return colors; } public void setColor(int index, Color c) { colors[index] = c; } public Color getColor(int index) { return colors[index]; } public void setTextColor(Color c) { textColor = c; } public Color getTextColor() { return textColor; } public void setLabels(String[] l) { labels = l; } public void setValues(double[] v) { values = v; } public abstract int indexOfEntryAt(MouseEvent me); public abstract void paint(Graphics g, JComponent c); }
A panel from where you can choose a color based on it's HTML name
import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.lang.reflect.Field; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.swing.Icon; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.UIManager; import javax.swing.colorchooser.AbstractColorChooserPanel; /** * This is a panel from where you can choose a color based on it's HTML name. * This panel was designed to be integrated in JColorChooser component. * <blockquote><code> * JColorChooser colorChooser = new JColorChooser(); * colorChooser.addChooserPanel(new HTMLColorsChooserPanel()); * </code></blockquote> * @author Adrian Ber * @see HTMLColors */ public class HTMLColorsChooserPanel extends AbstractColorChooserPanel { /** The name of this color chooser panel; will appear as the tab name * in the color chooser */ private String displayName; /** The name displayed for a color without a HTML name */ private String nonHTMLColorDisplayName; /** the color chooser in which is included this panel. */ private JColorChooser parent = null; /** The combo box filled with the HTML color names */ private JComboBox colorsComboBox = new JComboBox(); /** The label in front of the HTML color combo box. */ private JLabel colorLabel; public HTMLColorsChooserPanel() { this("HTML Names", "<Custom>"); } public HTMLColorsChooserPanel(String displayName) { this(displayName, "<Custom>"); } public HTMLColorsChooserPanel(String displayName, String nonHTMlColorDisplayName) { this.displayName = displayName; this.nonHTMLColorDisplayName = nonHTMlColorDisplayName; buildChooser(); } public Icon getSmallDisplayIcon() { return null; } public void updateChooser() { if (parent != null) { String x = HTMLColors.getName(getColorFromModel()); if (x == null) x = nonHTMLColorDisplayName; colorsComboBox.setSelectedItem(x); } } public String getDisplayName() { return displayName; } public Icon getLargeDisplayIcon() { return null; } /** Initializes this color chooser components. */ protected void buildChooser() { setLayout(new BorderLayout()); colorsComboBox.addItem(nonHTMLColorDisplayName); for (String color : HTMLColors.colors()) { colorsComboBox.addItem(color); } colorsComboBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { if (parent == null) return; Object name = colorsComboBox.getSelectedItem(); if ((name != null) && (!name.toString().equals(nonHTMLColorDisplayName))) { parent.setColor(HTMLColors.getColor(name.toString())); } } }); colorLabel = new JLabel(getColorLabelText()); add(colorLabel, BorderLayout.WEST); add(colorsComboBox, BorderLayout.CENTER); } private String getColorLabelText() { String x = UIManager.getString("HTMLColorsChooserPanel.colorLabel"); if (x == null) { x = "HTML Color:"; } return x; } public void installChooserPanel(JColorChooser enclosingChooser) { parent = enclosingChooser; super.installChooserPanel(enclosingChooser); } public void updateUI() { super.updateUI(); if (colorLabel != null) colorLabel.setText(getColorLabelText()); } } class HTMLColors { /** Don't instantiate this, use only the static methods */ private HTMLColors() { } /** map between color names and colors; * tough there are fields for every color we use a map because is a faster * way to get the color */ private static Map<String, Color> name2color = new HashMap<String, Color>(); /** map between colors and color names; * tough there are fields for every color we use a map because is a faster * way to get the color */ private static Map<Color, String> color2name = new HashMap<Color, String>(); /** Initialiase colors map */ private static void initColorsMap() { Field[] fields = HTMLColors.class.getFields(); for (Field field : fields) { if (field.getType().isAssignableFrom(Color.class)) { addColor(field.getName()); } } } /** Used to initialize the map */ private static void addColor(String colorName, Color color) { name2color.put(colorName, color); color2name.put(color, colorName); } /** Used to initialize the map */ private static void addColor(String colorName) { addColor(colorName, getColorFromField(colorName)); } /** Used to initialize the map */ private static void addColor(String colorName, int colorRGB) { addColor(colorName, new Color(colorRGB)); } /** Returns a color with the specified case-insensitive name. */ private static Color getColorFromField(String name) { try { Field colorField = HTMLColors.class.getField(name.toLowerCase()); return (Color) colorField.get(HTMLColors.class); } catch (NoSuchFieldException exc) { } catch (SecurityException exc) { } catch (IllegalAccessException exc) { } catch (IllegalArgumentException exc) { } return null; } /** Returns a color with the specified case-insensitive name.*/ public static String getName(Color color) { return color2name.get(color); } /** Returns a color with the specified case-insensitive name.*/ public static Color getColor(String name) { return name2color.get(name.toLowerCase()); } /** Returns a collection of all color names */ public static Collection<String> colors() { return name2color.keySet(); } /** Transform a color string into a color object. * @param s the color string * @return the color object */ public static Color decodeColor(String s) { if (s == null) return null; Color c; try { c = Color.decode(s); } catch (NumberFormatException exc) { c = HTMLColors.getColor(s); } return c; } public static final Color aliceblue = new Color(0xf0f8ff); public static final Color antiquewhite = new Color(0xfaebd7); public static final Color aqua = new Color(0x00ffff); public static final Color aquamarine = new Color(0x7fffd4); public static final Color azure = new Color(0xf0ffff); public static final Color beige = new Color(0xf5f5dc); public static final Color bisque = new Color(0xffe4c4); public static final Color black = new Color(0x000000); public static final Color blanchedalmond = new Color(0xffebcd); public static final Color blue = new Color(0x0000ff); public static final Color blueviolet = new Color(0x8a2be2); public static final Color brown = new Color(0xa52a2a); public static final Color burlywood = new Color(0xdeb887); public static final Color cadetblue = new Color(0x5f9ea0); public static final Color chartreuse = new Color(0x7fff00); public static final Color chocolate = new Color(0xd2691e); public static final Color coral = new Color(0xff7f50); public static final Color cornflowerblue = new Color(0x6495ed); public static final Color cornsilk = new Color(0xfff8dc); public static final Color crimson = new Color(0xdc143c); public static final Color cyan = new Color(0x00ffff); public static final Color darkblue = new Color(0x00008b); public static final Color darkcyan = new Color(0x008b8b); public static final Color darkgoldenrod = new Color(0xb8860b); public static final Color darkgray = new Color(0xa9a9a9); public static final Color darkgreen = new Color(0x006400); public static final Color darkkhaki = new Color(0xbdb76b); public static final Color darkmagenta = new Color(0x8b008b); public static final Color darkolivegreen = new Color(0x556b2f); public static final Color darkorange = new Color(0xff8c00); public static final Color darkorchid = new Color(0x9932cc); public static final Color darkred = new Color(0x8b0000); public static final Color darksalmon = new Color(0xe9967a); public static final Color darkseagreen = new Color(0x8fbc8f); public static final Color darkslateblue = new Color(0x483d8b); public static final Color darkslategray = new Color(0x2f4f4f); public static final Color darkturquoise = new Color(0x00ced1); public static final Color darkviolet = new Color(0x9400d3); public static final Color deeppink = new Color(0xff1493); public static final Color deepskyblue = new Color(0x00bfff); public static final Color dimgray = new Color(0x696969); public static final Color dodgerblue = new Color(0x1e90ff); public static final Color firebrick = new Color(0xb22222); public static final Color floralwhite = new Color(0xfffaf0); public static final Color forestgreen = new Color(0x228b22); public static final Color fuchsia = new Color(0xff00ff); public static final Color gainsboro = new Color(0xdcdcdc); public static final Color ghostwhite = new Color(0xf8f8ff); public static final Color gold = new Color(0xffd700); public static final Color goldenrod = new Color(0xdaa520); public static final Color gray = new Color(0x808080); public static final Color green = new Color(0x008000); public static final Color greenyellow = new Color(0xadff2f); public static final Color honeydew = new Color(0xf0fff0); public static final Color hotpink = new Color(0xff69b4); public static final Color indianred = new Color(0xcd5c5c); public static final Color indigo = new Color(0x4b0082); public static final Color ivory = new Color(0xfffff0); public static final Color khaki = new Color(0xf0e68c); public static final Color lavender = new Color(0xe6e6fa); public static final Color lavenderblush = new Color(0xfff0f5); public static final Color lawngreen = new Color(0x7cfc00); public static final Color lemonchiffon = new Color(0xfffacd); public static final Color lightblue = new Color(0xadd8e6); public static final Color lightcoral = new Color(0xf08080); public static final Color lightcyan = new Color(0xe0ffff); public static final Color lightgoldenrodyellow = new Color(0xfafad2); public static final Color lightgreen = new Color(0x90ee90); public static final Color lightgrey = new Color(0xd3d3d3); public static final Color lightpink = new Color(0xffb6c1); public static final Color lightsalmon = new Color(0xffa07a); public static final Color lightseagreen = new Color(0x20b2aa); public static final Color lightskyblue = new Color(0x87cefa); public static final Color lightslategray = new Color(0x778899); public static final Color lightsteelblue = new Color(0xb0c4de); public static final Color lightyellow = new Color(0xffffe0); public static final Color lime = new Color(0x00ff00); public static final Color limegreen = new Color(0x32cd32); public static final Color linen = new Color(0xfaf0e6); public static final Color magenta = new Color(0xff00ff); public static final Color maroon = new Color(0x800000); public static final Color mediumaquamarine = new Color(0x66cdaa); public static final Color mediumblue = new Color(0x0000cd); public static final Color mediumorchid = new Color(0xba55d3); public static final Color mediumpurple = new Color(0x9370db); public static final Color mediumseagreen = new Color(0x3cb371); public static final Color mediumslateblue = new Color(0x7b68ee); public static final Color mediumspringgreen = new Color(0x00fa9a); public static final Color mediumturquoise = new Color(0x48d1cc); public static final Color mediumvioletred = new Color(0xc71585); public static final Color midnightblue = new Color(0x191970); public static final Color mintcream = new Color(0xf5fffa); public static final Color mistyrose = new Color(0xffe4e1); public static final Color moccasin = new Color(0xffe4b5); public static final Color navajowhite = new Color(0xffdead); public static final Color navy = new Color(0x000080); public static final Color oldlace = new Color(0xfdf5e6); public static final Color olive = new Color(0x808000); public static final Color olivedrab = new Color(0x6b8e23); public static final Color orange = new Color(0xffa500); public static final Color orangered = new Color(0xff4500); public static final Color orchid = new Color(0xda70d6); public static final Color palegoldenrod = new Color(0xeee8aa); public static final Color palegreen = new Color(0x98fb98); public static final Color paleturquoise = new Color(0xafeeee); public static final Color palevioletred = new Color(0xdb7093); public static final Color papayawhip = new Color(0xffefd5); public static final Color peachpuff = new Color(0xffdab9); public static final Color peru = new Color(0xcd853f); public static final Color pink = new Color(0xffc0cb); public static final Color plum = new Color(0xdda0dd); public static final Color powderblue = new Color(0xb0e0e6); public static final Color purple = new Color(0x800080); public static final Color red = new Color(0xff0000); public static final Color rosybrown = new Color(0xbc8f8f); public static final Color royalblue = new Color(0x4169e1); public static final Color saddlebrown = new Color(0x8b4513); public static final Color salmon = new Color(0xfa8072); public static final Color sandybrown = new Color(0xf4a460); public static final Color seagreen = new Color(0x2e8b57); public static final Color seashell = new Color(0xfff5ee); public static final Color sienna = new Color(0xa0522d); public static final Color silver = new Color(0xc0c0c0); public static final Color skyblue = new Color(0x87ceeb); public static final Color slateblue = new Color(0x6a5acd); public static final Color slategray = new Color(0x708090); public static final Color snow = new Color(0xfffafa); public static final Color springgreen = new Color(0x00ff7f); public static final Color steelblue = new Color(0x4682b4); public static final Color tan = new Color(0xd2b48c); public static final Color teal = new Color(0x008080); public static final Color thistle = new Color(0xd8bfd8); public static final Color tomato = new Color(0xff6347); public static final Color turquoise = new Color(0x40e0d0); public static final Color violet = new Color(0xee82ee); public static final Color wheat = new Color(0xf5deb3); public static final Color white = new Color(0xffffff); public static final Color whitesmoke = new Color(0xf5f5f5); public static final Color yellow = new Color(0xffff00); public static final Color yellowgreen = new Color(0x9acd32); static { initColorsMap(); } }
A JOutlookBar provides a component that is similar to a JTabbedPane, but instead of maintaining tabs
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; /** * A JOutlookBar provides a component that is similar to a JTabbedPane, but * instead of maintaining tabs, it uses Outlook-style bars to control the * visible component */ public class JAccordion extends JPanel implements ActionListener { private static final long serialVersionUID = -2760245005186933366L; /** * The top panel: contains the buttons displayed on the top of the * JOutlookBar */ private JPanel topPanel = new JPanel(new GridLayout(1, 1)); /** * The bottom panel: contains the buttons displayed on the bottom of the * JOutlookBar */ private JPanel bottomPanel = new JPanel(new GridLayout(1, 1)); /** * A LinkedHashMap of bars: we use a linked hash map to preserve the order * of the bars */ private Map<String, BarInfo> bars = new LinkedHashMap<String, BarInfo>(); /** * The currently visible bar (zero-based index) */ private int visibleBar = 0; /** * A place-holder for the currently visible component */ private JComponent visibleComponent = null; /** * Creates a new JOutlookBar; after which you should make repeated calls to * addBar() for each bar */ public JAccordion() { this.setLayout(new BorderLayout()); this.add(topPanel, BorderLayout.NORTH); this.add(bottomPanel, BorderLayout.SOUTH); } /** * Adds the specified component to the JOutlookBar and sets the bar's name * * @param name * The name of the outlook bar * @param componenet * The component to add to the bar */ public void addBar(String name, JComponent component) { BarInfo barInfo = new BarInfo(name, component); barInfo.getButton().addActionListener(this); this.bars.put(name, barInfo); render(); } /** * Adds the specified component to the JOutlookBar and sets the bar's name * * @param name * The name of the outlook bar * @param icon * An icon to display in the outlook bar * @param componenet * The component to add to the bar */ public void addBar(String name, Icon icon, JComponent component) { BarInfo barInfo = new BarInfo(name, icon, component); barInfo.getButton().addActionListener(this); this.bars.put(name, barInfo); render(); } /** * Removes the specified bar from the JOutlookBar * * @param name * The name of the bar to remove */ public void removeBar(String name) { this.bars.remove(name); render(); } /** * Returns the index of the currently visible bar (zero-based) * * @return The index of the currently visible bar */ public int getVisibleBar() { return this.visibleBar; } /** * Programmatically sets the currently visible bar; the visible bar index * must be in the range of 0 to size() - 1 * * @param visibleBar * The zero-based index of the component to make visible */ public void setVisibleBar(int visibleBar) { if (visibleBar > 0 && visibleBar < this.bars.size() - 1) { this.visibleBar = visibleBar; render(); } } /** * Causes the outlook bar component to rebuild itself; this means that it * rebuilds the top and bottom panels of bars as well as making the * currently selected bar's panel visible */ public void render() { // Compute how many bars we are going to have where int totalBars = this.bars.size(); int topBars = this.visibleBar + 1; int bottomBars = totalBars - topBars; // Get an iterator to walk through out bars with Iterator<String> itr = this.bars.keySet().iterator(); // Render the top bars: remove all components, reset the GridLayout to // hold to correct number of bars, add the bars, and "validate" it to // cause it to re-layout its components this.topPanel.removeAll(); GridLayout topLayout = (GridLayout) this.topPanel.getLayout(); topLayout.setRows(topBars); BarInfo barInfo = null; for (int i = 0; i < topBars; i++) { String barName = (String) itr.next(); barInfo = (BarInfo) this.bars.get(barName); this.topPanel.add(barInfo.getButton()); } this.topPanel.validate(); // Render the center component: remove the current component (if there // is one) and then put the visible component in the center of this // panel if (this.visibleComponent != null) { this.remove(this.visibleComponent); } this.visibleComponent = barInfo.getComponent(); this.add(visibleComponent, BorderLayout.CENTER); // Render the bottom bars: remove all components, reset the GridLayout // to // hold to correct number of bars, add the bars, and "validate" it to // cause it to re-layout its components this.bottomPanel.removeAll(); GridLayout bottomLayout = (GridLayout) this.bottomPanel.getLayout(); bottomLayout.setRows(bottomBars); for (int i = 0; i < bottomBars; i++) { String barName = (String) itr.next(); barInfo = (BarInfo) this.bars.get(barName); this.bottomPanel.add(barInfo.getButton()); } this.bottomPanel.validate(); // Validate all of our components: cause this container to re-layout its // subcomponents validate(); } /** * Invoked when one of our bars is selected */ public void actionPerformed(ActionEvent e) { int currentBar = 0; for (Iterator<String> i = this.bars.keySet().iterator(); i.hasNext();) { String barName = (String) i.next(); BarInfo barInfo = (BarInfo) this.bars.get(barName); if (barInfo.getButton() == e.getSource()) { // Found the selected button this.visibleBar = currentBar; render(); return; } currentBar++; } } /** * Debug, dummy method */ public static JPanel getDummyPanel(String name) { JPanel panel = new JPanel(new BorderLayout()); panel.add(new JLabel(name, JLabel.CENTER)); return panel; } /** * Debug test... */ public static void main(String[] args) { JFrame frame = new JFrame("JOutlookBar Test"); JAccordion outlookBar = new JAccordion(); outlookBar.addBar("One", getDummyPanel("Onexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxo")); outlookBar.addBar("Two", getDummyPanel("Two")); outlookBar.addBar("Three", getDummyPanel("Three")); outlookBar.addBar("Four", getDummyPanel("Four")); outlookBar.addBar("Five", getDummyPanel("Five")); outlookBar.setVisibleBar(2); // outlookBar.setPreferredSize(new Dimension(400, 400)); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(outlookBar, BorderLayout.CENTER); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); frame.setLocation(d.width / 2 - 400, d.height / 2 - 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } /** * Internal class that maintains information about individual Outlook bars; * specifically it maintains the following information: * * name The name of the bar button The associated JButton for the bar * component The component maintained in the Outlook bar */ class BarInfo { /** * The name of this bar */ private String name; /** * The JButton that implements the Outlook bar itself */ private JButton button; /** * The component that is the body of the Outlook bar */ private JComponent component; /** * Creates a new BarInfo * * @param name * The name of the bar * @param component * The component that is the body of the Outlook Bar */ public BarInfo(String name, JComponent component) { this.name = name; this.component = component; this.button = new JButton(name); } /** * Creates a new BarInfo * * @param name * The name of the bar * @param icon * JButton icon * @param component * The component that is the body of the Outlook Bar */ public BarInfo(String name, Icon icon, JComponent component) { this.name = name; this.component = component; this.button = new JButton(name, icon); } /** * Returns the name of the bar * * @return The name of the bar */ public String getName() { return this.name; } /** * Sets the name of the bar * * @param The * name of the bar */ public void setName(String name) { this.name = name; } /** * Returns the outlook bar JButton implementation * * @return The Outlook Bar JButton implementation */ public JButton getButton() { return this.button; } /** * Returns the component that implements the body of this Outlook Bar * * @return The component that implements the body of this Outlook Bar */ public JComponent getComponent() { return this.component; } } }
Another Link button
import java.awt.AlphaComposite; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Composite; import java.awt.Cursor; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ButtonModel; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonUI; import javax.swing.plaf.basic.BasicGraphicsUtils; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; /** * A button targeted to be used as an hyperlink. Most UI will make it * transparent and it will react on mouse over by changing the cursor to the * hand cursor. * * @javabean.class name="JLinkButton" shortDescription="A button looking as an * hyperlink." stopClass="java.awt.Component" * * @javabean.attribute name="isContainer" value="Boolean.FALSE" rtexpr="true" * * @javabean.icons mono16="JLinkButton16-mono.gif" color16="JLinkButton16.gif" * mono32="JLinkButton32-mono.gif" color32="JLinkButton32.gif" */ public class AnotherLinkButton extends JButton { public AnotherLinkButton() { super(); } public AnotherLinkButton(String text) { super(text); } public AnotherLinkButton(String text, Icon icon) { super(text, icon); } public AnotherLinkButton(Action a) { super(a); } public AnotherLinkButton(Icon icon) { super(icon); } public void updateUI() { setUI(new WindowsLinkButtonUI()); } public static void main(String[] args) throws Exception { JFrame frame = new JFrame("JLinkButton"); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add("Center", new AnotherLinkButton("www.java2s.com")); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocation(100, 100); frame.setVisible(true); } } class BasicLinkButtonUI extends BasicButtonUI { public static ComponentUI createUI(JComponent c) { return new BasicLinkButtonUI(); } private static Rectangle viewRect = new Rectangle(); private static Rectangle textRect = new Rectangle(); private static Rectangle iconRect = new Rectangle(); private static MouseListener handCursorListener = new HandCursor(); protected int dashedRectGapX; protected int dashedRectGapY; protected int dashedRectGapWidth; protected int dashedRectGapHeight; private Color focusColor; protected void installDefaults(AbstractButton b) { super.installDefaults(b); b.setOpaque(false); b.setBorderPainted(false); b.setRolloverEnabled(true); dashedRectGapX = UIManager.getInt("ButtonUI.dashedRectGapX"); dashedRectGapY = UIManager.getInt("ButtonUI.dashedRectGapY"); dashedRectGapWidth = UIManager.getInt("ButtonUI.dashedRectGapWidth"); dashedRectGapHeight = UIManager.getInt("ButtonUI.dashedRectGapHeight"); focusColor = UIManager.getColor("ButtonUI.focus"); b.setHorizontalAlignment(AbstractButton.LEFT); } protected void installListeners(AbstractButton b) { super.installListeners(b); b.addMouseListener(handCursorListener); } protected void uninstallListeners(AbstractButton b) { super.uninstallListeners(b); b.removeMouseListener(handCursorListener); } protected Color getFocusColor() { return focusColor; } public void paint(Graphics g, JComponent c) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); FontMetrics fm = g.getFontMetrics(); Insets i = c.getInsets(); viewRect.x = i.left; viewRect.y = i.top; viewRect.width = b.getWidth() - (i.right + viewRect.x); viewRect.height = b.getHeight() - (i.bottom + viewRect.y); textRect.x = textRect.y = textRect.width = textRect.height = 0; iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0; Font f = c.getFont(); g.setFont(f); // layout the text and icon String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), b .getIcon(), b.getVerticalAlignment(), b .getHorizontalAlignment(), b.getVerticalTextPosition(), b .getHorizontalTextPosition(), viewRect, iconRect, textRect, b .getText() == null ? 0 : b.getIconTextGap()); clearTextShiftOffset(); // perform UI specific press action, e.g. Windows L&F shifts text if (model.isArmed() && model.isPressed()) { paintButtonPressed(g, b); } // Paint the Icon if (b.getIcon() != null) { paintIcon(g, c, iconRect); } Composite oldComposite = ((Graphics2D) g).getComposite(); if (model.isRollover()) { ((Graphics2D) g).setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f)); } if (text != null && !text.equals("")) { View v = (View) c.getClientProperty(BasicHTML.propertyKey); if (v != null) { textRect.x += getTextShiftOffset(); textRect.y += getTextShiftOffset(); v.paint(g, textRect); textRect.x -= getTextShiftOffset(); textRect.y -= getTextShiftOffset(); } else { paintText(g, b, textRect, text); } } if (b.isFocusPainted() && b.hasFocus()) { // paint UI specific focus paintFocus(g, b, viewRect, textRect, iconRect); } ((Graphics2D) g).setComposite(oldComposite); } protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { if (b.getParent() instanceof JToolBar) { // Windows doesn't draw the focus rect for buttons in a toolbar. return; } // focus painted same color as text int width = b.getWidth(); int height = b.getHeight(); g.setColor(getFocusColor()); BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, width - dashedRectGapWidth, height - dashedRectGapHeight); } protected void paintButtonPressed(Graphics g, AbstractButton b) { setTextShiftOffset(); } static class HandCursor extends MouseAdapter { public void mouseEntered(MouseEvent e) { e.getComponent().setCursor( Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } public void mouseExited(MouseEvent e) { e.getComponent().setCursor(Cursor.getDefaultCursor()); } } } class WindowsLinkButtonUI extends BasicLinkButtonUI { private static WindowsLinkButtonUI buttonUI = new WindowsLinkButtonUI(); public static ComponentUI createUI(JComponent c) { return buttonUI; } protected void paintButtonPressed(Graphics g, AbstractButton b) { setTextShiftOffset(); } }
import java.awt.Color; import java.awt.Cursor; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Rectangle; import java.net.URL; import javax.swing.Action; import javax.swing.ButtonModel; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.metal.MetalButtonUI; public class JLinkButton extends JButton { private static final String uiString = "LinkButtonUI"; public static final int ALWAYS_UNDERLINE = 0; public static final int HOVER_UNDERLINE = 1; public static final int NEVER_UNDERLINE = 2; public static final int SYSTEM_DEFAULT = 3; private int linkBehavior; private Color linkColor; private Color colorPressed; private Color visitedLinkColor; private Color disabledLinkColor; private URL buttonURL; private Action defaultAction; private boolean isLinkVisited; public static void main(String[] a) { JFrame f = new JFrame(); f.getContentPane().setLayout(new GridLayout(0,2)); f.getContentPane().add(new JLinkButton("www.java2s.com")); f.getContentPane().add(new JLinkButton("www.java2s.com/ExampleCode/CatalogExampleCode.htm")); f.setSize(600, 200); f.setVisible(true); } public JLinkButton() { this(null, null, null); } public JLinkButton(Action action) { this(); setAction(action); } public JLinkButton(Icon icon) { this(null, icon, null); } public JLinkButton(String s) { this(s, null, null); } public JLinkButton(URL url) { this(null, null, url); } public JLinkButton(String s, URL url) { this(s, null, url); } public JLinkButton(Icon icon, URL url) { this(null, icon, url); } public JLinkButton(String text, Icon icon, URL url) { super(text, icon); linkBehavior = SYSTEM_DEFAULT; linkColor = Color.blue; colorPressed = Color.red; visitedLinkColor = new Color(128, 0, 128); if (text == null && url != null) setText(url.toExternalForm()); setLinkURL(url); setCursor(Cursor.getPredefinedCursor(12)); setBorderPainted(false); setContentAreaFilled(false); setRolloverEnabled(true); addActionListener(defaultAction); } public void updateUI() { setUI(BasicLinkButtonUI.createUI(this)); } private void setDefault() { UIManager.getDefaults().put("LinkButtonUI", "BasicLinkButtonUI"); } public String getUIClassID() { return "LinkButtonUI"; } protected void setupToolTipText() { String tip = null; if (buttonURL != null) tip = buttonURL.toExternalForm(); setToolTipText(tip); } public void setLinkBehavior(int bnew) { checkLinkBehaviour(bnew); int old = linkBehavior; linkBehavior = bnew; firePropertyChange("linkBehavior", old, bnew); repaint(); } private void checkLinkBehaviour(int beha) { if (beha != ALWAYS_UNDERLINE && beha != HOVER_UNDERLINE && beha != NEVER_UNDERLINE && beha != SYSTEM_DEFAULT) throw new IllegalArgumentException("Not a legal LinkBehavior"); else return; } public int getLinkBehavior() { return linkBehavior; } public void setLinkColor(Color color) { Color colorOld = linkColor; linkColor = color; firePropertyChange("linkColor", colorOld, color); repaint(); } public Color getLinkColor() { return linkColor; } public void setActiveLinkColor(Color colorNew) { Color colorOld = colorPressed; colorPressed = colorNew; firePropertyChange("activeLinkColor", colorOld, colorNew); repaint(); } public Color getActiveLinkColor() { return colorPressed; } public void setDisabledLinkColor(Color color) { Color colorOld = disabledLinkColor; disabledLinkColor = color; firePropertyChange("disabledLinkColor", colorOld, color); if (!isEnabled()) repaint(); } public Color getDisabledLinkColor() { return disabledLinkColor; } public void setVisitedLinkColor(Color colorNew) { Color colorOld = visitedLinkColor; visitedLinkColor = colorNew; firePropertyChange("visitedLinkColor", colorOld, colorNew); repaint(); } public Color getVisitedLinkColor() { return visitedLinkColor; } public URL getLinkURL() { return buttonURL; } public void setLinkURL(URL url) { URL urlOld = buttonURL; buttonURL = url; setupToolTipText(); firePropertyChange("linkURL", urlOld, url); revalidate(); repaint(); } public void setLinkVisited(boolean flagNew) { boolean flagOld = isLinkVisited; isLinkVisited = flagNew; firePropertyChange("linkVisited", flagOld, flagNew); repaint(); } public boolean isLinkVisited() { return isLinkVisited; } public void setDefaultAction(Action actionNew) { Action actionOld = defaultAction; defaultAction = actionNew; firePropertyChange("defaultAction", actionOld, actionNew); } public Action getDefaultAction() { return defaultAction; } protected String paramString() { String str; if (linkBehavior == ALWAYS_UNDERLINE) str = "ALWAYS_UNDERLINE"; else if (linkBehavior == HOVER_UNDERLINE) str = "HOVER_UNDERLINE"; else if (linkBehavior == NEVER_UNDERLINE) str = "NEVER_UNDERLINE"; else str = "SYSTEM_DEFAULT"; String colorStr = linkColor == null ? "" : linkColor.toString(); String colorPressStr = colorPressed == null ? "" : colorPressed .toString(); String disabledLinkColorStr = disabledLinkColor == null ? "" : disabledLinkColor.toString(); String visitedLinkColorStr = visitedLinkColor == null ? "" : visitedLinkColor.toString(); String buttonURLStr = buttonURL == null ? "" : buttonURL.toString(); String isLinkVisitedStr = isLinkVisited ? "true" : "false"; return super.paramString() + ",linkBehavior=" + str + ",linkURL=" + buttonURLStr + ",linkColor=" + colorStr + ",activeLinkColor=" + colorPressStr + ",disabledLinkColor=" + disabledLinkColorStr + ",visitedLinkColor=" + visitedLinkColorStr + ",linkvisitedString=" + isLinkVisitedStr; } } class BasicLinkButtonUI extends MetalButtonUI { private static final BasicLinkButtonUI ui = new BasicLinkButtonUI(); public BasicLinkButtonUI() { } public static ComponentUI createUI(JComponent jcomponent) { return ui; } protected void paintText(Graphics g, JComponent com, Rectangle rect, String s) { JLinkButton bn = (JLinkButton) com; ButtonModel bnModel = bn.getModel(); Color color = bn.getForeground(); Object obj = null; if (bnModel.isEnabled()) { if (bnModel.isPressed()) bn.setForeground(bn.getActiveLinkColor()); else if (bn.isLinkVisited()) bn.setForeground(bn.getVisitedLinkColor()); else bn.setForeground(bn.getLinkColor()); } else { if (bn.getDisabledLinkColor() != null) bn.setForeground(bn.getDisabledLinkColor()); } super.paintText(g, com, rect, s); int behaviour = bn.getLinkBehavior(); boolean drawLine = false; if (behaviour == JLinkButton.HOVER_UNDERLINE) { if (bnModel.isRollover()) drawLine = true; } else if (behaviour == JLinkButton.ALWAYS_UNDERLINE || behaviour == JLinkButton.SYSTEM_DEFAULT) drawLine = true; if (!drawLine) return; FontMetrics fm = g.getFontMetrics(); int x = rect.x + getTextShiftOffset(); int y = (rect.y + fm.getAscent() + fm.getDescent() + getTextShiftOffset()) - 1; if (bnModel.isEnabled()) { g.setColor(bn.getForeground()); g.drawLine(x, y, (x + rect.width) - 1, y); } else { g.setColor(bn.getBackground().brighter()); g.drawLine(x, y, (x + rect.width) - 1, y); } } }
Separator Sample 2
import java.awt.Container; import java.awt.GridLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JSeparator; public class AnotherSeparatorSample { public static void main(String args[]) { JFrame f = new JFrame("JSeparator Sample"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container content = f.getContentPane(); content.setLayout(new GridLayout(0, 1)); JLabel above = new JLabel("Above Separator"); content.add(above); JSeparator separator = new JSeparator(); content.add(separator); JLabel below = new JLabel("Below Separator"); content.add(below); f.setSize(300, 100); f.setVisible(true); } }
Separator Sample
import java.awt.BorderLayout; import java.awt.Container; import javax.swing.JFrame; import javax.swing.JSeparator; public class SeparatorSample { public static void main(String args[]) { JFrame frame = new JFrame("Separator Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JSeparator north = new JSeparator(JSeparator.HORIZONTAL); JSeparator south = new JSeparator(JSeparator.VERTICAL); JSeparator east = new JSeparator(JSeparator.HORIZONTAL); JSeparator west = new JSeparator(JSeparator.VERTICAL); Container contentPane = frame.getContentPane(); contentPane.add(north, BorderLayout.NORTH); contentPane.add(south, BorderLayout.SOUTH); contentPane.add(east, BorderLayout.EAST); contentPane.add(west, BorderLayout.WEST); frame.setSize(350, 250); frame.setVisible(true); } }
A demonstration of the JSeparator() component used in a toolbar-like
import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSeparator; public class SeparatorExample extends JPanel { public SeparatorExample() { super(true); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); Box box1 = new Box(BoxLayout.X_AXIS); Box box2 = new Box(BoxLayout.X_AXIS); Box box3 = new Box(BoxLayout.X_AXIS); box1.add(new JButton("Press Me")); box1.add(new JButton("No Me!")); box1.add(new JButton("Ignore Them!")); box2.add(new JSeparator()); box3.add(new JButton("I'm the Button!")); box3.add(new JButton("It's me!")); box3.add(new JButton("Go Away!")); add(box1); add(box2); add(box3); } public static void main(String s[]) { SeparatorExample example = new SeparatorExample(); JFrame frame = new JFrame("Separator Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(example); frame.pack(); frame.setVisible(true); } }
Thumb Slider Example
import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.BoundedRangeModel; import javax.swing.DefaultBoundedRangeModel; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MouseInputAdapter; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSliderUI; import javax.swing.plaf.basic.BasicSliderUI.TrackListener; import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalSliderUI; /** * @version 1.0 9/3/99 */ public class MThumbSliderExample extends JFrame { public MThumbSliderExample() { super("MThumbSlider Example"); JSlider slider = new JSlider(); slider.putClientProperty("JSlider.isFilled", Boolean.TRUE); int n = 2; MThumbSlider mSlider = new MThumbSlider(n); mSlider.setValueAt(25, 0); mSlider.setValueAt(75, 1); mSlider.setFillColorAt(Color.green, 0); mSlider.setFillColorAt(Color.yellow, 1); mSlider.setTrackFillColor(Color.red); mSlider.putClientProperty("JSlider.isFilled", Boolean.TRUE); getContentPane().setLayout(new FlowLayout()); getContentPane().add(slider); getContentPane().add(mSlider); } public static void main(String args[]) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} MThumbSliderExample f = new MThumbSliderExample(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(300, 80); f.show(); } } class MThumbSlider extends JSlider { protected int thumbNum; protected BoundedRangeModel[] sliderModels; protected Icon[] thumbRenderers; protected Color[] fillColors; protected Color trackFillColor; private static final String uiClassID = "MThumbSliderUI"; public MThumbSlider(int n) { createThumbs(n); updateUI(); } protected void createThumbs(int n) { thumbNum = n; sliderModels = new BoundedRangeModel[n]; thumbRenderers = new Icon[n]; fillColors = new Color[n]; for (int i = 0; i < n; i++) { sliderModels[i] = new DefaultBoundedRangeModel(50, 0, 0, 100); thumbRenderers[i] = null; fillColors[i] = null; } } public void updateUI() { AssistantUIManager.setUIName(this); super.updateUI(); /* * // another way // updateLabelUIs(); * setUI(AssistantUIManager.createUI(this)); //setUI(new * BasicMThumbSliderUI(this)); //setUI(new MetalMThumbSliderUI(this)); * //setUI(new MotifMThumbSliderUI(this)); */ } public String getUIClassID() { return uiClassID; } public int getThumbNum() { return thumbNum; } public int getValueAt(int index) { return getModelAt(index).getValue(); } public void setValueAt(int n, int index) { getModelAt(index).setValue(n); // should I fire? } public int getMinimum() { return getModelAt(0).getMinimum(); } public int getMaximum() { return getModelAt(0).getMaximum(); } public BoundedRangeModel getModelAt(int index) { return sliderModels[index]; } public Icon getThumbRendererAt(int index) { return thumbRenderers[index]; } public void setThumbRendererAt(Icon icon, int index) { thumbRenderers[index] = icon; } public Color getFillColorAt(int index) { return fillColors[index]; } public void setFillColorAt(Color color, int index) { fillColors[index] = color; } public Color getTrackFillColor() { return trackFillColor; } public void setTrackFillColor(Color color) { trackFillColor = color; } } class MetalMThumbSliderUI extends MetalSliderUI implements MThumbSliderAdditional { MThumbSliderAdditionalUI additonalUi; MouseInputAdapter mThumbTrackListener; public static ComponentUI createUI(JComponent c) { return new MetalMThumbSliderUI((JSlider) c); } public MetalMThumbSliderUI() { //super(null); } public MetalMThumbSliderUI(JSlider b) { //super(null); } public void installUI(JComponent c) { additonalUi = new MThumbSliderAdditionalUI(this); additonalUi.installUI(c); mThumbTrackListener = createMThumbTrackListener((JSlider) c); super.installUI(c); } public void uninstallUI(JComponent c) { super.uninstallUI(c); additonalUi.uninstallUI(c); additonalUi = null; mThumbTrackListener = null; } protected MouseInputAdapter createMThumbTrackListener(JSlider slider) { return additonalUi.trackListener; } protected TrackListener createTrackListener(JSlider slider) { return null; } protected ChangeListener createChangeListener(JSlider slider) { return additonalUi.changeHandler; } protected void installListeners(JSlider slider) { slider.addMouseListener(mThumbTrackListener); slider.addMouseMotionListener(mThumbTrackListener); slider.addFocusListener(focusListener); slider.addComponentListener(componentListener); slider.addPropertyChangeListener(propertyChangeListener); slider.getModel().addChangeListener(changeListener); } protected void uninstallListeners(JSlider slider) { slider.removeMouseListener(mThumbTrackListener); slider.removeMouseMotionListener(mThumbTrackListener); slider.removeFocusListener(focusListener); slider.removeComponentListener(componentListener); slider.removePropertyChangeListener(propertyChangeListener); slider.getModel().removeChangeListener(changeListener); } protected void calculateGeometry() { super.calculateGeometry(); additonalUi.calculateThumbsSize(); additonalUi.calculateThumbsLocation(); } protected void calculateThumbLocation() { } Icon thumbRenderer; public void paint(Graphics g, JComponent c) { Rectangle clip = g.getClipBounds(); Rectangle[] thumbRects = additonalUi.getThumbRects(); thumbRect = thumbRects[0]; int thumbNum = additonalUi.getThumbNum(); if (slider.getPaintTrack() && clip.intersects(trackRect)) { boolean filledSlider_tmp = filledSlider; filledSlider = false; paintTrack(g); filledSlider = filledSlider_tmp; if (filledSlider) { g.translate(trackRect.x, trackRect.y); Point t1 = new Point(0, 0); Point t2 = new Point(0, 0); Rectangle maxThumbRect = new Rectangle(thumbRect); thumbRect = maxThumbRect; if (slider.getOrientation() == JSlider.HORIZONTAL) { t2.y = (trackRect.height - 1) - getThumbOverhang(); t1.y = t2.y - (getTrackWidth() - 1); t2.x = trackRect.width - 1; int maxPosition = xPositionForValue(slider.getMaximum()); thumbRect.x = maxPosition - (thumbRect.width / 2) - 2; thumbRect.y = trackRect.y; } else { t1.x = (trackRect.width - getThumbOverhang()) - getTrackWidth(); t2.x = (trackRect.width - getThumbOverhang()) - 1; t2.y = trackRect.height - 1; int maxPosition = yPositionForValue(slider.getMaximum()); thumbRect.x = trackRect.x; thumbRect.y = maxPosition - (thumbRect.height / 2) - 2; } Color fillColor = ((MThumbSlider) slider).getTrackFillColor(); if (fillColor == null) { fillColor = MetalLookAndFeel.getControlShadow(); } fillTrack(g, t1, t2, fillColor); for (int i = thumbNum - 1; 0 <= i; i--) { thumbRect = thumbRects[i]; fillColor = ((MThumbSlider) slider).getFillColorAt(i); if (fillColor == null) { fillColor = MetalLookAndFeel.getControlShadow(); } fillTrack(g, t1, t2, fillColor); } g.translate(-trackRect.x, -trackRect.y); } } if (slider.getPaintTicks() && clip.intersects(tickRect)) { paintTicks(g); } if (slider.getPaintLabels() && clip.intersects(labelRect)) { paintLabels(g); } for (int i = thumbNum - 1; 0 <= i; i--) { if (clip.intersects(thumbRects[i])) { thumbRect = thumbRects[i]; thumbRenderer = ((MThumbSlider) slider).getThumbRendererAt(i); if (thumbRenderer == null) { if (slider.getOrientation() == JSlider.HORIZONTAL) { thumbRenderer = horizThumbIcon; } else { thumbRenderer = vertThumbIcon; } } paintThumb(g); } } } public void paintThumb(Graphics g) { thumbRenderer.paintIcon(slider, g, thumbRect.x, thumbRect.y); } public void fillTrack(Graphics g, Point t1, Point t2, Color fillColor) { // t1------------------- // | | // --------------------t2 int middleOfThumb = 0; if (slider.getOrientation() == JSlider.HORIZONTAL) { middleOfThumb = thumbRect.x + (thumbRect.width / 2) - trackRect.x; if (slider.isEnabled()) { g.setColor(fillColor); g.fillRect(t1.x + 2, t1.y + 2, middleOfThumb - t1.x - 1, t2.y - t1.y - 3); g.setColor(fillColor.brighter()); g.drawLine(t1.x + 1, t1.y + 1, middleOfThumb, t1.y + 1); g.drawLine(t1.x + 1, t1.y + 1, t1.x + 1, t2.y - 2); } else { g.setColor(fillColor); g.fillRect(t1.x, t1.y, middleOfThumb - t1.x + 2, t2.y - t1.y); } } else { middleOfThumb = thumbRect.y + (thumbRect.height / 2) - trackRect.y; if (slider.isEnabled()) { g.setColor(slider.getBackground()); g.drawLine(t1.x + 1, middleOfThumb, t2.x - 2, middleOfThumb); g.drawLine(t1.x + 1, middleOfThumb, t1.x + 1, t2.y - 2); g.setColor(fillColor); g.fillRect(t1.x + 2, middleOfThumb + 1, t2.x - t1.x - 3, t2.y - 2 - middleOfThumb); } else { g.setColor(fillColor); g.fillRect(t1.x, middleOfThumb + 2, t2.x - 1 - t1.x, t2.y - t1.y); } } } public void scrollByBlock(int direction) { } public void scrollByUnit(int direction) { } // // MThumbSliderAdditional // public Rectangle getTrackRect() { return trackRect; } public Dimension getThumbSize() { return super.getThumbSize(); } public int xPositionForValue(int value) { return super.xPositionForValue(value); } public int yPositionForValue(int value) { return super.yPositionForValue(value); } } interface MThumbSliderAdditional { public Rectangle getTrackRect(); public Dimension getThumbSize(); public int xPositionForValue(int value); public int yPositionForValue(int value); } class MThumbSliderAdditionalUI { MThumbSlider mSlider; BasicSliderUI ui; Rectangle[] thumbRects; int thumbNum; private transient boolean isDragging; Icon thumbRenderer; Rectangle trackRect; ChangeHandler changeHandler; TrackListener trackListener; public MThumbSliderAdditionalUI(BasicSliderUI ui) { this.ui = ui; } public void installUI(JComponent c) { mSlider = (MThumbSlider) c; thumbNum = mSlider.getThumbNum(); thumbRects = new Rectangle[thumbNum]; for (int i = 0; i < thumbNum; i++) { thumbRects[i] = new Rectangle(); } isDragging = false; trackListener = new MThumbSliderAdditionalUI.TrackListener(mSlider); changeHandler = new ChangeHandler(); } public void uninstallUI(JComponent c) { thumbRects = null; trackListener = null; changeHandler = null; } protected void calculateThumbsSize() { Dimension size = ((MThumbSliderAdditional) ui).getThumbSize(); for (int i = 0; i < thumbNum; i++) { thumbRects[i].setSize(size.width, size.height); } } protected void calculateThumbsLocation() { for (int i = 0; i < thumbNum; i++) { if (mSlider.getSnapToTicks()) { int tickSpacing = mSlider.getMinorTickSpacing(); if (tickSpacing == 0) { tickSpacing = mSlider.getMajorTickSpacing(); } if (tickSpacing != 0) { int sliderValue = mSlider.getValueAt(i); int snappedValue = sliderValue; //int min = mSlider.getMinimumAt(i); int min = mSlider.getMinimum(); if ((sliderValue - min) % tickSpacing != 0) { float temp = (float) (sliderValue - min) / (float) tickSpacing; int whichTick = Math.round(temp); snappedValue = min + (whichTick * tickSpacing); mSlider.setValueAt(snappedValue, i); } } } trackRect = getTrackRect(); if (mSlider.getOrientation() == JSlider.HORIZONTAL) { int value = mSlider.getValueAt(i); int valuePosition = ((MThumbSliderAdditional) ui) .xPositionForValue(value); thumbRects[i].x = valuePosition - (thumbRects[i].width / 2); thumbRects[i].y = trackRect.y; } else { int valuePosition = ((MThumbSliderAdditional) ui) .yPositionForValue(mSlider.getValueAt(i)); // need thumbRects[i].x = trackRect.x; thumbRects[i].y = valuePosition - (thumbRects[i].height / 2); } } } public int getThumbNum() { return thumbNum; } public Rectangle[] getThumbRects() { return thumbRects; } private static Rectangle unionRect = new Rectangle(); public void setThumbLocationAt(int x, int y, int index) { Rectangle rect = thumbRects[index]; unionRect.setBounds(rect); rect.setLocation(x, y); SwingUtilities.computeUnion(rect.x, rect.y, rect.width, rect.height, unionRect); mSlider.repaint(unionRect.x, unionRect.y, unionRect.width, unionRect.height); } public Rectangle getTrackRect() { return ((MThumbSliderAdditional) ui).getTrackRect(); } public class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent e) { if (!isDragging) { calculateThumbsLocation(); mSlider.repaint(); } } } public class TrackListener extends MouseInputAdapter { protected transient int offset; protected transient int currentMouseX, currentMouseY; protected Rectangle adjustingThumbRect = null; protected int adjustingThumbIndex; protected MThumbSlider slider; protected Rectangle trackRect; TrackListener(MThumbSlider slider) { this.slider = slider; } public void mousePressed(MouseEvent e) { if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); slider.requestFocus(); for (int i = 0; i < thumbNum; i++) { Rectangle rect = thumbRects[i]; if (rect.contains(currentMouseX, currentMouseY)) { switch (slider.getOrientation()) { case JSlider.VERTICAL: offset = currentMouseY - rect.y; break; case JSlider.HORIZONTAL: offset = currentMouseX - rect.x; break; } isDragging = true; slider.setValueIsAdjusting(true); adjustingThumbRect = rect; adjustingThumbIndex = i; return; } } } public void mouseDragged(MouseEvent e) { if (!slider.isEnabled() || !isDragging || !slider.getValueIsAdjusting() || adjustingThumbRect == null) { return; } int thumbMiddle = 0; currentMouseX = e.getX(); currentMouseY = e.getY(); Rectangle rect = thumbRects[adjustingThumbIndex]; trackRect = getTrackRect(); switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = rect.height / 2; int thumbTop = e.getY() - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + (trackRect.height - 1); thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setThumbLocationAt(rect.x, thumbTop, adjustingThumbIndex); thumbMiddle = thumbTop + halfThumbHeight; mSlider.setValueAt(ui.valueForYPosition(thumbMiddle), adjustingThumbIndex); break; case JSlider.HORIZONTAL: int halfThumbWidth = rect.width / 2; int thumbLeft = e.getX() - offset; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setThumbLocationAt(thumbLeft, rect.y, adjustingThumbIndex); thumbMiddle = thumbLeft + halfThumbWidth; mSlider.setValueAt(ui.valueForXPosition(thumbMiddle), adjustingThumbIndex); break; } } public void mouseReleased(MouseEvent e) { if (!slider.isEnabled()) { return; } offset = 0; isDragging = false; mSlider.setValueIsAdjusting(false); mSlider.repaint(); } public boolean shouldScroll(int direction) { return false; } } } class AssistantUIManager { public static ComponentUI createUI(JComponent c) { String componentName = c.getClass().getName(); int index = componentName.lastIndexOf(".") + 1; StringBuffer sb = new StringBuffer(); sb.append(componentName.substring(0, index)); // // UIManager.getLookAndFeel().getName() // // [ Metal ] [ Motif ] [ Mac ] [ Windows ] // Metal CDE/Motif Macintosh Windows // String lookAndFeelName = UIManager.getLookAndFeel().getName(); if (lookAndFeelName.startsWith("CDE/")) { lookAndFeelName = lookAndFeelName.substring(4, lookAndFeelName .length()); } sb.append(lookAndFeelName); sb.append(componentName.substring(index)); sb.append("UI"); ComponentUI componentUI = getInstance(sb.toString()); if (componentUI == null) { sb.setLength(0); sb.append(componentName.substring(0, index)); sb.append("Basic"); sb.append(componentName.substring(index)); sb.append("UI"); componentUI = getInstance(sb.toString()); } return componentUI; } private static ComponentUI getInstance(String name) { try { return (ComponentUI) Class.forName(name).newInstance(); } catch (ClassNotFoundException ex) { } catch (IllegalAccessException ex) { ex.printStackTrace(); } catch (InstantiationException ex) { ex.printStackTrace(); } return null; } public static void setUIName(JComponent c) { String key = c.getUIClassID(); String uiClassName = (String) UIManager.get(key); if (uiClassName == null) { String componentName = c.getClass().getName(); int index = componentName.lastIndexOf(".") + 1; StringBuffer sb = new StringBuffer(); sb.append(componentName.substring(0, index)); String lookAndFeelName = UIManager.getLookAndFeel().getName(); if (lookAndFeelName.startsWith("CDE/")) { lookAndFeelName = lookAndFeelName.substring(4, lookAndFeelName .length()); } sb.append(lookAndFeelName); sb.append(key); UIManager.put(key, sb.toString()); } } public AssistantUIManager() { } }
Thumb Slider Example 1
import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.BoundedRangeModel; import javax.swing.DefaultBoundedRangeModel; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MouseInputAdapter; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSliderUI; import com.sun.java.swing.plaf.motif.MotifSliderUI; /** * @version 1.0 9/3/99 */ public class MThumbSliderExample1 extends JFrame { public MThumbSliderExample1() { super("MThumbSlider Example"); JSlider slider = new JSlider(); int n = 2; MThumbSlider mSlider = new MThumbSlider(n); mSlider.setValueAt(25, 0); mSlider.setValueAt(75, 1); getContentPane().setLayout(new FlowLayout()); getContentPane().add(slider); getContentPane().add(mSlider); } public static void main(String args[]) { try { UIManager .setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); } catch (Exception ex) { System.err.println("Error loading L&F: " + ex); } MThumbSliderExample1 f = new MThumbSliderExample1(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(300, 80); f.show(); } } class MThumbSlider extends JSlider { protected int thumbNum; protected BoundedRangeModel[] sliderModels; protected Icon[] thumbRenderers; protected Color[] fillColors; protected Color trackFillColor; private static final String uiClassID = "MThumbSliderUI"; public MThumbSlider(int n) { createThumbs(n); updateUI(); } protected void createThumbs(int n) { thumbNum = n; sliderModels = new BoundedRangeModel[n]; thumbRenderers = new Icon[n]; fillColors = new Color[n]; for (int i = 0; i < n; i++) { sliderModels[i] = new DefaultBoundedRangeModel(50, 0, 0, 100); thumbRenderers[i] = null; fillColors[i] = null; } } public void updateUI() { AssistantUIManager.setUIName(this); super.updateUI(); /* * // another way // updateLabelUIs(); * setUI(AssistantUIManager.createUI(this)); //setUI(new * BasicMThumbSliderUI(this)); //setUI(new MetalMThumbSliderUI(this)); * //setUI(new MotifMThumbSliderUI(this)); */ } public String getUIClassID() { return uiClassID; } public int getThumbNum() { return thumbNum; } public int getValueAt(int index) { return getModelAt(index).getValue(); } public void setValueAt(int n, int index) { getModelAt(index).setValue(n); // should I fire? } public int getMinimum() { return getModelAt(0).getMinimum(); } public int getMaximum() { return getModelAt(0).getMaximum(); } public BoundedRangeModel getModelAt(int index) { return sliderModels[index]; } public Icon getThumbRendererAt(int index) { return thumbRenderers[index]; } public void setThumbRendererAt(Icon icon, int index) { thumbRenderers[index] = icon; } public Color getFillColorAt(int index) { return fillColors[index]; } public void setFillColorAt(Color color, int index) { fillColors[index] = color; } public Color getTrackFillColor() { return trackFillColor; } public void setTrackFillColor(Color color) { trackFillColor = color; } } class MotifMThumbSliderUI extends MotifSliderUI implements MThumbSliderAdditional { MThumbSliderAdditionalUI additonalUi; MouseInputAdapter mThumbTrackListener; public static ComponentUI createUI(JComponent c) { return new MotifMThumbSliderUI((JSlider) c); } public MotifMThumbSliderUI() { super(null); } public MotifMThumbSliderUI(JSlider b) { super(b); } public void installUI(JComponent c) { additonalUi = new MThumbSliderAdditionalUI(this); additonalUi.installUI(c); mThumbTrackListener = createMThumbTrackListener((JSlider) c); super.installUI(c); } public void uninstallUI(JComponent c) { super.uninstallUI(c); additonalUi.uninstallUI(c); additonalUi = null; mThumbTrackListener = null; } protected MouseInputAdapter createMThumbTrackListener(JSlider slider) { return additonalUi.trackListener; } protected TrackListener createTrackListener(JSlider slider) { return null; } protected ChangeListener createChangeListener(JSlider slider) { return additonalUi.changeHandler; } protected void installListeners(JSlider slider) { slider.addMouseListener(mThumbTrackListener); slider.addMouseMotionListener(mThumbTrackListener); slider.addFocusListener(focusListener); slider.addComponentListener(componentListener); slider.addPropertyChangeListener(propertyChangeListener); slider.getModel().addChangeListener(changeListener); } protected void uninstallListeners(JSlider slider) { slider.removeMouseListener(mThumbTrackListener); slider.removeMouseMotionListener(mThumbTrackListener); slider.removeFocusListener(focusListener); slider.removeComponentListener(componentListener); slider.removePropertyChangeListener(propertyChangeListener); slider.getModel().removeChangeListener(changeListener); } protected void calculateGeometry() { super.calculateGeometry(); additonalUi.calculateThumbsSize(); additonalUi.calculateThumbsLocation(); } protected void calculateThumbLocation() { } Rectangle zeroRect = new Rectangle(); public void paint(Graphics g, JComponent c) { Rectangle clip = g.getClipBounds(); thumbRect = zeroRect; super.paint(g, c); int thumbNum = additonalUi.getThumbNum(); Rectangle[] thumbRects = additonalUi.getThumbRects(); for (int i = thumbNum - 1; 0 <= i; i--) { if (clip.intersects(thumbRects[i])) { thumbRect = thumbRects[i]; paintThumb(g); } } } protected void installKeyboardActions(JSlider slider) { } protected void uninstallKeyboardActions(JSlider slider) { } public void scrollByBlock(int direction) { } public void scrollByUnit(int direction) { } // // MThumbSliderAdditional // public Rectangle getTrackRect() { return trackRect; } public Dimension getThumbSize() { return super.getThumbSize(); } public int xPositionForValue(int value) { return super.xPositionForValue(value); } public int yPositionForValue(int value) { return super.yPositionForValue(value); } } interface MThumbSliderAdditional { public Rectangle getTrackRect(); public Dimension getThumbSize(); public int xPositionForValue(int value); public int yPositionForValue(int value); } class MThumbSliderAdditionalUI { MThumbSlider mSlider; BasicSliderUI ui; Rectangle[] thumbRects; int thumbNum; private transient boolean isDragging; Icon thumbRenderer; Rectangle trackRect; ChangeHandler changeHandler; TrackListener trackListener; public MThumbSliderAdditionalUI(BasicSliderUI ui) { this.ui = ui; } public void installUI(JComponent c) { mSlider = (MThumbSlider) c; thumbNum = mSlider.getThumbNum(); thumbRects = new Rectangle[thumbNum]; for (int i = 0; i < thumbNum; i++) { thumbRects[i] = new Rectangle(); } isDragging = false; trackListener = new MThumbSliderAdditionalUI.TrackListener(mSlider); changeHandler = new ChangeHandler(); } public void uninstallUI(JComponent c) { thumbRects = null; trackListener = null; changeHandler = null; } protected void calculateThumbsSize() { Dimension size = ((MThumbSliderAdditional) ui).getThumbSize(); for (int i = 0; i < thumbNum; i++) { thumbRects[i].setSize(size.width, size.height); } } protected void calculateThumbsLocation() { for (int i = 0; i < thumbNum; i++) { if (mSlider.getSnapToTicks()) { int tickSpacing = mSlider.getMinorTickSpacing(); if (tickSpacing == 0) { tickSpacing = mSlider.getMajorTickSpacing(); } if (tickSpacing != 0) { int sliderValue = mSlider.getValueAt(i); int snappedValue = sliderValue; //int min = mSlider.getMinimumAt(i); int min = mSlider.getMinimum(); if ((sliderValue - min) % tickSpacing != 0) { float temp = (float) (sliderValue - min) / (float) tickSpacing; int whichTick = Math.round(temp); snappedValue = min + (whichTick * tickSpacing); mSlider.setValueAt(snappedValue, i); } } } trackRect = getTrackRect(); if (mSlider.getOrientation() == JSlider.HORIZONTAL) { int value = mSlider.getValueAt(i); int valuePosition = ((MThumbSliderAdditional) ui) .xPositionForValue(value); thumbRects[i].x = valuePosition - (thumbRects[i].width / 2); thumbRects[i].y = trackRect.y; } else { int valuePosition = ((MThumbSliderAdditional) ui) .yPositionForValue(mSlider.getValueAt(i)); // need thumbRects[i].x = trackRect.x; thumbRects[i].y = valuePosition - (thumbRects[i].height / 2); } } } public int getThumbNum() { return thumbNum; } public Rectangle[] getThumbRects() { return thumbRects; } private static Rectangle unionRect = new Rectangle(); public void setThumbLocationAt(int x, int y, int index) { Rectangle rect = thumbRects[index]; unionRect.setBounds(rect); rect.setLocation(x, y); SwingUtilities.computeUnion(rect.x, rect.y, rect.width, rect.height, unionRect); mSlider.repaint(unionRect.x, unionRect.y, unionRect.width, unionRect.height); } public Rectangle getTrackRect() { return ((MThumbSliderAdditional) ui).getTrackRect(); } public class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent e) { if (!isDragging) { calculateThumbsLocation(); mSlider.repaint(); } } } public class TrackListener extends MouseInputAdapter { protected transient int offset; protected transient int currentMouseX, currentMouseY; protected Rectangle adjustingThumbRect = null; protected int adjustingThumbIndex; protected MThumbSlider slider; protected Rectangle trackRect; TrackListener(MThumbSlider slider) { this.slider = slider; } public void mousePressed(MouseEvent e) { if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); slider.requestFocus(); for (int i = 0; i < thumbNum; i++) { Rectangle rect = thumbRects[i]; if (rect.contains(currentMouseX, currentMouseY)) { switch (slider.getOrientation()) { case JSlider.VERTICAL: offset = currentMouseY - rect.y; break; case JSlider.HORIZONTAL: offset = currentMouseX - rect.x; break; } isDragging = true; slider.setValueIsAdjusting(true); adjustingThumbRect = rect; adjustingThumbIndex = i; return; } } } public void mouseDragged(MouseEvent e) { if (!slider.isEnabled() || !isDragging || !slider.getValueIsAdjusting() || adjustingThumbRect == null) { return; } int thumbMiddle = 0; currentMouseX = e.getX(); currentMouseY = e.getY(); Rectangle rect = thumbRects[adjustingThumbIndex]; trackRect = getTrackRect(); switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = rect.height / 2; int thumbTop = e.getY() - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + (trackRect.height - 1); thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setThumbLocationAt(rect.x, thumbTop, adjustingThumbIndex); thumbMiddle = thumbTop + halfThumbHeight; mSlider.setValueAt(ui.valueForYPosition(thumbMiddle), adjustingThumbIndex); break; case JSlider.HORIZONTAL: int halfThumbWidth = rect.width / 2; int thumbLeft = e.getX() - offset; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setThumbLocationAt(thumbLeft, rect.y, adjustingThumbIndex); thumbMiddle = thumbLeft + halfThumbWidth; mSlider.setValueAt(ui.valueForXPosition(thumbMiddle), adjustingThumbIndex); break; } } public void mouseReleased(MouseEvent e) { if (!slider.isEnabled()) { return; } offset = 0; isDragging = false; mSlider.setValueIsAdjusting(false); mSlider.repaint(); } public boolean shouldScroll(int direction) { return false; } } } class AssistantUIManager { public static ComponentUI createUI(JComponent c) { String componentName = c.getClass().getName(); int index = componentName.lastIndexOf(".") + 1; StringBuffer sb = new StringBuffer(); sb.append(componentName.substring(0, index)); // // UIManager.getLookAndFeel().getName() // // [ Metal ] [ Motif ] [ Mac ] [ Windows ] // Metal CDE/Motif Macintosh Windows // String lookAndFeelName = UIManager.getLookAndFeel().getName(); if (lookAndFeelName.startsWith("CDE/")) { lookAndFeelName = lookAndFeelName.substring(4, lookAndFeelName .length()); } sb.append(lookAndFeelName); sb.append(componentName.substring(index)); sb.append("UI"); ComponentUI componentUI = getInstance(sb.toString()); if (componentUI == null) { sb.setLength(0); sb.append(componentName.substring(0, index)); sb.append("Basic"); sb.append(componentName.substring(index)); sb.append("UI"); componentUI = getInstance(sb.toString()); } return componentUI; } private static ComponentUI getInstance(String name) { try { return (ComponentUI) Class.forName(name).newInstance(); } catch (ClassNotFoundException ex) { } catch (IllegalAccessException ex) { ex.printStackTrace(); } catch (InstantiationException ex) { ex.printStackTrace(); } return null; } public static void setUIName(JComponent c) { String key = c.getUIClassID(); String uiClassName = (String) UIManager.get(key); if (uiClassName == null) { String componentName = c.getClass().getName(); int index = componentName.lastIndexOf(".") + 1; StringBuffer sb = new StringBuffer(); sb.append(componentName.substring(0, index)); String lookAndFeelName = UIManager.getLookAndFeel().getName(); if (lookAndFeelName.startsWith("CDE/")) { lookAndFeelName = lookAndFeelName.substring(4, lookAndFeelName .length()); } sb.append(lookAndFeelName); sb.append(key); UIManager.put(key, sb.toString()); } } public AssistantUIManager() { } }
Thumb Slider Example 2
import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.BoundedRangeModel; import javax.swing.DefaultBoundedRangeModel; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MouseInputAdapter; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSliderUI; /** * @version 1.0 9/3/99 */ public class MThumbSliderExample2 extends JFrame { public MThumbSliderExample2() { super("MThumbSlider Example"); JSlider slider = new JSlider(); slider.setUI(new javax.swing.plaf.basic.BasicSliderUI(slider)); int n = 2; MThumbSlider mSlider = new MThumbSlider(n); mSlider.setValueAt(25, 0); mSlider.setValueAt(75, 1); mSlider.setUI(new BasicMThumbSliderUI()); getContentPane().setLayout(new FlowLayout()); getContentPane().add(slider); getContentPane().add(mSlider); } public static void main(String args[]) { try { UIManager .setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); } catch (Exception ex) { System.err.println("Error loading L&F: " + ex); } MThumbSliderExample2 f = new MThumbSliderExample2(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(300, 100); f.show(); } } class MThumbSlider extends JSlider { protected int thumbNum; protected BoundedRangeModel[] sliderModels; protected Icon[] thumbRenderers; protected Color[] fillColors; protected Color trackFillColor; private static final String uiClassID = "MThumbSliderUI"; public MThumbSlider(int n) { createThumbs(n); updateUI(); } protected void createThumbs(int n) { thumbNum = n; sliderModels = new BoundedRangeModel[n]; thumbRenderers = new Icon[n]; fillColors = new Color[n]; for (int i = 0; i < n; i++) { sliderModels[i] = new DefaultBoundedRangeModel(50, 0, 0, 100); thumbRenderers[i] = null; fillColors[i] = null; } } public void updateUI() { AssistantUIManager.setUIName(this); super.updateUI(); /* * // another way // updateLabelUIs(); * setUI(AssistantUIManager.createUI(this)); //setUI(new * BasicMThumbSliderUI(this)); //setUI(new MetalMThumbSliderUI(this)); * //setUI(new MotifMThumbSliderUI(this)); */ } public String getUIClassID() { return uiClassID; } public int getThumbNum() { return thumbNum; } public int getValueAt(int index) { return getModelAt(index).getValue(); } public void setValueAt(int n, int index) { getModelAt(index).setValue(n); // should I fire? } public int getMinimum() { return getModelAt(0).getMinimum(); } public int getMaximum() { return getModelAt(0).getMaximum(); } public BoundedRangeModel getModelAt(int index) { return sliderModels[index]; } public Icon getThumbRendererAt(int index) { return thumbRenderers[index]; } public void setThumbRendererAt(Icon icon, int index) { thumbRenderers[index] = icon; } public Color getFillColorAt(int index) { return fillColors[index]; } public void setFillColorAt(Color color, int index) { fillColors[index] = color; } public Color getTrackFillColor() { return trackFillColor; } public void setTrackFillColor(Color color) { trackFillColor = color; } } class BasicMThumbSliderUI extends BasicSliderUI implements MThumbSliderAdditional { MThumbSliderAdditionalUI additonalUi; MouseInputAdapter mThumbTrackListener; public static ComponentUI createUI(JComponent c) { return new BasicMThumbSliderUI((JSlider) c); } public BasicMThumbSliderUI() { super(null); } public BasicMThumbSliderUI(JSlider b) { super(b); } public void installUI(JComponent c) { additonalUi = new MThumbSliderAdditionalUI(this); additonalUi.installUI(c); mThumbTrackListener = createMThumbTrackListener((JSlider) c); super.installUI(c); } public void uninstallUI(JComponent c) { super.uninstallUI(c); additonalUi.uninstallUI(c); additonalUi = null; mThumbTrackListener = null; } protected MouseInputAdapter createMThumbTrackListener(JSlider slider) { return additonalUi.trackListener; } protected TrackListener createTrackListener(JSlider slider) { return null; } protected ChangeListener createChangeListener(JSlider slider) { return additonalUi.changeHandler; } protected void installListeners(JSlider slider) { slider.addMouseListener(mThumbTrackListener); slider.addMouseMotionListener(mThumbTrackListener); slider.addFocusListener(focusListener); slider.addComponentListener(componentListener); slider.addPropertyChangeListener(propertyChangeListener); slider.getModel().addChangeListener(changeListener); } protected void uninstallListeners(JSlider slider) { slider.removeMouseListener(mThumbTrackListener); slider.removeMouseMotionListener(mThumbTrackListener); slider.removeFocusListener(focusListener); slider.removeComponentListener(componentListener); slider.removePropertyChangeListener(propertyChangeListener); slider.getModel().removeChangeListener(changeListener); } protected void calculateGeometry() { super.calculateGeometry(); additonalUi.calculateThumbsSize(); additonalUi.calculateThumbsLocation(); } protected void calculateThumbLocation() { } Rectangle zeroRect = new Rectangle(); public void paint(Graphics g, JComponent c) { Rectangle clip = g.getClipBounds(); thumbRect = zeroRect; super.paint(g, c); int thumbNum = additonalUi.getThumbNum(); Rectangle[] thumbRects = additonalUi.getThumbRects(); for (int i = thumbNum - 1; 0 <= i; i--) { if (clip.intersects(thumbRects[i])) { thumbRect = thumbRects[i]; paintThumb(g); } } } public void scrollByBlock(int direction) { } public void scrollByUnit(int direction) { } // // MThumbSliderAdditional // public Rectangle getTrackRect() { return trackRect; } public Dimension getThumbSize() { return super.getThumbSize(); } public int xPositionForValue(int value) { return super.xPositionForValue(value); } public int yPositionForValue(int value) { return super.yPositionForValue(value); } } interface MThumbSliderAdditional { public Rectangle getTrackRect(); public Dimension getThumbSize(); public int xPositionForValue(int value); public int yPositionForValue(int value); } class MThumbSliderAdditionalUI { MThumbSlider mSlider; BasicSliderUI ui; Rectangle[] thumbRects; int thumbNum; private transient boolean isDragging; Icon thumbRenderer; Rectangle trackRect; ChangeHandler changeHandler; TrackListener trackListener; public MThumbSliderAdditionalUI(BasicSliderUI ui) { this.ui = ui; } public void installUI(JComponent c) { mSlider = (MThumbSlider) c; thumbNum = mSlider.getThumbNum(); thumbRects = new Rectangle[thumbNum]; for (int i = 0; i < thumbNum; i++) { thumbRects[i] = new Rectangle(); } isDragging = false; trackListener = new MThumbSliderAdditionalUI.TrackListener(mSlider); changeHandler = new ChangeHandler(); } public void uninstallUI(JComponent c) { thumbRects = null; trackListener = null; changeHandler = null; } protected void calculateThumbsSize() { Dimension size = ((MThumbSliderAdditional) ui).getThumbSize(); for (int i = 0; i < thumbNum; i++) { thumbRects[i].setSize(size.width, size.height); } } protected void calculateThumbsLocation() { for (int i = 0; i < thumbNum; i++) { if (mSlider.getSnapToTicks()) { int tickSpacing = mSlider.getMinorTickSpacing(); if (tickSpacing == 0) { tickSpacing = mSlider.getMajorTickSpacing(); } if (tickSpacing != 0) { int sliderValue = mSlider.getValueAt(i); int snappedValue = sliderValue; //int min = mSlider.getMinimumAt(i); int min = mSlider.getMinimum(); if ((sliderValue - min) % tickSpacing != 0) { float temp = (float) (sliderValue - min) / (float) tickSpacing; int whichTick = Math.round(temp); snappedValue = min + (whichTick * tickSpacing); mSlider.setValueAt(snappedValue, i); } } } trackRect = getTrackRect(); if (mSlider.getOrientation() == JSlider.HORIZONTAL) { int value = mSlider.getValueAt(i); int valuePosition = ((MThumbSliderAdditional) ui) .xPositionForValue(value); thumbRects[i].x = valuePosition - (thumbRects[i].width / 2); thumbRects[i].y = trackRect.y; } else { int valuePosition = ((MThumbSliderAdditional) ui) .yPositionForValue(mSlider.getValueAt(i)); // need thumbRects[i].x = trackRect.x; thumbRects[i].y = valuePosition - (thumbRects[i].height / 2); } } } public int getThumbNum() { return thumbNum; } public Rectangle[] getThumbRects() { return thumbRects; } private static Rectangle unionRect = new Rectangle(); public void setThumbLocationAt(int x, int y, int index) { Rectangle rect = thumbRects[index]; unionRect.setBounds(rect); rect.setLocation(x, y); SwingUtilities.computeUnion(rect.x, rect.y, rect.width, rect.height, unionRect); mSlider.repaint(unionRect.x, unionRect.y, unionRect.width, unionRect.height); } public Rectangle getTrackRect() { return ((MThumbSliderAdditional) ui).getTrackRect(); } public class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent e) { if (!isDragging) { calculateThumbsLocation(); mSlider.repaint(); } } } public class TrackListener extends MouseInputAdapter { protected transient int offset; protected transient int currentMouseX, currentMouseY; protected Rectangle adjustingThumbRect = null; protected int adjustingThumbIndex; protected MThumbSlider slider; protected Rectangle trackRect; TrackListener(MThumbSlider slider) { this.slider = slider; } public void mousePressed(MouseEvent e) { if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); slider.requestFocus(); for (int i = 0; i < thumbNum; i++) { Rectangle rect = thumbRects[i]; if (rect.contains(currentMouseX, currentMouseY)) { switch (slider.getOrientation()) { case JSlider.VERTICAL: offset = currentMouseY - rect.y; break; case JSlider.HORIZONTAL: offset = currentMouseX - rect.x; break; } isDragging = true; slider.setValueIsAdjusting(true); adjustingThumbRect = rect; adjustingThumbIndex = i; return; } } } public void mouseDragged(MouseEvent e) { if (!slider.isEnabled() || !isDragging || !slider.getValueIsAdjusting() || adjustingThumbRect == null) { return; } int thumbMiddle = 0; currentMouseX = e.getX(); currentMouseY = e.getY(); Rectangle rect = thumbRects[adjustingThumbIndex]; trackRect = getTrackRect(); switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = rect.height / 2; int thumbTop = e.getY() - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + (trackRect.height - 1); thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setThumbLocationAt(rect.x, thumbTop, adjustingThumbIndex); thumbMiddle = thumbTop + halfThumbHeight; mSlider.setValueAt(ui.valueForYPosition(thumbMiddle), adjustingThumbIndex); break; case JSlider.HORIZONTAL: int halfThumbWidth = rect.width / 2; int thumbLeft = e.getX() - offset; int trackLeft = trackRect.x; int trackRight = trackRect.x + (trackRect.width - 1); thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setThumbLocationAt(thumbLeft, rect.y, adjustingThumbIndex); thumbMiddle = thumbLeft + halfThumbWidth; mSlider.setValueAt(ui.valueForXPosition(thumbMiddle), adjustingThumbIndex); break; } } public void mouseReleased(MouseEvent e) { if (!slider.isEnabled()) { return; } offset = 0; isDragging = false; mSlider.setValueIsAdjusting(false); mSlider.repaint(); } public boolean shouldScroll(int direction) { return false; } } } class AssistantUIManager { public static ComponentUI createUI(JComponent c) { String componentName = c.getClass().getName(); int index = componentName.lastIndexOf(".") + 1; StringBuffer sb = new StringBuffer(); sb.append(componentName.substring(0, index)); // // UIManager.getLookAndFeel().getName() // // [ Metal ] [ Motif ] [ Mac ] [ Windows ] // Metal CDE/Motif Macintosh Windows // String lookAndFeelName = UIManager.getLookAndFeel().getName(); if (lookAndFeelName.startsWith("CDE/")) { lookAndFeelName = lookAndFeelName.substring(4, lookAndFeelName .length()); } sb.append(lookAndFeelName); sb.append(componentName.substring(index)); sb.append("UI"); ComponentUI componentUI = getInstance(sb.toString()); if (componentUI == null) { sb.setLength(0); sb.append(componentName.substring(0, index)); sb.append("Basic"); sb.append(componentName.substring(index)); sb.append("UI"); componentUI = getInstance(sb.toString()); } return componentUI; } private static ComponentUI getInstance(String name) { try { return (ComponentUI) Class.forName(name).newInstance(); } catch (ClassNotFoundException ex) { } catch (IllegalAccessException ex) { ex.printStackTrace(); } catch (InstantiationException ex) { ex.printStackTrace(); } return null; } public static void setUIName(JComponent c) { String key = c.getUIClassID(); String uiClassName = (String) UIManager.get(key); if (uiClassName == null) { String componentName = c.getClass().getName(); int index = componentName.lastIndexOf(".") + 1; StringBuffer sb = new StringBuffer(); sb.append(componentName.substring(0, index)); String lookAndFeelName = UIManager.getLookAndFeel().getName(); if (lookAndFeelName.startsWith("CDE/")) { lookAndFeelName = lookAndFeelName.substring(4, lookAndFeelName .length()); } sb.append(lookAndFeelName); sb.append(key); UIManager.put(key, sb.toString()); } } public AssistantUIManager() { } }
Slider With ToolTip Example
import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; /** * @version 1.0 10/4/99 */ public class SliderWithToolTipExample extends JFrame { public SliderWithToolTipExample() { super("Mad Level"); JSlider s = new JSlider(JSlider.VERTICAL, 0, 120, 60) { String[] tooltips = {"Call 911", "Seeing red", "Really mad", "Ticked off", "Slightly peeved", "Oh bother", "Feel good"}; public String getToolTipText(MouseEvent e) { Point p = e.getPoint(); Rectangle rect = new Rectangle(); rect = getBounds(rect); int n = getLabelTable().size(); int index = n * p.y / rect.height; return tooltips[index]; } }; s.setPaintTicks(true); s.setMajorTickSpacing(20); s.setPaintLabels( true ); s.putClientProperty( "JSlider.isFilled", Boolean.TRUE ); s.setToolTipText(""); getContentPane().setLayout(new FlowLayout()); getContentPane().add(s); } public static void main (String args[]) { SliderWithToolTipExample f = new SliderWithToolTipExample(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize (120, 250); f.show(); } }
A dialog that presents the user with a sequence of steps for completing a task.
import java.awt.BorderLayout; import java.awt.Container; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; /** * A dialog that presents the user with a sequence of steps for completing a * task. The dialog contains "Next" and "Previous" buttons, allowing the user to * navigate through the task. * <P> * When the user backs up by one or more steps, the dialog keeps the completed * steps so that they can be reused if the user doesn't change anything - this * handles the cases where the user backs up a few steps just to review what has * been completed. * <p> * But if the user changes some options in an earlier step, then the dialog may * have to discard the later steps and have them repeated. * <P> * THIS CLASS IS NOT WORKING CORRECTLY YET. * * * @author David Gilbert */ public class WizardDialog extends JDialog implements ActionListener { /** The end result of the wizard sequence. */ private Object result; /** The current step in the wizard process (starting at step zero). */ private int step; /** A reference to the current panel. */ private WizardPanel currentPanel; /** * A list of references to the panels the user has already seen - used for * navigating through the steps that have already been completed. */ private java.util.List panels; /** A handy reference to the "previous" button. */ private JButton previousButton; /** A handy reference to the "next" button. */ private JButton nextButton; /** A handy reference to the "finish" button. */ private JButton finishButton; /** A handy reference to the "help" button. */ private JButton helpButton; /** * Standard constructor - builds and returns a new WizardDialog. * * @param owner * the owner. * @param modal * modal? * @param title * the title. * @param firstPanel * the first panel. */ public WizardDialog(final JDialog owner, final boolean modal, final String title, final WizardPanel firstPanel) { super(owner, title + " : step 1", modal); this.result = null; this.currentPanel = firstPanel; this.step = 0; this.panels = new ArrayList(); this.panels.add(firstPanel); setContentPane(createContent()); } /** * Standard constructor - builds a new WizardDialog owned by the specified * JFrame. * * @param owner * the owner. * @param modal * modal? * @param title * the title. * @param firstPanel * the first panel. */ public WizardDialog(final JFrame owner, final boolean modal, final String title, final WizardPanel firstPanel) { super(owner, title + " : step 1", modal); this.result = null; this.currentPanel = firstPanel; this.step = 0; this.panels = new ArrayList(); this.panels.add(firstPanel); setContentPane(createContent()); } /** * Returns the result of the wizard sequence. * * @return the result. */ public Object getResult() { return this.result; } /** * Returns the total number of steps in the wizard sequence, if this number is * known. Otherwise this method returns zero. Subclasses should override this * method unless the number of steps is not known. * * @return the number of steps. */ public int getStepCount() { return 0; } /** * Returns true if it is possible to back up to the previous panel, and false * otherwise. * * @return boolean. */ public boolean canDoPreviousPanel() { return (this.step > 0); } /** * Returns true if there is a 'next' panel, and false otherwise. * * @return boolean. */ public boolean canDoNextPanel() { return this.currentPanel.hasNextPanel(); } /** * Returns true if it is possible to finish the sequence at this point * (possibly with defaults for the remaining entries). * * @return boolean. */ public boolean canFinish() { return this.currentPanel.canFinish(); } /** * Returns the panel for the specified step (steps are numbered from zero). * * @param step * the current step. * * @return the panel. */ public WizardPanel getWizardPanel(final int step) { if (step < this.panels.size()) { return (WizardPanel) this.panels.get(step); } else { return null; } } /** * Handles events. * * @param event * the event. */ public void actionPerformed(final ActionEvent event) { final String command = event.getActionCommand(); if (command.equals("nextButton")) { next(); } else if (command.equals("previousButton")) { previous(); } else if (command.equals("finishButton")) { finish(); } } /** * Handles a click on the "previous" button, by displaying the previous panel * in the sequence. */ public void previous() { if (this.step > 0) { final WizardPanel previousPanel = getWizardPanel(this.step - 1); // tell the panel that we are returning previousPanel.returnFromLaterStep(); final Container content = getContentPane(); content.remove(this.currentPanel); content.add(previousPanel); this.step = this.step - 1; this.currentPanel = previousPanel; setTitle("Step " + (this.step + 1)); enableButtons(); pack(); } } /** * Displays the next step in the wizard sequence. */ public void next() { WizardPanel nextPanel = getWizardPanel(this.step + 1); if (nextPanel != null) { if (!this.currentPanel.canRedisplayNextPanel()) { nextPanel = this.currentPanel.getNextPanel(); } } else { nextPanel = this.currentPanel.getNextPanel(); } this.step = this.step + 1; if (this.step < this.panels.size()) { this.panels.set(this.step, nextPanel); } else { this.panels.add(nextPanel); } final Container content = getContentPane(); content.remove(this.currentPanel); content.add(nextPanel); this.currentPanel = nextPanel; setTitle("Step " + (this.step + 1)); enableButtons(); pack(); } /** * Finishes the wizard. */ public void finish() { this.result = this.currentPanel.getResult(); setVisible(false); } /** * Enables/disables the buttons according to the current step. A good idea * would be to ask the panels to return the status... */ private void enableButtons() { this.previousButton.setEnabled(this.step > 0); this.nextButton.setEnabled(canDoNextPanel()); this.finishButton.setEnabled(canFinish()); this.helpButton.setEnabled(false); } /** * Checks, whether the user cancelled the dialog. * * @return false. */ public boolean isCancelled() { return false; } /** * Creates a panel containing the user interface for the dialog. * * @return the panel. */ public JPanel createContent() { final JPanel content = new JPanel(new BorderLayout()); content.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); content.add((JPanel) this.panels.get(0)); final L1R3ButtonPanel buttons = new L1R3ButtonPanel("Help", "Previous", "Next", "Finish"); this.helpButton = buttons.getLeftButton(); this.helpButton.setEnabled(false); this.previousButton = buttons.getRightButton1(); this.previousButton.setActionCommand("previousButton"); this.previousButton.addActionListener(this); this.previousButton.setEnabled(false); this.nextButton = buttons.getRightButton2(); this.nextButton.setActionCommand("nextButton"); this.nextButton.addActionListener(this); this.nextButton.setEnabled(true); this.finishButton = buttons.getRightButton3(); this.finishButton.setActionCommand("finishButton"); this.finishButton.addActionListener(this); this.finishButton.setEnabled(false); buttons.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); content.add(buttons, BorderLayout.SOUTH); return content; } } /* * JCommon : a free general purpose class library for the Java(tm) platform * * * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jcommon/index.html * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. in the * United States and other countries.] * * ---------------- WizardPanel.java ---------------- (C) Copyright 2000-2004, * by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited); Contributor(s): -; * * $Id: WizardPanel.java,v 1.5 2007/11/02 17:50:36 taqua Exp $ * * Changes (from 26-Oct-2001) -------------------------- 26-Oct-2001 : Changed * package to com.jrefinery.ui.*; 14-Oct-2002 : Fixed errors reported by * Checkstyle (DG); * */ /** * A panel that provides the user interface for a single step in a WizardDialog. * * @author David Gilbert */ abstract class WizardPanel extends JPanel { /** The owner. */ private WizardDialog owner; /** * Creates a new panel. * * @param layout * the layout manager. */ protected WizardPanel(final LayoutManager layout) { super(layout); } /** * Returns a reference to the dialog that owns the panel. * * @return the owner. */ public WizardDialog getOwner() { return this.owner; } /** * Sets the reference to the dialog that owns the panel (this is called * automatically by the dialog when the panel is added to the dialog). * * @param owner * the owner. */ public void setOwner(final WizardDialog owner) { this.owner = owner; } /** * Returns the result. * * @return the result. */ public Object getResult() { return null; } /** * This method is called when the dialog redisplays this panel as a result of * the user clicking the "Previous" button. Inside this method, subclasses * should make a note of their current state, so that they can decide what to * do when the user hits "Next". */ public abstract void returnFromLaterStep(); /** * Returns true if it is OK to redisplay the last version of the next panel, * or false if a new version is required. * * @return boolean. */ public abstract boolean canRedisplayNextPanel(); /** * Returns true if there is a next panel. * * @return boolean. */ public abstract boolean hasNextPanel(); /** * Returns true if it is possible to finish from this panel. * * @return boolean. */ public abstract boolean canFinish(); /** * Returns the next panel in the sequence, given the current user input. * Returns null if this panel is the last one in the sequence. * * @return the next panel in the sequence. */ public abstract WizardPanel getNextPanel(); } /* * JCommon : a free general purpose class library for the Java(tm) platform * * * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jcommon/index.html * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. in the * United States and other countries.] * * -------------------- L1R3ButtonPanel.java -------------------- (C) Copyright * 2000-2004, by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited); Contributor(s): -; * * $Id: L1R3ButtonPanel.java,v 1.5 2007/11/02 17:50:36 taqua Exp $ * * Changes (from 26-Oct-2001) -------------------------- 26-Oct-2001 : Changed * package to com.jrefinery.ui.* (DG); 26-Jun-2002 : Removed unnecessary import * (DG); 14-Oct-2002 : Fixed errors reported by Checkstyle (DG); * */ /** * A 'ready-made' panel that has one button on the left and three buttons on the * right - nested panels and layout managers take care of resizing. * * @author David Gilbert */ class L1R3ButtonPanel extends JPanel { /** The left button. */ private JButton left; /** The first button on the right of the panel. */ private JButton right1; /** The second button on the right of the panel. */ private JButton right2; /** The third button on the right of the panel. */ private JButton right3; /** * Standard constructor - creates panel with the specified button labels. * * @param label1 * the label for button 1. * @param label2 * the label for button 2. * @param label3 * the label for button 3. * @param label4 * the label for button 4. */ public L1R3ButtonPanel(final String label1, final String label2, final String label3, final String label4) { setLayout(new BorderLayout()); // create the pieces... final JPanel panel = new JPanel(new BorderLayout()); final JPanel panel2 = new JPanel(new BorderLayout()); this.left = new JButton(label1); this.right1 = new JButton(label2); this.right2 = new JButton(label3); this.right3 = new JButton(label4); // ...and put them together panel.add(this.left, BorderLayout.WEST); panel2.add(this.right1, BorderLayout.EAST); panel.add(panel2, BorderLayout.CENTER); panel.add(this.right2, BorderLayout.EAST); add(panel, BorderLayout.CENTER); add(this.right3, BorderLayout.EAST); } /** * Returns a reference to button 1, allowing the caller to set labels, * action-listeners etc. * * @return the left button. */ public JButton getLeftButton() { return this.left; } /** * Returns a reference to button 2, allowing the caller to set labels, * action-listeners etc. * * @return the right button 1. */ public JButton getRightButton1() { return this.right1; } /** * Returns a reference to button 3, allowing the caller to set labels, * action-listeners etc. * * @return the right button 2. */ public JButton getRightButton2() { return this.right2; } /** * Returns a reference to button 4, allowing the caller to set labels, * action-listeners etc. * * @return the right button 3. */ public JButton getRightButton3() { return this.right3; } }