2013-02-22 3 views
0

Короткие:
Возможно установить неизвестное значение на JSlider без ручки?Можно установить неизвестное значение на JSlider?

Long:
Я работаю над проектом, который имеет настольный клиент, разработанный в Java Swing, где пользователь требуется для измерения некоторых параметров с помощью ползунка. Это требование, это должен быть слайдер.
До тех пор, пока пользователь не взаимодействует со слайдером, значение должно быть неизвестно, а это означает отсутствие ручки. Это тоже требование.
При использовании команды JSlider ручка всегда показывает и не имеет возможности установить какое-либо значение из своих границ или установить значение null, поскольку оно использует примитивный тип int, а не объект Integer.
Есть ли способ установить для него нулевое значение отказа или хотя бы какое-то значение, которое не показывает ручку? Есть ли какое-то расширение, которое позволит это сделать?

ответ

1

С большой помощью Гарри Радости о пряча ручку, наконец, я был в состоянии решить эту проблему.

Если вы отметите ответ Гарри, вы можете прочитать об исключении метода BasicSliderUI.paintThumb(Graphics) для скрытия ручки. Он отлично работает на большинстве L & F не основано на синтезаторе (и это означает, что Nimbus), где такой подход будет отличаться друг от друга, но выполнимо с помощью настроек на L & F.

Установка это немного сложнее: имея PropertyChangeListener на UIManager, который проверяет любые изменения на L & F и устанавливает подходящий делегат пользовательского интерфейса на компоненте, делает магию (в этом решении я просто показываю тот, который основан на BasicSliderUI, остальные - это копии). Кроме того, я немного изменил его, чтобы установить значение в позицию, где сначала щелкнут. Для того, чтобы делегат знал, должен ли он рисовать ручку или нет, я решил иметь свойство клиента на JSlider под названием "ready", которое должно быть boolean. Таким образом, делегат может быть установлен на любом JSlider, а не только на расширенном.

Теперь, как управлять неизвестными значениями? Добавив еще одно новое свойство "selectedValue", он связан как с "value", так и с "ready" и Integer. "ready" является false или true в зависимости от того, если это null или нет, и наоборот, и как "value" и "selectedValue" держать то же значение (один из которых int и другой Integer), если не готов, который установил бы "selectedValue" к null. Это может показаться сложным, но это не так. Также есть небольшая настройка для очистки значения с помощью [Esc] и свойств распространения в реализованном компоненте.

Вот код:

BasicSliderUIExt

import java.awt.Graphics; 
import java.awt.event.MouseEvent; 
import javax.swing.JSlider; 
import javax.swing.SwingConstants; 
import javax.swing.plaf.basic.BasicSliderUI; 

public class BasicSliderUIExt extends BasicSliderUI { 

    public BasicSliderUIExt(JSlider slider) { 
     super(slider); 
    } 

    @Override 
    public void paintThumb(Graphics g) { 
     if (isReady(super.slider)) { 
      super.paintThumb(g); 
     } 
    } 

    @Override 
    protected TrackListener createTrackListener(final JSlider slider) { 
     return new TrackListener() { 
      @Override 
      public void mousePressed(MouseEvent event) { 
       if (isReady(slider)) { 
        super.mousePressed(event); 
       } else { 
        JSlider slider = (JSlider) event.getSource(); 
        switch (slider.getOrientation()) { 
        case SwingConstants.VERTICAL: 
         slider.setValue(valueForYPosition(event.getY())); 
         break; 
        case SwingConstants.HORIZONTAL: 
         slider.setValue(valueForXPosition(event.getX())); 
         break; 
        } 
        super.mousePressed(event); 
        super.mouseDragged(event); 
       } 
      } 

      @Override 
      public boolean shouldScroll(int direction) { 
       if (isReady(slider)) { 
        return super.shouldScroll(direction); 
       } 

       return false; 
      }}; 
    } 

    public static boolean isReady(JSlider slider) { 
     Object ready = slider.getClientProperty(JSliderExt.READY_PROPERTY); 
     return (ready == null) || (!(ready instanceof Boolean)) || (((Boolean) ready).booleanValue()); 
    } 

} 

JSliderExt

import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.lang.reflect.Constructor; 
import javax.swing.BoundedRangeModel; 
import javax.swing.JSlider; 
import javax.swing.LookAndFeel; 
import javax.swing.UIManager; 
import javax.swing.plaf.SliderUI; 

public class JSliderExt extends JSlider { 

    private static final long serialVersionUID = 1L; 

    public static final String EXTENT_PROPERTY = "extent"; 
    public static final String MAXIMUM_PROPERTY = "maximum"; 
    public static final String MINIMUM_PROPERTY = "minimum"; 
    public static final String READY_PROPERTY = "ready"; 
    public static final String SELECTED_VALUE_PROPERTY = "selectedValue"; 
    public static final String VALUE_PROPERTY = "value"; 

