Implemented a class for selecting among a mutually exclusive set of
buttons. git-svn-id: https://samskivert.googlecode.com/svn/trunk@644 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -0,0 +1,383 @@
|
||||
//
|
||||
// $Id: ComboButtonBox.java,v 1.1 2002/03/10 05:10:37 mdb Exp $
|
||||
|
||||
package com.samskivert.swing;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
|
||||
import com.samskivert.Log;
|
||||
|
||||
/**
|
||||
* Used to display a horizontal or vertical array of buttons, out of which
|
||||
* only one is selectable at a time (which will be represented by
|
||||
* rendering it with an indented border, whereas the other buttons will
|
||||
* render with an extruded border.
|
||||
*/
|
||||
public class ComboButtonBox extends JPanel
|
||||
implements SwingConstants, ListDataListener, MouseListener
|
||||
{
|
||||
/**
|
||||
* Constructs a button box with the specified orientation (either
|
||||
* {@link #HORIZONTAL} or {@link #VERTICAL}.
|
||||
*/
|
||||
public ComboButtonBox (int orientation)
|
||||
{
|
||||
this(orientation, new DefaultComboBoxModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a button box with the specified orientation (either
|
||||
* {@link #HORIZONTAL} or {@link #VERTICAL}. The supplied model will
|
||||
* be used to populate the buttons (see {@link #setModel} for more
|
||||
* details).
|
||||
*/
|
||||
public ComboButtonBox (int orientation, ComboBoxModel model)
|
||||
{
|
||||
// set up our layout
|
||||
setOrientation(orientation);
|
||||
|
||||
// set up our contents
|
||||
setModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the orientation of the box (either {@link #HORIZONTAL} or
|
||||
* {@link #VERTICAL}.
|
||||
*/
|
||||
public void setOrientation (int orientation)
|
||||
{
|
||||
GroupLayout gl = (orientation == HORIZONTAL) ?
|
||||
(GroupLayout)new HGroupLayout() : new VGroupLayout();
|
||||
gl.setPolicy(GroupLayout.EQUALIZE);
|
||||
setLayout(gl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the button box with a data model which it will display. If
|
||||
* the model contains {@link Image} objects, they will be used to make
|
||||
* icons for the buttons. Otherwise the button text will contain the
|
||||
* string representation of the elements in the model.
|
||||
*/
|
||||
public void setModel (ComboBoxModel model)
|
||||
{
|
||||
// if we had a previous model, unregister ourselves from it
|
||||
if (_model != null) {
|
||||
_model.removeListDataListener(this);
|
||||
}
|
||||
|
||||
// subscribe to our new model
|
||||
_model = model;
|
||||
_model.addListDataListener(this);
|
||||
|
||||
// rebuild the list
|
||||
removeAll();
|
||||
addButtons(0, _model.getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model in use by the button box.
|
||||
*/
|
||||
public ComboBoxModel getModel ()
|
||||
{
|
||||
return _model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index of the selected component. A value of -1 will clear
|
||||
* the selection.
|
||||
*/
|
||||
public void setSelectedIndex (int selidx)
|
||||
{
|
||||
// update the display
|
||||
updateSelection(selidx);
|
||||
|
||||
// let the model know what's up
|
||||
Object item = (selidx == -1) ? null : _model.getElementAt(selidx);
|
||||
_model.setSelectedItem(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the selected item.
|
||||
*/
|
||||
public int getSelectedIndex ()
|
||||
{
|
||||
return _selectedIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the command that will be used when generating action
|
||||
* events (which is done when the selection changes).
|
||||
*/
|
||||
public void setActionCommand (String actionCommand)
|
||||
{
|
||||
_actionCommand = actionCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to our list of entities to be notified when the
|
||||
* selection changes.
|
||||
*/
|
||||
public void addActionListener (ActionListener l)
|
||||
{
|
||||
listenerList.add(ActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the list.
|
||||
*/
|
||||
public void removeActionListener (ActionListener l)
|
||||
{
|
||||
listenerList.remove(ActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies our listeners when the selection changed.
|
||||
*/
|
||||
protected void fireActionPerformed ()
|
||||
{
|
||||
// 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] == ActionListener.class) {
|
||||
// lazily create the event:
|
||||
if (_actionEvent == null) {
|
||||
_actionEvent = new ActionEvent(
|
||||
this, ActionEvent.ACTION_PERFORMED, _actionCommand);
|
||||
}
|
||||
((ActionListener)listeners[i+1]).actionPerformed(_actionEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void contentsChanged (ListDataEvent e)
|
||||
{
|
||||
// if this update is informing us of a new selection, reflect that
|
||||
// in the UI
|
||||
int start = e.getIndex0(), count = start - e.getIndex1() + 1;
|
||||
if (start == -1) {
|
||||
// figure out the selected index
|
||||
int selidx = -1;
|
||||
Object eitem = _model.getSelectedItem();
|
||||
if (eitem != null) {
|
||||
int ecount = _model.getSize();
|
||||
for (int i = 0; i < ecount; i++) {
|
||||
if (eitem == _model.getElementAt(i)) {
|
||||
selidx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// and update it
|
||||
updateSelection(selidx);
|
||||
|
||||
} else {
|
||||
// replace the buttons in this range
|
||||
removeButtons(start, count);
|
||||
addButtons(start, count);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void intervalAdded (ListDataEvent e)
|
||||
{
|
||||
int start = e.getIndex0(), count = e.getIndex1() - start + 1;
|
||||
|
||||
// adjust the selected index
|
||||
if (_selectedIndex >= start) {
|
||||
_selectedIndex += count;
|
||||
}
|
||||
|
||||
// add buttons for the new interval
|
||||
addButtons(start, count);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void intervalRemoved (ListDataEvent e)
|
||||
{
|
||||
// remove the buttons in the specified interval
|
||||
int start = e.getIndex0(), count = e.getIndex1() - start + 1;
|
||||
removeButtons(start, count);
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void mouseClicked (MouseEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void mousePressed (MouseEvent e)
|
||||
{
|
||||
// keep track of the selected button
|
||||
_selectedButton = (JLabel)e.getSource();
|
||||
_selectedButton.setBorder(SELECTED_BORDER);
|
||||
_selectedButton.repaint();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void mouseReleased (MouseEvent e)
|
||||
{
|
||||
// if the mouse was released within the bounds of the button, go
|
||||
// ahead and select it properly
|
||||
if (_selectedButton != null) {
|
||||
if (_selectedButton.contains(e.getX(), e.getY())) {
|
||||
// figure out which button this is
|
||||
int selidx = -1;
|
||||
int ccount = getComponentCount();
|
||||
for (int i = 0; i < ccount; i++) {
|
||||
if (_selectedButton == getComponent(i)) {
|
||||
selidx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if (selidx == -1) {
|
||||
Log.warning("Got action from non-button component!? " +
|
||||
"[event=" + e + "].");
|
||||
|
||||
} else {
|
||||
// if the selection changed, update our display and
|
||||
// the model
|
||||
setSelectedIndex(selidx);
|
||||
}
|
||||
|
||||
} else {
|
||||
_selectedButton.setBorder(DESELECTED_BORDER);
|
||||
_selectedButton.repaint();
|
||||
}
|
||||
|
||||
// clear out the selected button indicator
|
||||
_selectedButton = null;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void mouseEntered (MouseEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void mouseExited (MouseEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds buttons for the specified range of model elements.
|
||||
*/
|
||||
protected void addButtons (int start, int count)
|
||||
{
|
||||
Object selobj = _model.getSelectedItem();
|
||||
for (int i = start; i < count; i++) {
|
||||
Object elem = _model.getElementAt(i);
|
||||
if (selobj == elem) {
|
||||
_selectedIndex = i;
|
||||
}
|
||||
JLabel ibut = null;
|
||||
if (elem instanceof Image) {
|
||||
ibut = new JLabel(new ImageIcon((Image)elem));
|
||||
} else {
|
||||
ibut = new JLabel(elem.toString());
|
||||
}
|
||||
ibut.addMouseListener(this);
|
||||
ibut.setBorder((_selectedIndex == i) ?
|
||||
SELECTED_BORDER : DESELECTED_BORDER);
|
||||
add(ibut, i);
|
||||
}
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the buttons in the specified interval.
|
||||
*/
|
||||
protected void removeButtons (int start, int count)
|
||||
{
|
||||
while (count-- > 0) {
|
||||
remove(start);
|
||||
}
|
||||
|
||||
// adjust the selected index
|
||||
if (_selectedIndex >= start) {
|
||||
if (start + count > _selectedIndex) {
|
||||
_selectedIndex = -1;
|
||||
} else {
|
||||
_selectedIndex -= count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection to the specified index and updates the buttons
|
||||
* to reflect the change. This does not update the model.
|
||||
*/
|
||||
protected void updateSelection (int selidx)
|
||||
{
|
||||
// do nothing if this element is already selected
|
||||
if (selidx == _selectedIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unhighlight the old component
|
||||
if (_selectedIndex != -1) {
|
||||
JLabel but = (JLabel)getComponent(_selectedIndex);
|
||||
but.setBorder(DESELECTED_BORDER);
|
||||
}
|
||||
|
||||
// save the new selection
|
||||
_selectedIndex = selidx;
|
||||
|
||||
// if the selection is valid, highlight the new component
|
||||
if (_selectedIndex != -1) {
|
||||
JLabel but = (JLabel)getComponent(_selectedIndex);
|
||||
but.setBorder(SELECTED_BORDER);
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
/** The contents of the box. */
|
||||
protected ComboBoxModel _model;
|
||||
|
||||
/** The index of the selected button. */
|
||||
protected int _selectedIndex = -1;
|
||||
|
||||
/** The button over which the mouse was pressed. */
|
||||
protected JLabel _selectedButton;
|
||||
|
||||
/** Used when notifying our listeners. */
|
||||
protected ActionEvent _actionEvent;
|
||||
|
||||
/** The action command we generate when the selection changes. */
|
||||
protected String _actionCommand;
|
||||
|
||||
/** The border used for selected components. */
|
||||
protected static final Border SELECTED_BORDER =
|
||||
BorderFactory.createLoweredBevelBorder();
|
||||
|
||||
/** The border used for non-selected components. */
|
||||
protected static final Border DESELECTED_BORDER =
|
||||
BorderFactory.createRaisedBevelBorder();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// $Id: TestComboButtonBox.java,v 1.1 2002/03/10 05:10:37 mdb Exp $
|
||||
|
||||
package com.samskivert.swing;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
/**
|
||||
* Tests the image button box.
|
||||
*/
|
||||
public class TestComboButtonBox
|
||||
{
|
||||
protected static Image createImage (Color color)
|
||||
{
|
||||
BufferedImage img =
|
||||
new BufferedImage(24, 24, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics g = img.getGraphics();
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, 24, 24);
|
||||
g.dispose();
|
||||
return img;
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
JFrame frame = new JFrame("Test ComboButtonBox");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||
model.addElement(createImage(Color.blue));
|
||||
model.addElement(createImage(Color.green));
|
||||
model.addElement(createImage(Color.red));
|
||||
model.addElement(createImage(Color.yellow));
|
||||
|
||||
ComboButtonBox box =
|
||||
new ComboButtonBox(ComboButtonBox.HORIZONTAL, model);
|
||||
frame.getContentPane().add(box);
|
||||
frame.pack();
|
||||
frame.show();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user