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

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

问题描述


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

基于,使用和测试由kleopatra和Hovercraft 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();
                }
            });
        }
    }
    

    EDIT2


    • (对于所有Win OS都不要使用Nimbus,Renderer非常有趣,从未见过,很棒!!!这怎么可能)

    EDIT3:

    注意我尽可能简化代码,在我的问题之前测试,然后再渲染渲染组件到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.

    以下是2个解决方案我可以提出:

    Here are 2 solutions I can come up with:


    • ActionListener 添加到组合框并调用 table.repaint()(易于操作)

    • 更改表模型并调用 fireTableCellUpdated(行,列) )用于相关单元格。

    • 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天全站免登陆