package com.vistatec.ocelot.freme.gui; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.SystemColor; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; /** * Dialog having the appearance of a balloon tool tip. It is possible to specify * a custom Swing Component to be displayed into the balloon. */ public class BalloonTip extends JDialog implements ActionListener { /** Serial version UID. */ private static final long serialVersionUID = -7622023874939252456L; /** The custom component. */ private Component component; /** X position for the tool tip. */ private int x; /** Y position for the tool tip. */ private int y; /** * Constructor. * * @param owner * the owner window * @param component * the custom component * @param x * the x position for the tool tip. * @param y * the y position for the tool tip. */ public BalloonTip(Window owner, Component component, int x, int y) { super(); setModal(true); this.x = x; this.y = y; this.component = component; setUndecorated(true); } /** * Makes the UI for this dialog. */ public void makeUI() { setBackground(new Color(0, 0, 0, 0)); BalloonPanel panel = new BalloonPanel(0, 0, component.getWidth() + 50, component.getHeight() + 80, this); panel.add(component); add(panel); setSize(component.getWidth() + 50, component.getHeight() + 80); setLocation(x - panel.getPointerOffset(), y); setVisible(true); } public static void main(String[] args) { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); String marta = "Marta"; JLabel label = new JLabel(marta); FontMetrics metrics = label.getFontMetrics(label.getFont()); final int lblWidth = metrics.charsWidth(marta.toCharArray(), 0, marta.length()); final int lblHeight = metrics.getHeight(); label.setSize(new Dimension(lblWidth, lblHeight)); final BalloonTip bt = new BalloonTip(frame, label, 200, 300); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { frame.setVisible(true); bt.makeUI(); } }); } /** * Panel shaped as balloon. */ class BalloonPanel extends JPanel { /** The serial version UID. */ private static final long serialVersionUID = -2374203623407595249L; /** Balloon arrow half size constant. */ private static final int POINTER_HALF_SIZE = 20; /** Width of the round border. */ private static final int ROUND_BORDER_ARC_WIDTH = 20; /** x location for the balloon. */ private int x; /** y location for the balloon. */ private int y; /** * Constructor. * @param x the x location * @param y the y location * @param width the width * @param height the height * @param listener the action listener */ public BalloonPanel(final int x, final int y, int width, int height, ActionListener listener) { this.x = x; this.y = y; setSize(new Dimension(width, height)); setOpaque(true); JPanel panel = new JPanel(); panel.setBackground(new Color(0, 0, 0, 0)); panel.setPreferredSize(new Dimension(width, 20)); add(panel, BorderLayout.NORTH); //close button JButton btnClose = new JButton() { private static final long serialVersionUID = -6765879759340989663L; /* * (non-Javadoc) * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ @Override protected void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); g2d.setColor(Color.lightGray); g2d.setStroke(new BasicStroke(3f)); g2d.drawLine(7, 7, getWidth() - 7, getHeight() - 7); g2d.drawLine(7, getHeight() - 7, getWidth() - 7, 7); } /* * (non-Javadoc) * @see javax.swing.AbstractButton#paintBorder(java.awt.Graphics) */ @Override protected void paintBorder(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); g2d.setColor(Color.lightGray); g2d.drawRoundRect(1, 1, getWidth() - 2, getHeight() - 2, 9, 9); } }; btnClose.setOpaque(false); btnClose.setText("X"); btnClose.setPreferredSize(new Dimension(20, 20)); btnClose.addActionListener(listener); JPanel btnPanel = new JPanel( new FlowLayout(FlowLayout.RIGHT, 10, 0)); btnPanel.setBackground(new Color(0, 0, 0, 0)); btnPanel.setPreferredSize(new Dimension(width, 20)); btnPanel.add(btnClose); add(btnPanel); } /* * (non-Javadoc) * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ @Override protected void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); // set the color of the line borders. g2d.setColor(Color.lightGray); // set the thickness of the borders g2d.setStroke(new BasicStroke(1.5f)); // draw the rectangle with rounded corners. g2d.drawRoundRect(1, POINTER_HALF_SIZE, getWidth() - 2, getHeight() - POINTER_HALF_SIZE - 2, ROUND_BORDER_ARC_WIDTH, ROUND_BORDER_ARC_WIDTH); // draw the two lines for the pointer (upper triangle) int[] trLineXPoints = { getPointerOffset() - POINTER_HALF_SIZE, getPointerOffset(), getPointerOffset() + POINTER_HALF_SIZE }; int[] trLineYPoints = { POINTER_HALF_SIZE, 0, POINTER_HALF_SIZE }; g2d.drawPolyline(trLineXPoints, trLineYPoints, trLineXPoints.length); // set the color for the filling. It is the system color used for // info balloons. g2d.setColor(SystemColor.info); // fill the rounded rectangle. g2d.fillRoundRect(2, POINTER_HALF_SIZE + 1, getWidth() - 4, getHeight() - POINTER_HALF_SIZE - 4, ROUND_BORDER_ARC_WIDTH - 1, ROUND_BORDER_ARC_WIDTH - 1); // fill the poiinter. int[] trXPoints = { getPointerOffset() - POINTER_HALF_SIZE, getPointerOffset(), getPointerOffset() + POINTER_HALF_SIZE }; int[] trYPoints = { POINTER_HALF_SIZE + 1, 1, POINTER_HALF_SIZE + 1 }; g2d.fillPolygon(trXPoints, trYPoints, trXPoints.length); } /** * Gets the balloon pointer offset. * @return the balloon pointer offset. */ public int getPointerOffset() { return getWidth() / 2; } } /* * (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { dispose(); setVisible(false); } }