程式扎記: [ Java 範例代碼 ] Swing: Creating a Java Swing range slider

標籤

2014年6月13日 星期五

[ Java 範例代碼 ] Swing: Creating a Java Swing range slider

來源自 這裡 
Preface: 
有關 Java Swing Slider 的使用可以參考 "How to Use Sliders". 預設 Java Swing Slider 只提供一個方向的滑動. 一個 Swing Tutorial 的範例如下: 
 

通常 Slider 上會有 Min/Max 的設定, 而上面的範例只能選擇由 Min~Max 間的某個值. 但如果我希望使用 Slider 來選擇的是一個 Range, 則可以參考這邊的範例代碼. 
 

Description: 
In order to create the range slider, we needed a new Swing component because the existing JSlider component only displays a single thumb to adjust the slider value. Interestingly, even though JSlider only allows you to update a single value, its data model actually provides support for two values; these define an internal range within the minimum and maximum bounds. 

The internal range is defined by the slider value and an “extent,” which is the length of the inner range that begins at the slider value. In DefaultBoundedRangeModel, the default “extent” is zero and not normally used for anything. We can add it to the slider value to define an upper value of a selected range. 
  1. /** 
  2. * Sets the upper value in the range. 
  3. */  
  4. public void setUpperValue(int value) {  
  5.     // Compute new extent.  
  6.     int lowerValue = getValue();  
  7.     int newExtent = Math.min(Math.max(0, value - lowerValue), getMaximum() - lowerValue);  
  8.       
  9.     // Set extent to set upper value.  
  10.     setExtent(newExtent);  
  11. }  
The new dual-thumb slider component takes advantage of the built-in definition for DefaultBoundedRangeModel, and is implemented with just two classes: RangeSliderand RangeSliderUI. These are included in the demo source code

