TableCellRenderer 以及如何在不使用 JTable.repaint() 的情况下刷新单元格背景 [英] TableCellRenderer and how to refresh Cell background without using JTable.repaint()

查看:21
本文介绍了TableCellRenderer 以及如何在不使用 JTable.repaint() 的情况下刷新单元格背景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • 可以根据外部值正确刷新背景,无需强制重绘 table.repaint();

基于、使用和测试由 kleopatra 和气垫船 Full Of Eels 编写的优秀代码

对 Java6/7 有效,因为 API 没有任何变化

valid for Java6/7, because there weren't any changes in APIs

我的 SSCCE 工作正常,由 JTable.repaint() 重新绘制

my SSCCE works correctly, repainted by JTable.repaint()

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class MyTableAndRenderer {

    private JFrame frame = new JFrame();
    private JPanel panel = new JPanel();
    private String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"};
    private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(items);
    private JComboBox combo = new JComboBox(comboBoxModel);
    private JPanel panel1 = new JPanel();
    private String[] columnNames = {"First Name", "Last Name", "Sport",
        "# of Years", "Vegetarian"};
    private Object[][] data = {
        {"Kathy", "Smith", "Item 1", new Integer(5), (false)},
        {"John", "Doe", "Item 1", new Integer(3), (true)},
        {"Sue", "Black", "Item 3", new Integer(2), (false)},
        {"Jane", "White", "Item 3", new Integer(20), (true)},
        {"Joe", "Brown", "Item 3", new Integer(10), (false)}
    };
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
        private static final long serialVersionUID = 1L;

        @Override
        public Class getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };
    private JTable table = new JTable(model);

    public MyTableAndRenderer() {
        panel.setBorder(new EmptyBorder(10, 0, 2, 0));
        panel.add(combo);
        //@HFOE
        /*table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                    super.getTableCellRendererComponent(table, value, isSelected,
                        hasFocus, row, column);
                String str = combo.getSelectedItem().toString();
                if (value.toString().equalsIgnoreCase(str)) {
                    setBackground(Color.RED);
                } else {
                    setBackground(null);
                }
                return this;
            }
        });*/
        //@kleopatra
        /*table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                String str = combo.getSelectedItem().toString();
                if (value.toString().equalsIgnoreCase(str)) {
                    setBackground(Color.RED);
                } else {
                    setBackground(null);
                }
                super.getTableCellRendererComponent(table, value, isSelected,
                        hasFocus, row, column);
                return this;
            }
        });*/
        table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                super.getTableCellRendererComponent(table, value, isSelected,
                        hasFocus, row, column);
                String str = combo.getSelectedItem().toString();
                if (value.toString().equalsIgnoreCase(str)) {
                    setBackground(Color.RED);
                    table.repaint();
                } else {
                    setBackground(null);
                    table.repaint();
                }
                return this;
            }
        });
        table.getTableHeader().setReorderingAllowed(false);
        table.setAutoCreateRowSorter(true);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        panel1.setLayout(new GridLayout(1, 1, 10, 10));
        panel1.add(new JScrollPane(table));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel, BorderLayout.NORTH);
        frame.add(panel1);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyTableAndRenderer fs = new MyTableAndRenderer();
            }
        });
    }
}

编辑

@Devolus 写道 你测试过我发布的内容吗?我从我自己的工作代码中获取了这个片段,我只是删除了中间的内容,因为它与答案无关.我在这里使用 Java 6,这对我有用.

@Devolus wrote Did you test what I posted? I took this snippet from my own working code, I just removed the stuff inbetween as it is not relevant for the answer. I'm using Java 6 here and this works for me.

