I'm trying to show multiple images in a component's tooltip, found createToolTip()
and implemented a custom that adds the needed components like this:
setComponent(component);
JPanel images = new JPanel(null);
images.setLayout(new BoxLayout(images, BoxLayout.X_AXIS));
for(ImageIcon icon:myIcons) {
images.add(new JLabel(icon));
}
JPanel content = new JPanel(new BorderLayout());
content.add(new JLabel(title), BorderLayout.NORTH);
content.add(new JLabel(description));
content.add(images, BorderLayout.SOUTH);
add(content);
However, all I see is a little dot, indicating that the tool tip is shown, but somehow the size is ignored. What do I miss implementing a custom tooltip?
The base "problems" are that JToolTip
- is-not designed as a container, it's only accidentally a container because JComponent is. For a Swing "not-container" its the responsibility of the ui-delegate to act as LayoutManager.
- isn't rich enough, it can handle text-only (at least with the emergency door html, which is @Andrew's favourite :-)
By-passing those limitations basically is a driving that widget nearly over the edge. A clean solution would roll a new component .. On the other hand, the OP already found the screws to tweak. The only thingy that could be slightly improved is to neither call setXXSize, nor set a custom ui. Instead, make it behave like a container by overriding getXXSize() like:
@Override
public Dimension getPreferredSize() {
if (getLayout() != null) {
return getLayout().preferredLayoutSize(this);
}
return super.getPreferredSize();
}
Tool tips can render HTML. If you can form URLs to the images (not practical if they are generated in memory but usually doable otherwise), it is an easy matter to write some HTML that will load the images, and use that HTML as the tool tip.
E.G.
import javax.swing.*;
class MultiIconToolTip {
public static void main(String[] args) throws Exception {
final String html =
"<html><body>" +
"<img src='" +
"http://i.stack.imgur.com/OVOg3.jpg" +
"' width=160 height=120> " +
"<img src='" +
"http://i.stack.imgur.com/lxthA.jpg" +
"' width=160 height=120>" +
"<p>Look Ma, no hands!";
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JLabel hover = new JLabel("Point at me!");
hover.setToolTipText(html);
JOptionPane.showMessageDialog(null, hover);
}
});
}
}
I'd suggest to using JWindow
or un_decorated JDialog
, as popup window (used by default for JCalendar
or JDatePicker
) rather than JTooltip
, for nicer output to the GUI implements Translucent and Shaped Windows
It might sound silly but, have you tried setting bounds for JPanel
?
setBounds(100, 100, 150, 50);
And you can try setting a gap between components in BorderLayout
JPanel content = new JPanel(new BorderLayout(1,1));
There are essentially two things missing. First of all, JToolTip
extends JComponent
, and unlike JPanel
, it doesn't have a default layout. To stretch the content
across the tooltip, use a BorderLayout
.
setLayout(new BorderLayout());
The second problem is the size. The ToolTipManager
respects the preferred size of the tool tip. While the BorderLayout
calculates the size, the ToolTipUI
ignores it. So, there are two alternatives: Manually set the preferred size...
setPreferredSize(content.getPreferredSize());
Note that this does not make the layout obsolete; otherwise, you get an empty tool tip with the right size.
... or subclass ToolTipUI
to respect the layout, which is what I went with. The resulting code is:
setComponent(StadtLabel.this);
JPanel images = new JPanel(null);
waren.setLayout(new BoxLayout(waren, BoxLayout.X_AXIS));
for(ImageIcon icon:myIcons) {
JLabel lbl = new JLabel(icon);
}
JPanel content = new JPanel(new BorderLayout());
content.add(new JLabel(title), BorderLayout.NORTH);
content.add(new JLabel(description));
content.add(images, BorderLayout.SOUTH);
setLayout(new BorderLayout());
add(content);
setUI(new ToolTipUI() {
@Override
public Dimension getMinimumSize(JComponent c) {
return c.getLayout().minimumLayoutSize(c);
}
@Override
public Dimension getPreferredSize(JComponent c) {
return c.getLayout().preferredLayoutSize(c);
}
@Override
public Dimension getMaximumSize(JComponent c) {
return getPreferredSize(c);
}
});
Instead of reinventing the wheel try this: https://github.com/timmolderez/balloontip. You can put any content as JComponent.