[Schmitzm-commits] r2176 - in trunk/schmitzm-core/src/main/java/de/schmitzm/swing: . event
scm-commit at wald.intevation.org
scm-commit at wald.intevation.org
Fri Dec 21 16:19:06 CET 2012
Author: mojays
Date: 2012-12-21 16:19:06 +0100 (Fri, 21 Dec 2012)
New Revision: 2176
Added:
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JSpinner.java
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingKeyListener.java
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingMouseListener.java
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingSettable.java
Modified:
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SliderSpinnerPanel.java
Log:
new JSpinner with "value is adjusting" functionality.
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JSpinner.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JSpinner.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/JSpinner.java 2012-12-21 15:19:06 UTC (rev 2176)
@@ -0,0 +1,126 @@
+package de.schmitzm.swing;
+
+import java.awt.Component;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseListener;
+import java.util.Arrays;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+
+import de.schmitzm.swing.event.ValueAdjustingKeyListener;
+import de.schmitzm.swing.event.ValueAdjustingMouseListener;
+import de.schmitzm.swing.event.ValueAdjustingSettable;
+
+/**
+ * {@link javax.swing.JSpinner} enhanded by "value is adjusting" functionality as long as
+ * up/down button or up/down key is pressed.<br>
+ * <b>Note:</b>: The "value is adjusting" property does <u>not</u> avoid listener calls
+ * automatically (by {@link #fireStateChanged()}. Each listener can/must decide individually
+ * whether to react even on "value adjusting" changes or not.
+ * @author Martin O.J. Schmitz
+ */
+public class JSpinner extends javax.swing.JSpinner implements ValueAdjustingSettable {
+
+ /** Flag indicating whether spinner value currently is adjusting. */
+ protected boolean valueIsAdjusting = false;
+ /** MouseListener for up/down buttons to set "valueIsAdjusting" flag
+ * as long as button is pressed */
+ protected MouseListener valueAdjustingMouseListener;
+ /** KeyListener for up/down keys to set "valueIsAdjusting" flag
+ * as long as key is pressed */
+ protected KeyListener valueAdjustingKeyListener;
+
+ /**
+ * Creates new spinner with {@link SpinnerNumberModel}.
+ */
+ public JSpinner() {
+ super();
+ init();
+ }
+
+ /**
+ * Creates a new spinner.
+ */
+ public JSpinner(SpinnerModel model) {
+ super(model);
+ init();
+ }
+
+ /**
+ * Called for every constructor.
+ */
+ protected void init() {
+ // MouseListener for up/down buttons to set "valueIsAdjusting"
+ // flag as long as button is pressed
+ valueAdjustingMouseListener = new ValueAdjustingMouseListener() {
+ @Override
+ public void setValueIsAdjusting(boolean valueIsAdjusting) {
+ JSpinner.this.setValueIsAdjusting(valueIsAdjusting);
+ }
+ };
+ // KeyListener for up/down keys to set "valueIsAdjusting"
+ // flag as long as key is pressed
+ valueAdjustingKeyListener = new ValueAdjustingKeyListener(true,false) {
+ @Override
+ public void setValueIsAdjusting(boolean valueIsAdjusting) {
+ JSpinner.this.setValueIsAdjusting(valueIsAdjusting);
+ }
+ };
+
+ // Dirty, but does its work!
+ // Add listener to up/down buttons...
+ for (Component child : getComponents()) {
+ if ("Spinner.nextButton".equals(child.getName())) {
+ ((JButton) child).addMouseListener(valueAdjustingMouseListener);
+ }
+ if ("Spinner.previousButton".equals(child.getName())) {
+ ((JButton) child).addMouseListener(valueAdjustingMouseListener);
+ }
+ }
+ }
+
+ /**
+ * If not already added, this method adds the {@link #valueAdjustingKeyListener}
+ * to the current editor component.
+ */
+ protected void addValueAdjustingKeyListenerToEditor() {
+ JComponent comp = getEditor();
+ if ( comp instanceof DefaultEditor )
+ comp = ((DefaultEditor)comp).getTextField();
+ if ( !Arrays.asList( comp.getKeyListeners() ).contains(valueAdjustingKeyListener) )
+ comp.addKeyListener(valueAdjustingKeyListener);
+ }
+
+
+ /**
+ * After calling the super method, the {@link #valueAdjustingKeyListener}
+ * is added to the new editor component.
+ * @see #addValueAdjustingKeyListenerToEditor()
+ */
+ @Override
+ public void setEditor(JComponent comp) {
+ super.setEditor(comp);
+ addValueAdjustingKeyListenerToEditor();
+ }
+
+ /**
+ * Returns whether current value change is part of multiple changes.
+ */
+ public boolean getValueIsAdjusting() {
+ return valueIsAdjusting;
+ }
+
+ /**
+ * Sets whether (following) value changes are part of multiple changes.
+ * If set to {@code false}, {@link #fireStateChanged()} is called.
+ */
+ @Override
+ public void setValueIsAdjusting(boolean valueIsAdjusting) {
+ this.valueIsAdjusting = valueIsAdjusting;
+ if ( !valueIsAdjusting )
+ fireStateChanged();
+ }
+}
\ No newline at end of file
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SliderSpinnerPanel.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SliderSpinnerPanel.java 2012-12-21 11:44:35 UTC (rev 2175)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SliderSpinnerPanel.java 2012-12-21 15:19:06 UTC (rev 2176)
@@ -36,11 +36,15 @@
import javax.swing.JLabel;
import javax.swing.JSlider;
-import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import org.apache.log4j.Logger;
+
+import de.schmitzm.lang.LangUtil;
+import de.schmitzm.swing.event.ValueAdjustingKeyListener;
+
/**
* Dieses Panel enthaelt einen Slider, der mit einem Spinner verknuepft ist.
* Zusaetzlich wird eine Ueberschrift ausgewiesen.
@@ -48,6 +52,9 @@
* @version 1.0
*/
public class SliderSpinnerPanel extends JPanel {
+ /** For debugging */
+ protected Logger LOGGER = LangUtil.createLogger(this);
+
/** Konstante fuer die <b>horizontale</b> Orientierung des Sliders.
* @see JSlider#HORIZONTAL */
public static final int HORIZONTAL = JSlider.HORIZONTAL;
@@ -61,7 +68,16 @@
protected JLabel headerLabel = null;
/** Spinner des Panels. */
protected JSpinner spinner = null;
+ /** Value when {@link #fireChangeEvent(ChangeEvent)} was called the last time. */
+ protected Double lastValue = null;
+ /** {@link JSlider} can only maintain {@link Integer} values so we have to convert
+ * the value. */
+ protected double sliderValueConversionFactor = 1.0;
+
+ /** Flag during update of slider and spinner */
+ protected boolean sliderSpinnerAdjusting = false;
+
/**
* Erzeugt ein neues Panel.
* @param orientation Orientierung des Sliders
@@ -83,6 +99,12 @@
}
// Slider
this.slider = new JSlider(orientation);
+ slider.addKeyListener( new ValueAdjustingKeyListener() {
+ @Override
+ public void setValueIsAdjusting(boolean valueIsAdjusting) {
+ slider.setValueIsAdjusting(valueIsAdjusting);
+ }
+ });
this.add( slider, new GridBagConstraints(
0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0) );
// Spinner
@@ -94,21 +116,37 @@
// ActionListener auf Spinner, um Slider zu aktualisieren
this.spinner.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
- double newValue = ((Number)spinner.getValue()).doubleValue();
- if ( Math.round(newValue) != slider.getValue())
- slider.setValue( (int)Math.round(newValue) );
+ if ( sliderSpinnerAdjusting )
+ return;
+ sliderSpinnerAdjusting = true;
+ double newValue = ((Number)spinner.getValue()).doubleValue() * sliderValueConversionFactor;
+ slider.setValue( (int)Math.round(newValue) );
+ sliderSpinnerAdjusting = false;
}
});
// ActionListener auf Slider, um Spinner zu aktualisieren
this.slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
- int newValue = slider.getValue();
- if (newValue != Math.round( ((Number)spinner.getValue()).doubleValue() ))
- spinner.setValue(newValue);
+ if ( sliderSpinnerAdjusting )
+ return;
+ sliderSpinnerAdjusting = true;
+ double newValue = slider.getValue() / sliderValueConversionFactor;
+ spinner.setValue(newValue);
+ sliderSpinnerAdjusting = false;
}
});
+ // ActionListener auf Slider, um ChangeEvent an Listener weiterzugeben
+ ChangeListener changeListener = new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ fireChangeEvent(e);
+ }
+ };
+ this.slider.addChangeListener(changeListener);
+ this.spinner.addChangeListener(changeListener);
+
// Minimum, Maximum, StepSize und initalalier Wert einstellen
setRestrictions(value,min,max,step);
}
@@ -215,8 +253,9 @@
) );
spinner.setEditor( new JSpinner.NumberEditor(this.spinner,SwingUtil.getNumberFormatPattern(stepSize)) );
// Slider einstellen
+ sliderValueConversionFactor = (stepSize < 1) ? 1/stepSize : 1;
slider.setMinimum( (int)Math.floor(min) );
- slider.setMaximum( (int)Math.ceil(max) );
+ slider.setMaximum( (int)(Math.ceil(max) * sliderValueConversionFactor) );
setValue( value );
}
@@ -240,4 +279,41 @@
public JSpinner getSpinner() {
return this.spinner;
}
+
+
+
+ /**
+ * Adds a listener to spinner.
+ */
+ public void addChangeListener(ChangeListener l) {
+ this.listenerList.add(ChangeListener.class, l);
+ }
+
+ /**
+ * Removes a listener from component
+ */
+ public void removesChangeListener(ChangeListener l) {
+ this.listenerList.remove(ChangeListener.class, l);
+ }
+
+ /**
+ * Pipes the event to all connected {@link ChangeListener ChangeListeners},
+ * but only if value is not adjusting anymore!
+ */
+ protected void fireChangeEvent(ChangeEvent e) {
+ if ( slider.getValueIsAdjusting() || spinner.getValueIsAdjusting() )
+ return;
+ // on manual input in spinner text field 2 events are created, on for
+ // spinner and one for the slider!
+ // To avoid this we double-check for last value
+ double value = getValue();
+ if ( lastValue != null && value == lastValue )
+ return;
+ LOGGER.debug("value changed: "+lastValue+" -> "+value);
+ lastValue = value;
+ for (ChangeListener l : getListeners(ChangeListener.class))
+ l.stateChanged(e);
+ }
+
+
}
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingKeyListener.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingKeyListener.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingKeyListener.java 2012-12-21 15:19:06 UTC (rev 2176)
@@ -0,0 +1,88 @@
+package de.schmitzm.swing.event;
+
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+/**
+ * {@link KeyListener} which sets "value adjusting" flag to {@code true} as
+ * long as an arrow key (up/down/left/right) is pressed.
+ * @author Martin O.J. Schmitz
+ */
+public abstract class ValueAdjustingKeyListener extends KeyAdapter implements ValueAdjustingSettable {
+ protected boolean handleUpDown = true;
+ protected boolean handleLeftRight = true;
+
+ /**
+ * Creates new listener, which reacts on up, down, left and right
+ * key.
+ */
+ public ValueAdjustingKeyListener() {
+ this(true,true);
+ }
+
+ /**
+ * Creates new listener
+ * @param handleUpDown indicates whether "value is adjusting" is set on
+ * up and down key
+ * @param handleLeftRight indicates whether "value is adjusting" is set
+ * on left and right key
+ */
+ public ValueAdjustingKeyListener(boolean handleUpDown, boolean handleLeftRight) {
+ super();
+ this.handleLeftRight = handleLeftRight;
+ this.handleUpDown = handleUpDown;
+ }
+
+ /**
+ * Sets "value adjusting" flag to {@code true}.
+ * @see #setValueIsAdjusting(boolean)
+ */
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if ( isArrowKeyEvent(e) )
+ setValueIsAdjusting(true);
+ }
+
+ /**
+ * Sets "value adjusting" flag to {@code false}.
+ * @see #setValueIsAdjusting(boolean)
+ */
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if ( isArrowKeyEvent(e) )
+ setValueIsAdjusting(false);
+ }
+
+ /**
+ * Sets the "value adjusting" flag. Has to be implemented individually to
+ * call the {@code setValueIsAdjusting(.)} method of the individual
+ * component.
+ */
+ @Override
+ public abstract void setValueIsAdjusting(boolean valueIsAdjusting);
+
+ /**
+ * Checks whether {@link KeyEvent} represents arrow key.
+ */
+ public boolean isArrowKeyEvent(KeyEvent e) {
+ int id = e.getExtendedKeyCode();
+ switch ( id ) {
+ case KeyEvent.VK_UP:
+ case KeyEvent.VK_DOWN:
+ case KeyEvent.VK_KP_DOWN:
+ case KeyEvent.VK_KP_LEFT:
+ if ( handleUpDown )
+ return true;
+ break;
+ case KeyEvent.VK_LEFT:
+ case KeyEvent.VK_RIGHT:
+ case KeyEvent.VK_KP_UP:
+ case KeyEvent.VK_KP_RIGHT:
+ if ( handleLeftRight )
+ return true;
+ break;
+ }
+ return false;
+ }
+}
\ No newline at end of file
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingMouseListener.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingMouseListener.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingMouseListener.java 2012-12-21 15:19:06 UTC (rev 2176)
@@ -0,0 +1,38 @@
+package de.schmitzm.swing.event;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+/**
+ * {@link MouseListener} which sets "value adjusting" flag to {@code true} as
+ * long as mouse button is pressed.
+ * @author Martin O.J. Schmitz
+ */
+public abstract class ValueAdjustingMouseListener extends MouseAdapter implements ValueAdjustingSettable {
+ /**
+ * Sets "value adjusting" flag to {@code false}.
+ * @see #setValueIsAdjusting(boolean)
+ */
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ setValueIsAdjusting(false);
+ }
+
+ /**
+ * Sets "value adjusting" flag to {@code true}.
+ * @see #setValueIsAdjusting(boolean)
+ */
+ @Override
+ public void mousePressed(MouseEvent e) {
+ setValueIsAdjusting(true);
+ }
+
+ /**
+ * Sets the "value adjusting" flag. Has to be implemented individually to
+ * call the {@code setValueIsAdjusting(.)} method of the individual
+ * component.
+ */
+ @Override
+ public abstract void setValueIsAdjusting(boolean valueIsAdjusting);
+}
\ No newline at end of file
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingSettable.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingSettable.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/ValueAdjustingSettable.java 2012-12-21 15:19:06 UTC (rev 2176)
@@ -0,0 +1,14 @@
+package de.schmitzm.swing.event;
+
+/**
+ * Interface for component for which the "value adjusting" flag can be
+ * set.
+ * @author Martin O.J. Schmitz
+ *
+ */
+public interface ValueAdjustingSettable {
+ /**
+ * Sets the "value adjusting" flag.
+ */
+ public void setValueIsAdjusting(boolean valueIsAdjusting);
+}
\ No newline at end of file
More information about the Schmitzm-commits
mailing list