前一篇利用层实现ToolTip,利用图形组合实现不规则的ToolTip 是实现不规则窗体的ToolTip的方法,该方法虽然实现了要求,但却有两点不足:
第一:该方法太笨拙,每个需要ToolTip的组件都得重新去设置一次新的ToolTip类;
第二:在ToolTip超出窗体边缘时,没法显示超出部分。
于是乎觉得这样处理是不正确的,定有其他方法来更好的实现。所以在网上找了下。找了N久,还是在google中找到了比较满意的解决方法。而且该方法能解决上面的两点不足。
这里说下该方法的思想。
第一用到了
PopupFactory.setSharedInstance(PopupFactory popu)方法
这里为什么要用该方法呢?原来所有的Popup的获取都会从该PopupFactory中获取,所以在这里调用该方法设置用于获取 Popup 的 PopupFactory后系统的调用Popup就在我们的控制范围内了。
所以我们就必须得重新实现PopupFactory类来拦截对JToolTip的处理。
第二用到了实时截图并实时绘制截图,使得我们呈现出来的JToolTip窗体和其周围的内容没有出入。
先看效果:
下面贴出代码:
自己实现的PopupFactory类,这里主要拦截了JToolTip。
package com.michael.swingx.tooltip; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Robot; import java.awt.Shape; import java.awt.geom.Area; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import javax.swing.JComponent; import javax.swing.JToolTip; import javax.swing.Popup; import javax.swing.PopupFactory; import javax.swing.border.Border; public class NonRectanglePopupFactory extends PopupFactory { private static final int BORDER_PAD = 20; private static Robot robot; static { try { robot = new Robot(); } catch (Exception e) { } } public NonRectanglePopupFactory() { } @Override public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException { if (contents instanceof JToolTip) { ((JToolTip) contents).setBorder(null); Dimension dim = contents.getPreferredSize(); Rectangle bound = new Rectangle(x, y, dim.width + 2 * BORDER_PAD, dim.height + 2 * BORDER_PAD); /** * 这是关键创建包含从屏幕中读取的像素的图像。该图像不包括鼠标光标。 */ BufferedImage backgroundImage = robot.createScreenCapture(bound); NonRectangleFrame frame = new NonRectangleFrame(owner, contents, backgroundImage); return super.getPopup(owner, frame, x, y); } else return super.getPopup(owner, contents, x, y); } /** * * @author mengke * @email wqjsir@foxmail.com * @version 1.0 */ class NonRectangleFrame extends JComponent { public NonRectangleFrame(Component owner, Component content, BufferedImage backgroundImage) { setLayout(new BorderLayout()); add(content, BorderLayout.CENTER); setBorder(new NonRectangleBorder(owner, content, backgroundImage)); } } /** * @author mengke * @email wqjsir@foxmail.com * @version 1.0 */ class NonRectangleBorder implements Border { private BufferedImage leftImage; private BufferedImage rightImage; private BufferedImage topImage; private BufferedImage bottomImage; private Component content; private Color backColor = new Color(205, 235, 235); private Color borderColor = new Color(95, 145, 145); NonRectangleBorder(Component owner, Component content, BufferedImage backgroundImage) { this.content = content; // backColor = this.content.getBackground(); // borderColor = backColor.darker(); generateLeftImage(backgroundImage); generateTopImage(backgroundImage); generateRightImage(backgroundImage); generateBottomImage(backgroundImage); } @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { //绘制图形,这些图形是当前位置的截图图形 g.drawImage(leftImage, x, y, c); g.drawImage(rightImage, x + width - BORDER_PAD, y, c); g.drawImage(topImage, x + BORDER_PAD, y, c); g.drawImage(bottomImage, x + BORDER_PAD, y + height - BORDER_PAD, c); Rectangle bounds = new Rectangle(x, y, width, height); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(backColor); // 背景颜色 content.setBackground(backColor);//使背景色与填充的多边形颜色一致 g2d.fill(getArea(bounds.getSize())); g2d.setColor(borderColor); g2d.draw(getArea(bounds.getSize()));//画边框 g.setColor(Color.black); } /** * 返回画图所需要的区域<br> * 这里主要用到了图形合并共能。通过图形合并我们可以实现各种自定义的图形 * * @param dim * @return */ private Area getArea(Dimension dim) { int roundX = BORDER_PAD - 2; int roundY = BORDER_PAD - 2; Shape r = new RoundRectangle2D.Float(roundX, roundY, dim.width - roundX * 2, dim.height - roundY * 2, 5, 5); // 圆角矩形 Area area = new Area(r); Polygon polygon = new Polygon();// 多边形 polygon.addPoint(22, roundY); polygon.addPoint(35, roundY); polygon.addPoint(22, 0); area.add(new Area(polygon)); // 合并图形 return area; } @Override public Insets getBorderInsets(Component c) { return new Insets(BORDER_PAD, BORDER_PAD, BORDER_PAD, BORDER_PAD); } @Override public boolean isBorderOpaque() { return true; } private void generateLeftImage(BufferedImage backgroundImage) { leftImage = backgroundImage.getSubimage(0, 0, BORDER_PAD, backgroundImage.getHeight()); } private void generateTopImage(BufferedImage backgroundImage) { topImage = backgroundImage.getSubimage(BORDER_PAD, 0, backgroundImage.getWidth() - 2 * BORDER_PAD, BORDER_PAD); } private void generateRightImage(BufferedImage backgroundImage) { rightImage = backgroundImage.getSubimage(backgroundImage.getWidth() - BORDER_PAD, 0, BORDER_PAD, backgroundImage.getHeight()); } private void generateBottomImage(BufferedImage backgroundImage) { bottomImage = backgroundImage.getSubimage(BORDER_PAD, backgroundImage.getHeight() - BORDER_PAD, backgroundImage.getWidth() - 2 * BORDER_PAD, BORDER_PAD); } } }
测试类:
package com.michael.swingx.tooltip; import java.awt.Dimension; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.PopupFactory; import javax.swing.UIManager; /** *@author michael *@email wqjsir@foxmail.com *@version 1.0 */ public class TestToolTip extends JFrame{ /***/ private static final long serialVersionUID = 1L; public TestToolTip(){ JButton _btn = new JButton("ToolTip测试"); _btn.setToolTipText(_btn.getText()); JLabel _lb = new JLabel("<html>这是个Label,<br>这里测试ToolTip</html>"); _lb.setToolTipText(_lb.getText()); JPanel _plBody = new JPanel(); _plBody.add(_btn); _plBody.add(_lb); getContentPane().add(_plBody); setLocationRelativeTo(null); setSize(new Dimension(100,300)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main(String args[]) { try { /** *设置用于获取 Popup 的 PopupFactory。 */ PopupFactory.setSharedInstance(new NonRectanglePopupFactory()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ex) { } java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new TestToolTip().setVisible(true); } }); } }
原文参考:http://blog.sina.com.cn/s/blog_4b6047bc01000aue.html