Tooltip in labels in JSlider

2019-07-02 12:55发布

问题:

I want to create a JSlider with labels, which have a tooltip.

JSlider slider = new JSlider();
JLabel label = new JLabel("First");

slider.setPaintLabels(true);
Hashtable<Integer, JLabel> labels = new Hashtable<Integer, JLabel>();

label.setToolTipText("Tooltip");

labels.put(new Integer(0), label);
slider.setLabelTable(labels);

But, this code does not work. I think it's because we can add tooltip to JSlider, and it "covered" all others.

Is there a method, how I can resolve my problem?

回答1:

You would need to override the getToolTipText(MouseEvent) method.

Then in the code you would need to determine the mouse position in the slider to determine the text to display. I've never tried it but you might be able to use the BasicSliderUI for this. It has methods valueForXPosition and valueForYPosition which might help.



回答2:

Underlying reason for the obviously first try not working is that the labels are not added to the slider (as probably they should, given they are not too numerous anyway and the map is a map of real JLabels) but simply rendered on-the-fly in the paintHorizontal/VerticalLabel of BasicSliderUI. So Rob's advice the natural way to go: calculate if any of the labels is under the mousePosition and return its tooltip if available.

Astonishing, there is no public api (neither on JSlider nor on the ui delegate) to achieve the calculation of the label boundaries. What you would need is access to the x/yPositionForValue - but that's protected. So there are only dirty ways out

  • access the x/yPositionForValue reflectively
  • c&p and implement in a JSlider subclass: gives approximations only, as many of the ui internals are protected or even private

Would love to be proven wrong and see a clean implementation (without subclassing the ui-delegates :-)



回答3:

Here is how I did it. It is a little rough but it works fine. :)

    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseMotionListener;
    import javax.swing.JMenuItem;
    import javax.swing.JPopupMenu;
    import javax.swing.JSlider;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;

    /**
     *
     * @author VirtejF
     */
    public class MYJslider extends JSlider{

MYJslider ref=this;
JPopupMenu info=new JPopupMenu();
JMenuItem value=new JMenuItem();
int Ypos=0;

public MYJslider()
{
    super();
    //this.addMouseListener(new Handlerclass());
    this.addChangeListener(new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent ce) {
        JSlider slider = (JSlider)ce.getSource();
            slider.setToolTipText(slider.getValue()+"");
            value.setText(slider.getValue()+"");
    }
});
    this.addMouseListener(new Handlerclass());
    this.addMouseMotionListener(new mouseMotion());
    info.add(value);


}

public class Handlerclass implements MouseListener{

    @Override
    public void mousePressed(MouseEvent e) {
         info.setVisible(true);
         Ypos=e.getY()+20;
         info.show(e.getComponent(), e.getX()+15, Ypos); 
        }

    @Override
    public void mouseReleased(MouseEvent e) {
        info.setVisible(false);
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    @Override
    public void mouseClicked(MouseEvent e) {

    }

}

public class mouseMotion implements MouseMotionListener
{

    @Override
    public void mouseDragged(MouseEvent e) {
        //if(e.getX() > ref.getX() && e.getX() < ref.getX()+ref.getWidth())
        info.show(e.getComponent(), e.getX()+15, Ypos);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

}

}



回答4:

This works fine. Here is the source link

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.plaf.basic.BasicSliderUI;

class JSliderEX extends JFrame
{
  JSlider slider = new JSlider(0,100,0);
  public JSliderEX()
  {
    super("JSliderEX");
    setSize(300,80);
    setLocation(400,200);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    MySliderUI ms = new MySliderUI(slider,this);
    slider.setUI(ms);
    slider.setMajorTickSpacing(10);
    slider.setMinorTickSpacing(5);
    slider.setPaintTicks(true);
    slider.setPaintLabels(true);
    getContentPane().add(slider);
  }
  public static void main(String args[]){new JSliderEX().setVisible(true);}
}
class MySliderUI extends BasicSliderUI implements MouseMotionListener, MouseListener
{
  JPopupMenu pop = new JPopupMenu();
  JFrame parent;
  JLabel lblPop = new JLabel("",SwingConstants.CENTER);
  public MySliderUI(JSlider slider,JFrame p)
  {
    super(slider);
    slider.addMouseMotionListener(this);
    slider.addMouseListener(this);
    parent = p;
    JPanel jp = new JPanel();
    lblPop.setPreferredSize(new Dimension(30,12));
    jp.add(lblPop);
    pop.add(jp);
  }
  public void setPop(MouseEvent me)
  {
    lblPop.setText(""+slider.getValue());
    pop.setLocation((int)(parent.getX()+slider.getX()+me.getX()-10),
                   (int)(parent.getY()+slider.getY()));
  }
  public void mouseDragged(MouseEvent me){setPop(me);}
  public void mouseMoved(MouseEvent me){}
  public void mousePressed(MouseEvent me){pop.setVisible(true);setPop(me);}
  public void mouseClicked(MouseEvent me){}
  public void mouseReleased(MouseEvent me){pop.setVisible(false);}
  public void mouseEntered(MouseEvent me){}
  public void mouseExited(MouseEvent me){}
}