0


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

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

4

2 回答 2

2

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

也看看这里:如何隐藏 jSlider 的旋钮?

于 2013-02-22T08:47:54.763 回答
1

在 Harry Joy 的大力帮助下隐藏旋钮,我终于能够解决问题。

如果您检查哈利的答案,您可以阅读有关覆盖BasicSliderUI.paintThumb(Graphics)隐藏旋钮的方法的信息。它适用于大多数不基于 Synth(这意味着 Nimbus)的 L&F,其中方法会有所不同,但可以通过 L&F 上的自定义来实现。

安装它有点棘手:有一个检查 L&FPropertyChangeListenerUIManager的任何更改并在组件上安装一个适当的 UI 委托会产生魔力(在这个解决方案中,我只是展示基于BasicSliderUI其他的一个是复制粘贴) . 此外,我对其进行了一些调整,使其将值设置为第一次单击的位置。为了让代表知道它是否必须绘制旋钮,我决定在被JSlider调用对象上有一个客户端属性"ready",即boolean. 这样,委托可以安装在任何一个JSlider,而不仅仅是一个扩展的。

现在,如何管理未知值?添加另一个新属性"selectedValue",这个属性绑定到"value"and"ready"Integer类型。"ready"is falseortrue取决于它是否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 都需要适当的委托来扩展并添加到侦听器上。

于 2013-02-25T20:55:18.833 回答