不规则窗体形状的ToolTip (二)

时间:2022-05-21 23:00:48

前一篇利用层实现ToolTip,利用图形组合实现不规则的ToolTip    是实现不规则窗体的ToolTip的方法,该方法虽然实现了要求,但却有两点不足:

第一:该方法太笨拙,每个需要ToolTip的组件都得重新去设置一次新的ToolTip类;

第二:在ToolTip超出窗体边缘时,没法显示超出部分。

   于是乎觉得这样处理是不正确的,定有其他方法来更好的实现。所以在网上找了下。找了N久,还是在google中找到了比较满意的解决方法。而且该方法能解决上面的两点不足。    

这里说下该方法的思想。

第一用到了

01.PopupFactory.setSharedInstance(PopupFactory popu)//方法  


这里为什么要用该方法呢?原来所有的Popup的获取都会从该PopupFactory中获取,所以在这里调用该方法设置用于获取 Popup 的 PopupFactory后系统的调用Popup就在我们的控制范围内了。

所以我们就必须得重新实现PopupFactory类来拦截对JToolTip的处理。

第二用到了实时截图并实时绘制截图,使得我们呈现出来的JToolTip窗体和其周围的内容没有出入。

先看效果:

不规则窗体形状的ToolTip (二)不规则窗体形状的ToolTip (二)

下面贴出代码:

自己实现的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);
}
});
}

}