I am creating a swing table cell renderer that should display an image as tooltip. This is the basic implementation:
The images are stored on the fileserver and managed using a document management system. We use a method to retrieve these files using their unique document id. This part cannot be changed.
Create a HashMap containing the image Id and the File object
This is the Renderer Method:
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
zebraPainter.paint(table, value, isSelected, hasFocus, row, column, this, false);
if (value != null) {
@SuppressWarnings({ "rawtypes", "unchecked" })
T bo = (T) (((DefaultBOTableModel) table.getModel()).getBusinessObject(row));
if (bo.getImageLink() != null) {
setToolTipText(getImageFile(bo.getImageLink()));
} else {
setToolTipText(null);
}
}
return this;
}
With T being the generic Object stored in the JTable.
This is the method that generated the tooltip HTML
private String getImageFile(final Integer documentId) {
if (documentId != null) {
final DocumentService docService = ResourceManager.get(DocumentService.class);
// check whether the document is already stored in imageMap. Use this if yes, download the image
// and put in the map if no.
File image = imageMap.get(documentId);
if (image == null) {
File myImage = docService.retrieveDocumentFile(new KeyObject(documentId, -1));
imageMap.put(documentId, myImage);
image = imageMap.get(documentId);
}
// URL of the image.
URL url;
try {
url = image.toURI().toURL();
} catch (MalformedURLException e) {
throw new MespasRuntimeException("Error generating image tooltip", e);
}
return "<html><img src='" + url + "'/></html>";
} else {
return null;
}
}
This works perfectly fine. However, as our tables can grow quite large (10'000 items can be displayed at once, this cannot be changed) and the user don't always have the best internet connection, this presents me with the following problem:
The images used to create the HTML tooltip are downloaded the moment the table is populated.
How can I changed this in a fashion, that the method
getImageFile()
is only called, when I perform a mouseover on the cell to make sure only the images that are actually being watched are downloaded?
You need to addMouseMotionListener
to detect when the mouse hovers over the image then you should access the generic object stored on the cell to get the link to call getImageFile()
.
The first process needs a condition inside mouseMoved
to count only movements from cell to another(not inside the cell).
The second needs to access the cell as a JComponent
to be able to set the tooltip image.
:
public static int rowh, colh;//global
...
table.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
int col = table.columnAtPoint(e.getPoint());
if (rowh != row || colh != col) { //movements from cell to cell inside the table.
rowh = row;
colh = col;
Object value = table.getModel().getValueAt(row, col);//get your Object value
TableCellRenderer cellRenderer = table.getCellRenderer(row, col);
Component rendererComponent = cellRenderer.getTableCellRendererComponent(table, null, false, true, row, col);
JComponent jcomp = (JComponent)rendererComponent;
//set the toolTip as you want.
T bo = (T) (((DefaultTableModel) table.getModel()).getBusinessObject(row));
if (bo.getImageLink() != null) {
jcomp.setToolTipText(getImageFile(bo.getImageLink()));
} else {
jcomp.setToolTipText(null);
}
}
}
@Override
public void mouseExited(MouseEvent e) {
rowh = -1;
colh = -1;
}
});