在弹出窗口中使用TextBubbleBorder [英] Using TextBubbleBorder in a popup
问题描述
首先,感谢安德鲁·汤普森(Andrew Thompson)关于圆角边界的解决方案角落.
First of all many thanks to Andrew Thompson for his solution about border with rounded corners.
现在是我的问题.我尝试在我们的应用程序中添加新增功能"(指向新组件的小气泡).除边框的透明功能外,其他所有功能均正常.这是我的MCVE(抱歉,它有点长,因为它包含Andrew编写的代码).
Now my problem. I try to add the "What's new" feature in our application (small bubble which points the new component). All works fine except the transparency feature of the border. Here is my MCVE (sorry it's a little bit long, because it contains the code written by Andrew).
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.TextAttribute;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import java.util.Collections;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.AbstractBorder;
/**
* <code>PopupTryout</code>.
*/
public class PopupTryout {
public static void main(String[] args) {
JFrame frm = new JFrame("Popup test");
JButton button = new JButton("Test");
JPanel p = new JPanel();
p.add(button);
frm.add(p, BorderLayout.SOUTH);
frm.add(new JScrollPane(new JTextArea()));
JPanel hintPanel = new JPanel();
hintPanel.add(new JLabel("This button has no function ;)"));
hintPanel.setOpaque(false);
JLabel closeBtn = new JLabel("Close");
closeBtn.setForeground(Color.BLUE);
closeBtn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
hintPanel.add(closeBtn);
hintPanel.setBorder(new TextBubbleBorder(Color.BLACK, 1, 6, 8, false));
frm.setSize(600, 500);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
Point pt = button.getLocationOnScreen();
Dimension panelSize = hintPanel.getPreferredSize();
Dimension buttonSize = button.getSize();
int x = pt.x + buttonSize.width - panelSize.width;
int y = pt.y - panelSize.height - 10;
// popup should only be closed when user clicks the "Close" button.
Popup popup = PopupFactory.getSharedInstance().getPopup(button, hintPanel, x, y);
popup.show();
// "link style" button
closeBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
Font f = e.getComponent().getFont();
e.getComponent().setFont(underlineOn(f));
}
@Override
public void mouseExited(MouseEvent e) {
e.getComponent().setFont(UIManager.getFont("Label.font"));
}
@Override
public void mousePressed(MouseEvent e) {
popup.hide();
}
});
}
/**
* Gets the underline font for the given base font.
*
* @param aBaseFont base font to paint it as underline.
* @return underline font.
*/
public static Font underlineOn(Font aBaseFont) {
return aBaseFont.deriveFont(Collections.singletonMap(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON));
}
static class TextBubbleBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
private boolean left = true;
RenderingHints hints;
TextBubbleBorder(Color color) {
this(color, 4, 8, 7);
}
TextBubbleBorder(Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness / 2;
hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + pointerSize + strokePad;
insets = new Insets(pad, pad, bottomPad, pad);
}
TextBubbleBorder(Color color, int thickness, int radii, int pointerSize, boolean left) {
this(color, thickness, radii, pointerSize);
this.left = left;
}
@Override
public Insets getBorderInsets(Component c) {
return insets;
}
@Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D) g;
int bottomLineY = height - thickness - pointerSize;
RoundRectangle2D.Double bubble =
new RoundRectangle2D.Double(0 + strokePad, 0 + strokePad, width - thickness, bottomLineY, radii, radii);
Polygon pointer = new Polygon();
if (left) {
// left point
pointer.addPoint(strokePad + radii + pointerPad, bottomLineY);
// right point
pointer.addPoint(strokePad + radii + pointerPad + pointerSize, bottomLineY);
// bottom point
pointer.addPoint(strokePad + radii + pointerPad + (pointerSize / 2), height - strokePad);
} else {
// left point
pointer.addPoint(width - (strokePad + radii + pointerPad), bottomLineY);
// right point
pointer.addPoint(width - (strokePad + radii + pointerPad + pointerSize), bottomLineY);
// bottom point
pointer.addPoint(width - (strokePad + radii + pointerPad + (pointerSize / 2)), height - strokePad);
}
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
// Paint the BG color of the parent, everywhere outside the clip
// of the text bubble.
Component parent = c.getParent();
if (parent != null) {
Color bg = parent.getBackground();
Rectangle rect = new Rectangle(0, 0, width, height);
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2.setClip(borderRegion);
g2.setColor(bg);
g2.fillRect(0, 0, width, height);
g2.setClip(null);
}
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
}
}
这是我得到的结果
如您所见,弹出窗口的底部不是透明的.我知道为什么会这样(最初的解决方案不适合这种情况),但是找不到解决方案.有什么想法吗?
As you can see, the bottom part of the popup is not transparent. I understand why it so (the initial solution is not suitable for this case), but can't find a solution to fix it. Any ideas?