public Component getTableCellRendererComponent(JTable table,
        Object value,
        boolean isSelected,
        boolean hasFocus, 
        int row, int column) 
{

    Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

    ... determine the color value ...

    cell.setBackground(back);
    cell.setForeground(fore);
}

  • 导致
    • 与 Java6/7 无关

    来自代码(发布 SSCCE 的原因)

    from code (reason to post an SSCCE)

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.GridLayout;
    import javax.swing.DefaultComboBoxModel;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.SwingUtilities;
    import javax.swing.border.EmptyBorder;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.DefaultTableModel;
    
    public class MyTableAndRenderer {
    
        private JFrame frame = new JFrame();
        private JPanel panel = new JPanel();
        private String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"};
        private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(items);
        private JComboBox combo = new JComboBox(comboBoxModel);
        private JPanel panel1 = new JPanel();
        private String[] columnNames = {"First Name", "Last Name", "Sport",
            "# of Years", "Vegetarian"};
        private Object[][] data = {
            {"Kathy", "Smith", "Item 1", new Integer(5), (false)},
            {"John", "Doe", "Item 1", new Integer(3), (true)},
            {"Sue", "Black", "Item 3", new Integer(2), (false)},
            {"Jane", "White", "Item 3", new Integer(20), (true)},
            {"Joe", "Brown", "Item 3", new Integer(10), (false)}
        };
        private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
            private static final long serialVersionUID = 1L;
    
            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
        };
        private JTable table = new JTable(model);
    
        public MyTableAndRenderer() {
            panel.setBorder(new EmptyBorder(10, 0, 2, 0));
            panel.add(combo);
            table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
                @Override
                public Component getTableCellRendererComponent(JTable table,
                        Object value, boolean isSelected, boolean hasFocus,
                        int row, int column) {
                    Component c = super.getTableCellRendererComponent(table, value, isSelected,
                            hasFocus, row, column);
                    String str = combo.getSelectedItem().toString();
                    if (value.toString().equalsIgnoreCase(str)) {
                        c.setBackground(Color.RED);
                    } else {
                        c.setBackground(null);
                    }
                    return this;
                }
            });
            table.getTableHeader().setReorderingAllowed(false);
            table.setAutoCreateRowSorter(true);
            table.setPreferredScrollableViewportSize(table.getPreferredSize());
            panel1.setLayout(new GridLayout(1, 1, 10, 10));
            panel1.add(new JScrollPane(table));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(panel, BorderLayout.NORTH);
            frame.add(panel1);
            frame.pack();
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    MyTableAndRenderer fs = new MyTableAndRenderer();
                }
            });
        }
    }
    

    编辑2

    • 来自 WinXp(对于所有 Win 操作系统不要使用 Nimbus,渲染器在那里很有趣,从未见过,太棒了!!!这怎么可能)

    编辑 3:

    注意我尽可能简化了代码,在我的问题之前进行了测试,然后将渲染组件转换为 JComponent/JLabel 也不起作用(使用 JLabel.repaint()/setOpaque())

    note I'm simplified code as is possible, tested before my question here, then casting Rendering Component to JComponent/JLabel doesn't works too (with JLabel.repaint()/setOpaque())

    推荐答案

    当您更改所选项目时会出现此问题.您的组合框和表格之间存在一些隐式交互(组合框的选定项目会影响表格的绘制方式).

    The issue occurs when you change the selected item. You have some implicit interaction between your combobox and you table (the selected item of the combo box influences the way the table is painted).

    当comboboxpopup隐藏时,它会自动触发悬停区域的重绘(RepaintManager只会重绘悬停区域,而不是整个表格).但与此同时,您更改了表格单元格的绘制方式(第一个单元格不再绘制为红色,因为它们不再与选择匹配).但是,重绘管理器强制只重绘表格的一小部分区域,该区域没有完全覆盖红色单元格,因此您会看到这些视觉故障.

    When the comboboxpopup is hidden, it automatically triggers a repaint of the hovered area (the RepaintManager will only repaint the hovered area, not the complete table). But in the meantime, you have changed the way the cells of the table are painted (the first cells are no longer painted in red because they don't match the selection anymore). However, the repaint manager forces to repaint only a small area of the table which does not cover completely the red cells, hence you see those visual glitches.

    这里有两个我能想到的解决方案:

    Here are 2 solutions I can come up with:

    • 向组合框添加一个 ActionListener 并调用 table.repaint()(容易做到)
    • 更改您的表格模型并为相关单元格调用 fireTableCellUpdated(row, column).
    • Add an ActionListener to the combobox and invoke table.repaint() (easy to do)
    • Change your table model and call fireTableCellUpdated(row, column) for the relevant cells.

    SSCCE 用于第二个解决方案:

    SSCCE for the second solution:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.DefaultComboBoxModel;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.SwingUtilities;
    import javax.swing.border.EmptyBorder;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.DefaultTableModel;
    
    public class MyTableAndRenderer {
    
        private final class DefaultTableModelExtension extends DefaultTableModel {
            private static final long serialVersionUID = 1L;
    
            private String selected;
    
            private DefaultTableModelExtension(Object[][] data, Object[] columnNames) {
                super(data, columnNames);
            }
    
            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
    
            public String getSelected() {
                return selected;
            }
    
            public void setSelected(String selected) {
                if (this.selected == null && selected == null || this.selected != null && this.selected.equalsIgnoreCase(selected)) {
                    return;
                }
                class Cell {
                    public final int row;
                    public final int column;
    
                    public Cell(int row, int column) {
                        super();
                        this.row = row;
                        this.column = column;
                    }
                }
                List<Cell> updatedCells = new ArrayList<Cell>();
                if (this.selected != null) {
                    for (int i = 0; i < data.length; i++) {
                        Object[] o = data[i];
                        for (int j = 0; j < o.length; j++) {
                            Object object = o[j];
                            if (this.selected.toString().equalsIgnoreCase(object.toString())) {
                                updatedCells.add(new Cell(i, j));
                            }
                        }
                    }
                }
                this.selected = selected;
                if (this.selected != null) {
                    for (int i = 0; i < data.length; i++) {
                        Object[] o = data[i];
                        for (int j = 0; j < o.length; j++) {
                            Object object = o[j];
                            if (this.selected.toString().equalsIgnoreCase(object.toString())) {
                                updatedCells.add(new Cell(i, j));
                            }
                        }
                    }
                }
                for (Cell pair : updatedCells) {
                    fireTableCellUpdated(pair.row, pair.column);
                }
            }
        }
    
        private JFrame frame = new JFrame();
        private JPanel panel = new JPanel();
        private String[] items = { "Item 1", "Item 2", "Item 3", "Item 4" };
        private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(items);
        private JComboBox combo = new JComboBox(comboBoxModel);
        private JPanel panel1 = new JPanel();
        private String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" };
        private Object[][] data = { { "Kathy", "Smith", "Item 1", new Integer(5), false }, { "John", "Doe", "Item 1", new Integer(3), true },
                { "Sue", "Black", "Item 3", new Integer(2), false }, { "Jane", "White", "Item 3", new Integer(20), true },
                { "Joe", "Brown", "Item 3", new Integer(10), false } };
        private DefaultTableModelExtension model = new DefaultTableModelExtension(data, columnNames);
        private JTable table = new JTable(model);
    
        public MyTableAndRenderer() {
            panel.setBorder(new EmptyBorder(10, 0, 2, 0));
            panel.add(combo);
            combo.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    updateSelected();
                }
    
            });
            // Need first synch
            updateSelected();
            table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
                        int column) {
                    Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                    String str = combo.getSelectedItem().toString();
                    if (value.toString().equalsIgnoreCase(str)) {
                        c.setBackground(Color.RED);
                    } else {
                        c.setBackground(null);
                    }
                    return this;
                }
            });
            table.getTableHeader().setReorderingAllowed(false);
            table.setAutoCreateRowSorter(true);
            table.setPreferredScrollableViewportSize(table.getPreferredSize());
            panel1.setLayout(new GridLayout(1, 1, 10, 10));
            panel1.add(new JScrollPane(table));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(panel, BorderLayout.NORTH);
            frame.add(panel1);
            frame.pack();
            frame.setVisible(true);
        }
    
        private void updateSelected() {
            model.setSelected((String) combo.getSelectedItem());
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    MyTableAndRenderer fs = new MyTableAndRenderer();
                }
            });
        }
    }
    

    这篇关于TableCellRenderer 以及如何在不使用 JTable.repaint() 的情况下刷新单元格背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