    public static final boolean READY_DEFAULT_VALUE = false; 

    protected SliderUI uix = new BasicSliderUIExt(this); 

    public JSliderExt(BoundedRangeModel model, boolean ready) { 
     super(model); 

     init(ready); 
    } 

    public JSliderExt(BoundedRangeModel model) { 
     super(model); 

     init(READY_DEFAULT_VALUE); 
    } 

    public JSliderExt(int orientation, int minimmum, int maximum, int value, boolean ready) { 
     super(orientation, minimmum, maximum, value); 

     init(ready); 
    } 

    public JSliderExt(int orientation, int minimmum, int maximum, int value) { 
     super(orientation, minimmum, maximum, value); 

     init(READY_DEFAULT_VALUE); 
    } 

    public JSliderExt(int minimmum, int maximum, int value, boolean ready) { 
     super(minimmum, maximum, value); 

     init(ready); 
    } 

    public JSliderExt(int minimmum, int maximum, int value) { 
     super(minimmum, maximum, value); 

     init(READY_DEFAULT_VALUE); 
    } 

    public JSliderExt(int minimmum, int maximum, boolean ready) { 
     super(minimmum, maximum); 

     init(ready); 
    } 

    public JSliderExt(int minimmum, int maximum) { 
     super(minimmum, maximum); 

     init(READY_DEFAULT_VALUE); 
    } 

    public JSliderExt(int orientation, boolean ready) { 
     super(orientation); 

     init(ready); 
    } 

    public JSliderExt(int orientation) { 
     super(orientation); 

     init(READY_DEFAULT_VALUE); 
    } 

    public JSliderExt(boolean ready) { 
     super(); 

     init(ready); 
    } 

    public JSliderExt() { 
     super(); 

     init(READY_DEFAULT_VALUE); 
    } 

    private void init(boolean ready) { 
     UIManager.addPropertyChangeListener(new PropertyChangeListener() { // Changes the UI delegate in L&F change 
      @Override 
      public void propertyChange(PropertyChangeEvent event) { 
       if ("lookAndFeel".equals(event.getPropertyName())) { 
        Object newValue = event.getNewValue(); 
        if ((newValue != null) && (newValue instanceof LookAndFeel)) { 
         LookAndFeel lookAndFeel = (LookAndFeel) newValue; 

         try { 
          if (lookAndFeel instanceof MetalLookAndFeel) { 
           JSliderExt.this.uix = new MetalSliderUIExt(); 
          } else if (lookAndFeel instanceof com.sun.java.swing.plaf.motif.MotifLookAndFeel) { 
           JSliderExt.this.uix = new MotifSliderUIExt(JSliderExt.this); 
          } else if (lookAndFeel instanceof com.sun.java.swing.plaf.windows.WindowsLookAndFeel) { 
           JSliderExt.this.uix = new WindowsSliderUIExt(JSliderExt.this); 
          } else { 
           throw new NullPointerException("Default Look & Feel not matched"); 
          } 
         } catch (Exception e) { 
          try { 
           Package sliderPackage = JSliderExt.this.getClass().getPackage(); 
           String lookAndFeelName = lookAndFeel.getName(); 
           if (lookAndFeelName.equals("CDE/Motif")) { 
            lookAndFeelName = "Motif"; 
           } else if (lookAndFeelName.equals("Windows Classic")) { 
            lookAndFeelName = "Windows"; 
           } else if (lookAndFeelName.startsWith("JGoodies")) { 
            lookAndFeelName = "Basic"; 
           } 

           Class<?> sliderUiType = Class.forName(sliderPackage.getName() + "." + lookAndFeelName 
             + "SliderUIExt"); 

           Constructor<?> constructor1 = null; 
           try { 
            constructor1 = sliderUiType.getConstructor(JSlider.class); 
           } catch (Exception e3) { // Nothing to do here 
           } 
           Constructor<?> constructor0 = null; 
           try { 
            constructor0 = sliderUiType.getConstructor(); 
           } catch (Exception e3) { // Nothing to do here 
           } 

           Object sliderUi = null; 
           if (constructor1 != null) { 
            sliderUi = constructor1.newInstance(JSliderExt.this); 
           } else if (constructor0 != null) { 
            sliderUi = constructor0.newInstance(); 
           } 

           if ((sliderUi != null) && (sliderUi instanceof SliderUI)) { 
            JSliderExt.this.setUI((SliderUI) sliderUi); 
           } 
          } catch (Exception e2) { 
           JSliderExt.this.uix = new BasicSliderUIExt(JSliderExt.this); 
          } 
         } 
        } else { 
         JSliderExt.this.uix = new BasicSliderUIExt(JSliderExt.this); 
        } 
        updateUI(); 
       } 
      }}); 

     addPropertyChangeListener(new PropertyChangeListener() { 
      @Override 
      public void propertyChange(PropertyChangeEvent event) { 
       String propertyName = event.getPropertyName(); 

       if (READY_PROPERTY.equals(propertyName)) { 
        Object newValue = event.getNewValue(); 

        if ((newValue == null) || (!(newValue instanceof Boolean)) || (((Boolean) newValue).booleanValue())) { 
         setSelectedValue(Integer.valueOf(getValue())); 
        } else { 
         setSelectedValue(null); 
        } 
       } else if (SELECTED_VALUE_PROPERTY.equals(propertyName)) { 
        Object newValue = event.getNewValue(); 
        System.out.println(newValue); 

        if ((newValue != null) && (newValue instanceof Integer)) { 
         int value = getValue(); 
         int newSelectedValue = ((Integer) newValue).intValue(); 

         if (value != newSelectedValue) { 
          setValue(newSelectedValue); 
         } 

         setReady(true); 
        } else { 
         setReady(false); 
        } 

        repaint(); 
       } else if (VALUE_PROPERTY.equals(propertyName)) { 
        setReady(true); 

        Object newValue = event.getNewValue(); 

        if ((newValue != null) && (newValue instanceof Integer)) { 
         setSelectedValue((Integer) newValue); 
        } 
       } 
      }}); 

     addKeyListener(new KeyAdapter() { // Enables escape key for clearing value 
      @Override 
      public void keyPressed(KeyEvent event) { 
       if (event.getKeyCode() == KeyEvent.VK_ESCAPE) { 
        JSliderExt.this.setReady(false); 
       } 
      }}); 

     setReady(ready); 
    } 

