JTable:如何用TableCellRenderer实现自定义翻转效果
JTable: how to achieve custom rollover effect with TableCellRenderer
我已经使用 TableCellRenderer 在我的 JTable 中添加了一张带有 JLabel 的图片。但是当鼠标移到特定列和行的单元格上时,如何为 JLabel 添加边框?
这是第一个渲染器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));
}
}
这是第二个渲染器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));
}
}
这就是我在 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 列中的所有单元格添加边框。如何在鼠标进入特定的行和列时只改变它为特定的行和列?
因此,对于您的 table 的特定列,您想在鼠标悬停的单元格上绘制边框(仅悬停的单元格,仅在该列中)。
(编辑:澄清后似乎 this question has been asked before -- 我将我的答案留在下面,因为它可能仍然有帮助)
不要动态更改单元格渲染器,该列只有 1 个渲染器,并在单个渲染器中处理这种情况。
不要在渲染器返回的 Component
上添加侦听器:不会触发此类侦听器,因为该组件仅用于其 paint()
-ing 逻辑。
相反,在 table 本身上添加鼠标移动侦听器,并使用 JTable
的方法 rowAtPoint
和 [= 计算悬停单元格的坐标15=],当鼠标移到table,或离开该区域时。
(与手头的问题无关,但值得一提)避免为渲染器的每次调用创建一个新的 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:在demo中我每次重绘整个可见区域,但如果你想优化应该可以只重绘2个单元格,这是一个全新的问题,请参阅here寻求帮助关于那个。
我已经使用 TableCellRenderer 在我的 JTable 中添加了一张带有 JLabel 的图片。但是当鼠标移到特定列和行的单元格上时,如何为 JLabel 添加边框?
这是第一个渲染器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));
}
}
这是第二个渲染器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));
}
}
这就是我在 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 列中的所有单元格添加边框。如何在鼠标进入特定的行和列时只改变它为特定的行和列?
因此,对于您的 table 的特定列,您想在鼠标悬停的单元格上绘制边框(仅悬停的单元格,仅在该列中)。
(编辑:澄清后似乎 this question has been asked before -- 我将我的答案留在下面,因为它可能仍然有帮助)
不要动态更改单元格渲染器,该列只有 1 个渲染器,并在单个渲染器中处理这种情况。
不要在渲染器返回的
Component
上添加侦听器:不会触发此类侦听器,因为该组件仅用于其paint()
-ing 逻辑。相反,在 table 本身上添加鼠标移动侦听器,并使用
JTable
的方法rowAtPoint
和 [= 计算悬停单元格的坐标15=],当鼠标移到table,或离开该区域时。(与手头的问题无关,但值得一提)避免为渲染器的每次调用创建一个新的
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:在demo中我每次重绘整个可见区域,但如果你想优化应该可以只重绘2个单元格,这是一个全新的问题,请参阅here寻求帮助关于那个。