现在的位置: 首页 > 综合 > 正文

利用层实现ToolTip,利用图形组合实现不规则的ToolTip

2018年01月30日 ⁄ 综合 ⁄ 共 4963字 ⁄ 字号 评论关闭

利用层实现ToolTip,利用图形组合实现不规则的ToolTip。这里源码来自五斗米

先看效果:

 

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.text.View;

import sun.swing.SwingUtilities2;

/**
 * 用层来模拟ToolTip的部分功能,可以做出非规则形状
 */
public class Test {
    private JFrame frame = null;

    private Box box = null; // 为了将MyButton放到一个合适的位置,采用这个比较麻烦的Box来管理

    private MyButton button = null;


    public Test() {
	frame = new JFrame("MyToolTip");
	
	box = Box.createVerticalBox();
	button = new MyButton("Button");
	button.setMyToolTip(new MyToolTip(frame.getLayeredPane(), "向Java战友问好!"));
	
	box.add(Box.createVerticalGlue());
	Box box_ = Box.createHorizontalBox();
	box_.add(Box.createHorizontalGlue());
	box_.add(button);
	box_.add(Box.createHorizontalGlue());
	box.add(box_);
	box.add(Box.createVerticalGlue());
	
	frame.getContentPane().add(box, BorderLayout.CENTER);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	frame.setSize(360, 220);
	frame.setLocationRelativeTo(null);
	frame.setVisible(true);
    }

    public static void main(String args[]) {
	new Test();
    }

    class MyButton extends JButton implements MouseListener, ActionListener {
	private static final long serialVersionUID = -6373246716080645309L;
	private Timer timer = null;
	private MyToolTip tip = null;

	// JButton的构造很多,都可以适用
	public MyButton(String text) {
	    super(text);
	    timer = new Timer(500, this); // 构造定时器,这里使用的是javax.swing.Timer
	    this.addMouseListener(this);
	}

	// 设置MyToolTip
	public void setMyToolTip(MyToolTip tip) {
	    this.tip = tip;
	}

	public MyToolTip getMyToolTip() {
	    return tip;
	}

	@Override
	public void mouseClicked(MouseEvent e) {
	}

	// 当鼠标进入时显示,也可以加一个定时器来延时显示
	@Override
	public void mouseEntered(MouseEvent e) {
	    timer.start(); // 启动定时器
	}

	// 鼠标离开即消失
	@Override
	public void mouseExited(MouseEvent e) {
	    tip.setVisible(false);
	    timer.stop();
	}

	@Override
	public void mousePressed(MouseEvent e) {
	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	@Override
	public void actionPerformed(ActionEvent e) {
	    timer.stop();
	    Point p = getLocationOnScreen();
	    /**设置显示的位置*/
	    SwingUtilities.convertPointFromScreen(p, frame.getContentPane());
	    tip.setLocation(new Point(p.x - tip.getWidth() + 10, p.y
		    - tip.getHeight() + 10));
	    tip.setVisible(true);
	}

    }

    /**
     * 继承JPanel,因为可以设置透明,所以我们很容易就可以做出不规则形状来。
     * <br> 但是很遗憾,它的缺点是位置不能超出JFrame,否则超出部分无法显示
     */
    class MyToolTip extends JPanel {

	private static final long serialVersionUID = -1405474493135741335L;

	private String text = null; // 将要显示的字符串

	private JLayeredPane lp = null; // 我们要用到的层

	public MyToolTip(JLayeredPane lp, String text) {
	    this.lp = lp;
	    this.text = text;
	    this.setOpaque(false);
	    // 将组件放在弹出层中,这样就可以浮现在其它组件之上
	    lp.add(this, new Integer(JLayeredPane.POPUP_LAYER));
	    this.setSize(this.getPreferredSize());
	    this.setVisible(false); // 设置组件不可视
	}

	public void setText(String text) {
	    this.text = text;
	    this.setSize(this.getPreferredSize()); // 改变文字后需要重新计算Size
	}

	public String getText() {
	    return text;
	}

	public JLayeredPane getLp() {
	    return lp;
	}

	public void setLp(JLayeredPane lp) {
	    this.lp = lp;
	}

	/**
	 *  画背景和文字
	 */
	@Override
	protected void paintComponent(Graphics g) {
	    super.paintComponent(g);
	    Graphics2D g2d = (Graphics2D) g;
	    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		    RenderingHints.VALUE_ANTIALIAS_ON);
	    g2d.setColor(new Color(205, 235, 235)); // 背景颜色
	    g2d.fill(this.getArea(this.getSize()));
	    g2d.setColor(new Color(40, 130, 180)); // 文字颜色
	    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		    RenderingHints.VALUE_ANTIALIAS_OFF);
	    g2d.drawString(text, 25 / 2, (getHeight() - 10) / 2 + 5);
	}

	// 画边框
	@Override
	protected void paintBorder(Graphics g) {
	    super.paintBorder(g);
	    Graphics2D g2d = (Graphics2D) g;
	    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		    RenderingHints.VALUE_ANTIALIAS_ON);
	    g2d.setColor(new Color(95, 145, 145)); // 边线颜色
	    g2d.draw(this.getArea(this.getSize()));
	}

	/**
	 * 返回适合的Size
	 */
	@Override
	public Dimension getPreferredSize() {
	    Font font = getFont();
	    FontMetrics fm = getFontMetrics(font);
	    Insets insets = getInsets();
	    Dimension prefSize = new Dimension(insets.left + insets.right,
		    insets.top + insets.bottom);
	    if ((text == null) || text.equals("")) {
		text = "";
	    } else {
		View v = (this != null) ? (View) getClientProperty("html")
			: null;
		if (v != null) {
		    prefSize.width += (int) v.getPreferredSpan(View.X_AXIS);
		    prefSize.height += (int) v.getPreferredSpan(View.Y_AXIS);
		} else {
		    prefSize.width += SwingUtilities2.stringWidth(this, fm,
			    text) + 25; // 25为多加的部分
		    prefSize.height += fm.getHeight() + 10; // 10为多加的部分
		}
	    }
	    return prefSize;
	}

	/**
	 * 返回画图所需要的区域<br>
	 * 这里主要用到了图形合并共能。通过图形合并我们可以实现各种自定义的图形
	 * @param dim
	 * @return
	 */
	private Area getArea(Dimension dim) {
	    Shape r = new RoundRectangle2D.Float(0, 0, dim.width - 1,
		    dim.height - 10, 5, 5); // 圆角矩形
	    Area area = new Area(r);
	    Polygon polygon = new Polygon(); // 多边形
	    polygon.addPoint(dim.width - 15, dim.height - 10);
	    polygon.addPoint(dim.width - 5, dim.height - 10);
	    polygon.addPoint(dim.width, dim.height);
	    area.add(new Area(polygon)); // 合并图形
	    return area; 
	}

    }

}

 

抱歉!评论已关闭.