“Highlighting” specific rows in a JTable

前端 未结 2 1791
广开言路
广开言路 2020-12-18 17:06

I would like to highlight specific rows in a JTable whenever the contents of the a cell match with an input from the user. The following code is what I have that works thus

相关标签:
2条回答
  • 2020-12-18 17:44

    Generally, overriding methods on the basic Swing classes is a bad idea. The recommended approach is to create a Jcomponent that implements TableCellRenderer and apply it to the table with setDefaultRenderer(). Note that by default JTable supplies 3 of these for Object, Number, and Boolean types. Typically, a renderer looks something like this:

    public class MyRenderer extends JLable, implements TableCellRenderer{
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, 
             boolean isSelected, boolean hasFocus, int row, int column) {
        // Set up default state here 
        c.setBackground(Color.white);
        c.setForeground(Color.black);
        // ...
        if (!isRowSelected(row) ) {
            c.setBackground((hashMapcontainer
                    .containsKey(row)) ? Color.GREEN
                    : getBackground());
        }
        return c;
    }
    

    This gives you a reusable component, rather than needing to extend JTable every place you create it. As for the same cells selecting in all tables, that is due to isRowSelected and hashMapContainer accessing global state instead of per-instance state. All JComponents have getClientProperty and putClientProperty. These allow you to attach your own state object to a JTable. Then your isRowSelected becomes isRowSelected(table, row), which simply calls:

    MyObject myObj = (MyObject)table.getClientProperty("MySelectionProperty");
    myObj.isRowSelected(row);
    

    Like wise the hashMapContainer can also be retrieved from the table:

    MyHashContainer myHash = (MyHash)table.getClientProperty("MyHashContainer");
    

    Update:

    This is pretty much the same for a dynamically generated table. Table creation will look something like this:

    JTable t = new JTable();
    // other typical table setup, t.setModel(...); etc
    t.setDefaultRenderer(String.class, myRenderer);
    t.putClientProperty("MySelectionProperty", new MyObject());
    t.putClientProperty("MyHashContainer", new MyHashContainer());
    

    It's worth noting that as long as the renderer carries no state there is no need to create an instance per table. I'll usually create one and use it for all my tables.

    Here's an update to the renderer above that does not use global state, rather looks to the table for properties:

    public class MyRenderer extends JLable, implements TableCellRenderer{
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, 
            boolean isSelected, boolean hasFocus, int row, int column) {
    
            // Pull hashMapContainer from the per-table client properties
            MyHashContainer hashMapcontainer = (MyHashContainer)table.getClientProperty("MyHashContainer");
    
            // Set defaults as above            
    
            if (!isRowSelected(table, row) ) {
                // Same as above
            }
            return c;
        }
        // Private method to check for row selection
        private boolean isRowSelected(JTable t, int row) {
            int[] selectedRows = table.getSelectedRows();
            for (int i = 0; i < selectedRows.length; i++) {
                if (selectedRows[i] == row) {
                    return true;
                }
             }
             return false;
        }
    }
    
    0 讨论(0)
  • 2020-12-18 17:50

    The renderers are "rubber stamps". That basically means that they carry there previous settings over to the next cell.

    What you need to do is provide a "default" behavior

    if (!isRowSelected(row) ) {
        c.setBackground((hashMapcontainer
            .containsKey(row)) ? Color.GREEN
            : getBackground());
    } else {
    
        // Define the default background color
        // Don't forget to take into the selection state
    
    }
    

    While I personally think that prepareRenderer in this case is probably a fair solution, you really should explore the possibly of providing a base line renderer. This is a lot of work to get right but has the advantage of been portable (if you change table implementations) as well as allowing other people the chance to define the highlight rules of a given cell, which you've basically just gone and overridden, IMHO.

    I'd also suggest taking a look at JXTable as it has in built highlighting

    0 讨论(0)
提交回复
热议问题