1

I already add a picture with JLabel in my JTable with TableCellRenderer. But how to add a border to the JLabel when mouse moves over the cell, on specific column and row?

This is the 1st renderer class:

public class RenderTabel implements TableCellRenderer{
@Override
public Component getTableCellRendererComponent(JTable table, Object 
value,boolean isSelected, boolean hasFocus,int row, int column){

   JLabel gambar=new JLabel();
   String url="D:\\Kuliah Semester 4\\Pemrograman Berorientasi Objek\\DINUS BOOKSTORE\\image";
   ImageIcon img=scalegmbr(url+"\\"+table.getModel().getValueAt(row, 0)+".png");
   gambar.setIcon(img);
   gambar.setText("");
   gambar.setHorizontalAlignment(SwingConstants.CENTER);


        table.setRowHeight(row, 50);


        table.getColumnModel().getColumn(column).setPreferredWidth(80); 
 return gambar;       
 }
  public  ImageIcon scalegmbr(String file){
   Image image=new ImageIcon(file).getImage();
   return new ImageIcon(image.getScaledInstance(80,50,SCALE_SMOOTH));
 }
 }

This is 2nd renderer class:

public class RenderTabel1 implements TableCellRenderer{
@Override
public Component getTableCellRendererComponent(JTable table, Object 
value,boolean isSelected, boolean hasFocus,int row, int column){

   JLabel gambar=new JLabel();
   String url="D:\\Kuliah Semester 4\\Pemrograman Berorientasi Objek\\DINUS BOOKSTORE\\image";
   ImageIcon img=scalegmbr(url+"\\"+table.getModel().getValueAt(row, 0)+".png");
   gambar.setIcon(img);
   gambar.setText("");
   gambar.setHorizontalAlignment(SwingConstants.CENTER);
  gambar.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(200, 100, 52), 2));

        table.setRowHeight(row, 50);


        table.getColumnModel().getColumn(column).setPreferredWidth(80); 
  return gambar;       
  }
   public  ImageIcon scalegmbr(String file){
   Image image=new ImageIcon(file).getImage();
   return new ImageIcon(image.getScaledInstance(80,50,SCALE_SMOOTH));
 }
}

and this is how I set the mouse enter and mouse clicked in my JTable:

private void tblbukuMouseEntered(java.awt.event.MouseEvent evt) {                                     
    // TODO add your handling code here: 



    tblbuku.getColumnModel().getColumn(6).setCellRenderer( new RenderTabel1());
}                                    

private void tblbukuMouseExited(java.awt.event.MouseEvent evt) {                                    
    // TODO add your handling code here:
    tblbuku.getColumnModel().getColumn(6).setCellRenderer( new RenderTabel());

}   

But this adds a border to all cells in column 6 when mouse moves ofer a cell of that column. How to change it only into specific row and column when mouse entered that row and column?

Hugues M.
  • 19,846
  • 6
  • 37
  • 65
Kevin
  • 23
  • 3
  • 1
    It would help greatly if you created and posted a valid [mcve], a small but complete program that only has necessary code to demonstrate your problem, that we can copy, paste, compile and run without modification, as this would help us to fully understand what you might be doing wrong. Note that this is code posted as code-formatted text and not as a link to an off-site resource. – Hovercraft Full Of Eels Jun 04 '17 at 15:00
  • Add mouse motion listener to component returned by cell renderer. – Antoniossss Jun 04 '17 at 15:34
  • already do that but no effect :( – Kevin Jun 04 '17 at 15:42

1 Answers1

4

So, for a particular column of your table, you want to paint a border on the cell that is hovered by the mouse (only the hovered cell, only in this column).

(edit: after clarification it appears that this question has been asked before -- I'm leaving my answer below as it might still help)

  • don't change the cell renderer dynamically, have only 1 renderer for that column, and handle that situation within the single renderer.

  • don't add listeners on the Component that is returned by the renderer: such listeners won't be triggered, as the component is only used for its paint()-ing logic.

  • instead, add a mouse motion listener on the table itself, and compute the coordinates of hovered cells with JTable's methods rowAtPoint and columnAtPoint, when mouse moves over table, or exits the area.

  • (irrelevant to problem at hand, but deserves a mention) Avoid creating a new JLabel for each call of your renderer, this is wasteful. Swing is single-thread, it's safe to reuse the same object (provided you don't forget to reset all its properties that might have changed between 2 calls)

Small demo that shows the effect:

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class SimpleTableDemo extends JPanel {

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(SimpleTableDemo::createAndShowGUI);
    }

    private int
            hoveredRow = -1,
            hoveredColumn = -1;

    SimpleTableDemo() {
        super(new GridLayout(1,0));

        String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"};

        Object[][] data = {
                {"Kathy", "Smith", "Snowboarding", 5, Boolean.FALSE},
                {"John", "Doe", "Rowing", 3, Boolean.TRUE},
                {"Sue", "Black", "Knitting", 2, Boolean.FALSE},
                {"Jane", "White", "Speed reading", 20, Boolean.TRUE},
                {"Joe", "Brown", "Pool", 10, Boolean.FALSE}
        };

        final JTable table = new JTable(data, columnNames);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);
        table.getColumn("Sport").setCellRenderer(new MyCellRenderer());

        table.addMouseMotionListener(new MouseAdapter() {
            public void mouseMoved(MouseEvent e) {
                Point p = e.getPoint();
                hoveredRow = table.rowAtPoint(p);
                hoveredColumn = table.columnAtPoint(p);
                table.repaint();
            }
            public void mouseExited(MouseEvent e) {
                hoveredRow = hoveredColumn = -1;
                table.repaint();
            }
        });

        JScrollPane scrollPane = new JScrollPane(table);

        add(scrollPane);
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        SimpleTableDemo newContentPane = new SimpleTableDemo();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);
        frame.pack();
        frame.setVisible(true);
    }

    private class MyCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (hoveredColumn == column && hoveredRow == row) {
                label.setBorder(BorderFactory.createLineBorder(Color.GREEN, 2));
            }
            else {
                label.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
            }
            return label;
        }
    }

}

Note 1: I'm using the default cell renderer, unlike you, but the same idea applies. The demo above is a generic example, that will be more useful as example to keep here than a specific solution for your case (for example, in my interpretation of the problem, I understand the details about icon are irrelevant).

Note 2: In the demo I repaint the whole visible area each time, but if you want to optimize it should be possible to repaint only 2 cells, that's an entire new question, see here for help about that.

Hugues M.
  • 19,846
  • 6
  • 37
  • 65