Search code examples
javaswingtooltiprenderer

Calculate ToolTip on Mouseover instead of loading the table


I am creating a swing table cell renderer that should display an image as tooltip. This is the basic implementation:

  1. 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.

  2. Create a HashMap containing the image Id and the File object

  3. The renderer checks whether the image Id is contained in the HashMap. If yes, the image will be loaded from the HashMap. If not, the Image should be downloaded.

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?


Solution

  • 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;
            }
        });