代码之家  ›  专栏  ›  技术社区  ›  I82Much

在Java中修改Office 2007的缩放栏(修改后的JSLIDER)

  •  1
  • I82Much  · 技术社区  · 15 年前

    我正在尝试模仿(或找到一个以前存在的组件)Word 2007中的缩放滑块:

    Two state zoom bar http://i49.tinypic.com/iyk65l.png

    这个组件和标准JavaJSLIDER有两个主要区别:

    1. 除了100%外,不会捕捉到滴答声,当您滑动条而不是释放鼠标时会捕捉到滴答声。
    2. 滑块在整个过程中不是线性的:滑块的左半部分从10%到100%;右侧从100%到500%。

    以下是迄今为止我所拥有的: Java clone http://i45.tinypic.com/2i8dms9.png

    来源:

        import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JSlider;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    /**
     *
     * @author NDUNN
     * @date Nov 25, 2009
     */
    public class ZoomBar extends JPanel implements ActionListener, ChangeListener {
    
        private JLabel zoomAmount;
        private JButton minus;
        private JButton plus;
        private JSlider slider;
    
        private static final int MIN_ZOOM = 10;
        private static final int MAX_ZOOM = 200;
        private static final int DEFAULT_ZOOM = 100;
    
        private static final int MAJOR_ZOOM_SPACING = 50;
        private static final int MINOR_ZOOM_SPACING = 10;
    
        public ZoomBar() {
            super();
    
            minus = new JButton("-");
            plus = new JButton("+");
            slider = new JSlider(MIN_ZOOM, MAX_ZOOM, DEFAULT_ZOOM);
    
            slider.setMinorTickSpacing(MINOR_ZOOM_SPACING);
            slider.setMajorTickSpacing(MAJOR_ZOOM_SPACING);
            slider.setPaintTicks(true);
            slider.setSnapToTicks(true);
    
            zoomAmount = new JLabel(slider.getValue() + "%");
    
            add(zoomAmount);
            add(minus);
            add(slider);
            add(plus);
    
            plus.addActionListener(this);
            minus.addActionListener(this);
    
            slider.addChangeListener(this);
        }
    
        public static void main(String[] args) {
            JFrame frame = new JFrame("Zoom bar clone");
            frame.setContentPane(new ZoomBar());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        }
    
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == plus) {
                slider.setValue(slider.getValue() + MINOR_ZOOM_SPACING);
            }
            else if (e.getSource() == minus) {
                slider.setValue(slider.getValue() - MINOR_ZOOM_SPACING);
            }
        }
    
        public void stateChanged(ChangeEvent e) {
            if (slider.getValueIsAdjusting()) {
                return;
            }
            zoomAmount.setText(slider.getValue() + "%");
        }
    
    }
    

    基本上只是模仿外观,但没有上述两个功能。我什么都没看到 JSlider API 这让我有了这种行为。我必须从头开始才能有这种行为吗?如果是这样的话,这不值得我花时间,但是如果有人知道一个好的方法来达到这种行为,我想在我正在进行的项目中拥有它会很好。

    谢谢,

    尼克


    编辑:

    多亏了pspeed提出了将0..50和50..100映射到不同值的想法。这样做的代码如下。

    不幸的是,将setvalue更改为snap的想法没有起作用。

    public void stateChanged(ChangeEvent e) {
        // While slider is moving, snap it to midpoint
        int value = slider.getValue();
        if (slider.getValueIsAdjusting()) {
            return;
        }
    
        zoomValue = fromSlider(value);
        zoomLabel.setText(zoomValue + "%");
    }
    
    public int fromSlider(int sliderValue) {
        int mappedValue = 0;
        if (sliderValue <= 50) {
            // Map from [0, 50] to [MIN ... DEFAULT]
            mappedValue = (int) map(sliderValue, 0, 50, MIN_ZOOM, DEFAULT_ZOOM);
        }
        else {
            // Convert from  (50, 100] to (DEFAULT ... MAX]
            mappedValue = (int) map(sliderValue, 50, 100, DEFAULT_ZOOM, MAX_ZOOM);
        }
        return mappedValue;
    }
    
    public int toSlider(int modelValue) {
        int mappedValue = 0;
        if (modelValue <= DEFAULT_ZOOM) {
            // Map from [MIN_ZOOM, DEFAULT_ZOOM] to [0 ... 50]
            mappedValue = (int) map(modelValue, MIN_ZOOM, DEFAULT_ZOOM, 0, 50);
        }
        else {
            // Convert from  (DEFAULT ... MAX] to (50, 100]
            mappedValue = (int) map(modelValue, DEFAULT_ZOOM, MAX_ZOOM, 50, 100);
        }
        return mappedValue;
    }
    
    
    /**
     * @param value The incoming value to be converted
     * @param low1  Lower bound of the value's current range
     * @param high1 Upper bound of the value's current range
     * @param low2  Lower bound of the value's target range
     * @param high2 Upper bound of the value's target range
     * @return
     */
    public static final double map(double value, double low1, double high1, double low2, double high2) {
    
        double diff = value - low1;
        double proportion = diff / (high1 - low1);
    
        return lerp(low2, high2, proportion);
    }
    
    public static final double lerp(double value1, double value2, double amt) {
        return ((value2 - value1) * amt) + value1;
    }
    

    编辑2: 我注意到的另一个不同点是jbutton不允许您多次按住它来启动按钮,而office中的+/-按钮可以。知道怎么模仿这个吗?

    1 回复  |  直到 15 年前
        1
  •  2
  •   PSpeed    15 年前

    我相信你可以用一个自定义的有界范围模型来实现所有这些行为。关键是要使模型报告成为一个正常的值范围类型,但在需要缩放因子时,对其进行不同的处理。

    例如,如果你让你的范围从0到100,你会以一种方式对待0到50,以另一种方式对待50到100(分别是10到100%和100到500%)。

    为了获得捕捉行为,我很确定您可以重写setValue()来捕捉您想要的范围。因此,使用0-100作为值范围,如果用47-53调用setValue(),那么只需将值捕捉到50。