【问题标题】:JTable: how to achieve custom rollover effect with TableCellRendererJTable:如何使用 TableCellRenderer 实现自定义翻转效果
【发布时间】:2017-11-05 10:14:47
【问题描述】:

我已经使用 TableCellRenderer 在我的 JTable 中添加了一张带有 JLabel 的图片。但是当鼠标在单元格上移动时,如何在特定列和行上为 JLabel 添加边框?

这是第一个渲染器类:

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

这是第二个渲染器类:

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

这就是我在 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());

}   

但是当鼠标移动该列的单元格时,这会为第 6 列中的所有单元格添加边框。鼠标进入该行列时如何只将其更改为特定行列?

【问题讨论】:

  • 如果您创建并发布了一个有效的minimal reproducible example 会很有帮助,这是一个小而完整的程序,只有必要的代码来演示您的问题,我们可以复制、粘贴、编译和运行而无需修改,因为这将帮助我们充分了解您可能做错了什么。请注意,这是作为代码格式文本发布的代码,而不是作为到场外资源的链接。
  • 向单元格渲染器返回的组件添加鼠标运动监听器。
  • 已经这样做了,但没有效果:(

标签: java swing jtable


【解决方案1】:

因此,对于表格的特定列,您希望在鼠标悬停的单元格上绘制边框(仅悬停的单元格,仅在此列中)。

(编辑:经过澄清后,this question has been asked before——我将在下面留下我的答案,因为它可能仍然有帮助)

  • 不要动态更改单元格渲染器,该列只有 1 个渲染器,并在单个渲染器中处理这种情况。

  • 不要在渲染器返回的Component 上添加侦听器:不会触发此类侦听器,因为该组件仅用于其paint()-ing 逻辑。

  • 改为在表格本身上添加鼠标运动侦听器,并在鼠标移动到表格上或退出该区域时,使用 JTable 的方法 rowAtPointcolumnAtPoint 计算悬停单元格的坐标.

  • (与手头的问题无关,但值得一提)避免为渲染器的每次调用创建新的JLabel,这很浪费。 Swing 是单线程的,重用同一个对象是安全的(前提是您不要忘记重置其所有可能在两次调用之间发生变化的属性)

展示效果的小demo:

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

}

注意 1:与您不同,我使用的是默认单元格渲染器,但同样的想法也适用。上面的演示是一个通用示例,作为示例保留在这里比针对您的案例的特定解决方案更有用(例如,在我对问题的解释中,我理解有关图标的详细信息是无关紧要的)。

注意 2:在演示中,我每次都重绘整个可见区域,但如果你想优化它应该可以只重绘 2 个单元格,这是一个全新的问题,请参阅 here 以获得有关帮助。

【讨论】:

  • 好的,我会试试,稍后告诉结果
  • @mKorbel 谢谢,添加了回答链接。现在 OP 确认它有效,可能值得优化。
猜你喜欢
  • 2017-01-02
  • 1970-01-01
  • 2012-02-18
  • 2017-12-16
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多