可以在JSlider上设置未知值吗?

时间:2013-02-22 08:42:54

标签: java swing jslider


可以在没有旋钮的JSlider上设置未知值吗?


我正在开发一个项目,该项目具有在Java Swing中开发的桌面客户端,用户需要使用滑块测量一些参数。这是一个要求,它必须是一个滑块 在用户与滑块交互之前,该值必须是未知的,这意味着不显示旋钮。这也是一个要求 使用JSlider时,旋钮始终显示并且无法设置任何值超出其边界或将其设置为null,因为它使用基本类型int而不是对象Integer
有没有办法设置一个空的失败值或至少一些没有显示旋钮的值?是否有一些允许这样做的扩展?

2 个答案:

答案 0 :(得分:2)

自行实施BasicSliderUI并覆盖paintThumb(Graphics g)以执行您所需的操作。

另请看这里:How to hide the knob of jSlider?

答案 1 :(得分:1)

在Harry Joy的大力帮助下隐藏旋钮,最后我已经能够解决问题了。

如果您查看Harry的答案,您可以阅读有关覆盖方法BasicSliderUI.paintThumb(Graphics)以隐藏旋钮的信息。它在大多数L& F上运行良好,不是基于Synth(这意味着Nimbus),这种方法会有所不同,但可以通过L& F上的自定义来实现。

安装它有点棘手:在PropertyChangeListenerUIManager检查L& F上的任何更改并在组件上安装正确的UI委托就行了不起(在此解决方案中我我只是展示了BasicSliderUI中的一个,其他的是复制贴。此外,我已经调整了一下,使它将值设置为首次点​​击的位置。 为了让代表知道它是否必须绘制旋钮我决定在名为JSlider的{​​{1}}上设置一个客户端属性,该属性为"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&amp; F或OSX,都需要在听众上扩展和添加适当的代表。