-1

我想用 Java 制作一个滑块,类似于 JSlider,但它本身可以有多个滑块。确切地说,我想在 Microsoft Excel 中实现固定宽度功能中使用的滑块(从数据-> 固定宽度)。一个普通的滑块只有一个点,我们可以将它拖到不同的位置。现在,如果我在滑块的某个位置单击,应该添加一个新点,并且该点的拖动操作应该独立于之前的拖动操作。此外,如果我双击,该点将从滑块中删除。

4

1 回答 1

3
import java.awt.*;
import java.awt.event.MouseEvent;

import javax.swing.*;
import javax.swing.plaf.basic.BasicSliderUI;

public class MultiSlider extends JComponent
{
  public static void main(String[] args)
  { // main method just for showing a usage example
    try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
    catch(Exception ex){}
    JFrame f=new JFrame();
    final MultiSlider slider = new MultiSlider();
    slider.setValue(0, 80);
    slider.addValue(20);
    f.getContentPane().add(slider);
    f.setSize(200, 100);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  public MultiSlider()
  {
    super.setLayout(null);
    addSlider(0);
  }

  public void setValue(int slider, int value)
  {
    ((JSlider)getComponent(slider)).setValue(value);
  }
  public void addValue(int value)
  {
    addSlider(value);
  }
  @Override
  public boolean isOptimizedDrawingEnabled()
  {
    return false;
  }

  @Override
  public void doLayout()
  {
    Insets i=getInsets();
    int x=i.left, y=i.top, width=getWidth()-x-i.right, height=getHeight()-y-i.bottom;
    for(int ix=0, n=getComponentCount(); ix<n; ix++)
      getComponent(ix).setBounds(x, y, width, height);
  }

  class SubSlider extends JSlider
  {
    private SubSlider active;

    @Override
    protected void processMouseEvent(MouseEvent e)
    {
      SubSlider sl=getClosestSlider(e);
      if(e.getID()==MouseEvent.MOUSE_PRESSED) active=sl;
      else if(e.getID()==MouseEvent.MOUSE_RELEASED) active=null;
      if(e.getID()==MouseEvent.MOUSE_CLICKED)
      {
        if(sl==null && e.getClickCount()==1) addSlider(e.getPoint());
        else if(sl!=null && e.getClickCount()==2)
        {
          removeSlider(sl);
          return;
        }
      }
      if(sl!=null) sl.realProcessMouseEvent(e);
    }
    private void realProcessMouseEvent(MouseEvent e)
    {
      e.setSource(this);
      super.processMouseEvent(e);
    }
    @Override
    protected void processMouseMotionEvent(MouseEvent e)
    {
      if(e.getID()==MouseEvent.MOUSE_MOVED)
        toAllSliders(e);
      else
      {
        if(active==null) active=getClosestSlider(e);
        if(active!=null) active.realProcessMouseMotionEvent(e);
      }
    }
    private void realProcessMouseMotionEvent(MouseEvent e)
    {
      e.setSource(this);
      super.processMouseMotionEvent(e);
    }
  }

  final void toAllSliders(MouseEvent e)
  {
    for(int ix=0, n=getComponentCount(); ix<n; ix++)
      ((SubSlider)getComponent(ix)).realProcessMouseMotionEvent(e);
  }
  public void removeSlider(SubSlider sl)
  {
    if(getComponentCount()<=1) return;// must keep the last slider
    remove(sl);
    JSlider slider=(JSlider)getComponent(getComponentCount()-1);
    slider.setOpaque(true);
    slider.setPaintTrack(true);
    revalidate();
    repaint();
  }

  final SubSlider getClosestSlider(MouseEvent e)
  {
    SubSlider s=(SubSlider)getComponent(0);
    BasicSliderUI bsUI=(BasicSliderUI)s.getUI();
    int value = bsUI.valueForXPosition(e.getX());
    if(Math.abs(s.getValue()-value)<=1) return s;
    for(int ix=1, n=getComponentCount(); ix<n; ix++)
    {
      s=(SubSlider)getComponent(ix);
      if(Math.abs(s.getValue()-value)<=1) return s;
    }
    return null;
  }

  void addSlider(Point point)
  {
    BasicSliderUI bsUI = (BasicSliderUI)((JSlider)getComponent(0)).getUI();
    addSlider(bsUI.valueForXPosition(point.x));
  }

  void addSlider(int value)
  {
    final JSlider slider = new SubSlider();
    slider.setFocusable(false);
    slider.setValue(value);
    if(getComponentCount()!=0)
    {
      slider.setOpaque(false);
      slider.setPaintTrack(false);
    }
    super.add(slider, 0);
    revalidate();
    repaint();
  }
}
于 2013-09-19T16:12:13.763 回答