RangeSlider extends JSlider to install a UI delegate and provide value change methods. The methods set the lower and upper values in the selected range. We define the existing slider value as the lower value, and the upper value as the lower value plus the extent. To access these values, we override some methods, and add a couple of our own. This class do below three things: 
  • We add setUpperValue(int) to calculate the extent based on the current lower value. We apply limits to ensure that the upper value is bounded by the lower value and the maximum.

  • We override setValue(int) to calculate the extent to ensure that the upper value does not change. We apply limits to ensure that the lower value stays bounded by the minimum and the upper value.

  • We override updateUI() to install a custom UI delegate to render the two thumbs.

    1. package proj.ui.cmp;  
    2.   
    3. import javax.swing.JSlider;  
    4.   
    5. public class RangeSlider extends JSlider{  
    6.     /** 
    7.      * Constructs a RangeSlider with default minimum and maximum values of 0 
    8.      * and 100. 
    9.      */  
    10.     public RangeSlider() {  
    11.         initSlider();  
    12.     }  
    13.       
    14.     /** 
    15.      * Initializes the slider by setting default properties. 
    16.      */  
    17.     private void initSlider() {  
    18.         setOrientation(HORIZONTAL);  
    19.     }  
    20.       
    21.     /** 
    22.      * Overrides the superclass method to install the UI delegate to draw two 
    23.      * thumbs. 
    24.      */  
    25.     @Override  
    26.     public void updateUI() {  
    27.         setUI(new RangeSliderUI(this));  
    28.         // Update UI for slider labels.  This must be called after updating the  
    29.         // UI of the slider.  Refer to JSlider.updateUI().  
    30.         updateLabelUIs();  
    31.     }  
    32.           
    33.     /** 
    34.      * Returns the lower value in the range. 
    35.      */  
    36.     @Override  
    37.     public int getValue() {  
    38.         return super.getValue();  
    39.     }  
    40.   
    41.     /** 
    42.      * Sets the lower value in the range. 
    43.      */  
    44.     @Override  
    45.     public void setValue(int value) {  
    46.         int oldValue = getValue();  
    47.         if (oldValue == value) {  
    48.             return;  
    49.         }  
    50.   
    51.         // Compute new value and extent to maintain upper value.  
    52.         int oldExtent = getExtent();  
    53.         int newValue = Math.min(Math.max(getMinimum(), value), oldValue + oldExtent);  
    54.         int newExtent = oldExtent + oldValue - newValue;  
    55.   
    56.         // Set new value and extent, and fire a single change event.  
    57.         getModel().setRangeProperties(newValue, newExtent, getMinimum(),   
    58.             getMaximum(), getValueIsAdjusting());  
    59.     }  
    60.       
    61.     /** 
    62.      * Returns the upper value in the range. 
    63.      */  
    64.     public int getUpperValue() {  
    65.         return getValue() + getExtent();  
    66.     }  
    67.   
    68.     /** 
    69.      * Sets the upper value in the range. 
    70.      */  
    71.     public void setUpperValue(int value) {  
    72.         // Compute new extent.  
    73.         int lowerValue = getValue();  
    74.         int newExtent = Math.min(Math.max(0, value - lowerValue), getMaximum() - lowerValue);  
    75.           
    76.         // Set extent to set upper value.  
    77.         setExtent(newExtent);  
    78.     }  
    79. }  
    RangeSliderUI extends BasicSliderUI to paint the two thumbs and handle user events. This provides a customized rendering of the two thumbs and handles user events to update their values. This is somewhat involved so we will only highlight the primary aspects of this code. The main tasks are: (1) calculating the thumb sizes and locations, (2) painting the thumbs, and (3) handling mouse and keyboard input events on the thumbs. (因為代碼太多, 請直接參考 Git 上的 RangeSliderUI

    Example Code: 
    1. package proj.ui.cmp;  
    2. import javax.swing.JLabel;  
    3.   
    4. public class DemoRange extends javax.swing.JFrame {  
    5.     private JLabel jLabelS;  
    6.     private RangeSlider jSliderBtm;  
    7.     private JLabel jLabelE;  
    8.   
    9.     /** 
    10.     * Auto-generated main method to display this JFrame 
    11.     */  
    12.     public static void main(String[] args) {  
    13.         SwingUtilities.invokeLater(new Runnable() {  
    14.             public void run() {  
    15.                 DemoRange inst = new DemoRange();  
    16.                 inst.setLocationRelativeTo(null);  
    17.                 inst.setVisible(true);  
    18.             }  
    19.         });  
    20.     }  
    21.       
    22.     public DemoRange() {  
    23.         super();  
    24.         initGUI();  
    25.         initSUI();  
    26.     }  
    27.       
    28.     void initSUI()  
    29.     {  
    30.         /*Setup Maximum/Minimum and initialize start/end*/  
    31.         jSliderBtm.setMaximum(10);  
    32.         jSliderBtm.setMinimum(0);  
    33.         jSliderBtm.setValue(0);  
    34.         jSliderBtm.setUpperValue(10);  
    35.           
    36.     }  
    37.       
    38.     private void initGUI() {  
    39.         try {  
    40.             setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);  
    41.             getContentPane().setLayout(null);  
    42.             {  
    43.                 jLabelS = new JLabel();  
    44.                 getContentPane().add(jLabelS);  
    45.                 jLabelS.setText("Start: 0");  
    46.                 jLabelS.setBounds(7636517);  
    47.             }  
    48.             {  
    49.                 jLabelE = new JLabel();  
    50.                 getContentPane().add(jLabelE);  
    51.                 jLabelE.setText("End: 10");  
    52.                 jLabelE.setBounds(72936517);  
    53.             }  
    54.             {  
    55.                 jSliderBtm = new RangeSlider();  
    56.                 getContentPane().add(jSliderBtm);  
    57.                 jSliderBtm.setBounds(75836516);  
    58.                 jSliderBtm.addChangeListener(new ChangeListener() {  
    59.                     public void stateChanged(ChangeEvent evt) {  
    60.                         jSliderBtmStateChanged(evt);  
    61.                     }  
    62.                 });  
    63.             }  
    64.             pack();  
    65.             this.setSize(400150);  
    66.         } catch (Exception e) {  
    67.             //add your error handling code here  
    68.             e.printStackTrace();  
    69.         }  
    70.     }  
    71.       
    72.     private void jSliderBtmStateChanged(ChangeEvent evt) {  
    73.         int lowerBnd = jSliderBtm.getValue();  
    74.         int highrBnd = jSliderBtm.getUpperValue();  
    75.         System.out.printf("%d~%d\n", lowerBnd, highrBnd);  
    76.         jLabelS.setText(String.format("Start: %d", lowerBnd));  
    77.         jLabelE.setText(String.format("End: %d", highrBnd));  
    78.     }  
    79.   
    80. }  
    執行結果: 

    沒有留言:

    張貼留言

    網誌存檔