    @Override 
    public void setValue(int value) { 
     int oldValue = getValue(); 
     super.setValue(value); 
     firePropertyChange(VALUE_PROPERTY, Integer.valueOf(oldValue), Integer.valueOf(value)); 
    } 

    @Override 
    public void setExtent(int extent) { 
     int oldExtent = getExtent(); 
     super.setExtent(extent); 
     firePropertyChange(EXTENT_PROPERTY, Integer.valueOf(oldExtent), Integer.valueOf(extent)); 
    } 

    @Override 
    public void setMinimum(int minimum) { 
     int oldMinimum = getMinimum(); 
     super.setMinimum(minimum); 
     firePropertyChange(MINIMUM_PROPERTY, Integer.valueOf(oldMinimum), Integer.valueOf(minimum)); 
    } 

    @Override 
    public void setMaximum(int maximum) { 
     int oldMaximum = getMaximum(); 
     super.setMaximum(maximum); 
     firePropertyChange(MAXIMUM_PROPERTY, Integer.valueOf(oldMaximum), Integer.valueOf(maximum)); 
    } 

    public Integer getSelectedValue() { 
     return (Integer) getClientProperty(SELECTED_VALUE_PROPERTY); 
    } 

    public void setSelectedValue(Integer selectedValue) { 
     putClientProperty(SELECTED_VALUE_PROPERTY, selectedValue); 
    } 

    public boolean isReady() { 
     Object ready = getClientProperty(READY_PROPERTY); 
     return ((ready != null) && (ready instanceof Boolean)) ? ((Boolean) ready).booleanValue() 
       : READY_DEFAULT_VALUE; 
    } 

    public void setReady(boolean waiting) { 
     putClientProperty(READY_PROPERTY, Boolean.valueOf(waiting)); 
    } 

    @Override 
    public void updateUI() { 
     setUI(this.uix); 
     updateLabelUIs(); 
    } 

} 

Пожалуйста, обратите внимание, что с помощью этого кода, может потребоваться некоторые изменения в выборе делегатов в зависимости от вашего приложения, так как это предназначен для системы Windows. Как сказано, Synth/Nimbus нужно работать по-другому, но также и любой пользовательский L & F или для OSX необходимо, чтобы делегат был расширен и добавлен в слушателя.

2

Сделайте свою собственную реализацию BasicSliderUI и переопределите paintThumb(Graphics g), чтобы выполнить то, что вам нужно.

Также смотрите здесь: How to hide the knob of jSlider?

+0

Ну, это очень помогает, но это не полностью решает проблему. В одной руке наше приложение поддерживает 2 взгляда и чувств, один из которых - Windows, и, похоже, он не работает под Windows LAF. С другой стороны, я все еще не знаю, как установить неизвестное значение, так как параметр «BoundedRangeModel» корректирует значения, устанавливаемые между минимумом и максимумом, и связывает их с этим поведением. –

+0

Он работает под Windows LAF, я просто установил его неправильно. В любом случае вторая проблема все еще не решена. –

+0

@ YagoMéndezVidal, что еще не сделано? спрятать ручку? –

Смежные вопросы