Highlighting a column header of a JTable

后端 未结 2 824
伪装坚强ぢ
伪装坚强ぢ 2021-01-02 23:57

i\'m currently building a little JTable, and want to highlight the column header (and row headers - the row-header part is actually working) when a cell is selected to make

相关标签:
2条回答
  • 2021-01-03 00:34

    A slight variant: as I read the question, the main problem is the header not updating on column selection change. Having a custom header listen to row selection changes doesn't help much for that scenario.

    In fact, a JTableHeader already is listening to the ColumnModel and the model's change notification includes selection changes. Only the columnSelectionChange method is intentionally implemented to do nothing:

    // --Redrawing the header is slow in cell selection mode.
    // --Since header selection is ugly and it is always clear from the
    // --view which columns are selected, don't redraw the header.
    

    A custom header can simply implement to repaint (here lazy me does it in the table's factory method just to spare me the wiring to the table, you can easily make it a stand-alone class :-).

    final JTable table = new JTable(new AncientSwingTeam()) {
    
        @Override
        protected JTableHeader createDefaultTableHeader() {
            // subclassing to take advantage of super's auto-wiring
            // as ColumnModelListener
            JTableHeader header = new JTableHeader(getColumnModel()) {
    
                @Override
                public void columnSelectionChanged(ListSelectionEvent e) {
                    repaint();
                }
    
            };
            return header;
        }
    
    };
    table.setCellSelectionEnabled(true);
    table.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer());
    

    Also tweaked Mad's renderer a bit, using table api:

    /**
     * Slightly adjusted compared to @Mad
     * - use table's selectionBackground
     * - use table's isColumnSelected to decide on highlight
     */
    public static class ColumnHeaderRenderer extends DefaultTableCellHeaderRenderer {
    
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean selected,  
            boolean focused, int row, int column) {
            super.getTableCellRendererComponent(table, value, selected, focused, row, column); 
            if (table.isColumnSelected(column)) {
                setBackground(table.getSelectionBackground());
            }
            return this;
        }
    }
    

    As to the observation:

    always says isSelected is false

    The reason is a slight quirk in BasicTableHeaderUI:

    ui.selected != columnModel.selected
    

    uiSelected is the column which will be accessible to keybindings - if the laf supports it and the header is focusOwner. Doesn't really make sense to me, but fully defining the semantics of ui and columnModel selection fell into the excitement about the new babe fx, that is got forgotten ;-)

    0 讨论(0)
  • 2021-01-03 00:41

    The basic issue I had was there was no connection between the table header and the selection change. In fact, the header is really clever with it's repaints...

    I ended up providing my own header, which attached a listener to the table's selection model and repainted the header on the selection changed.

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.EventQueue;
    import java.util.List;
    import javax.swing.Icon;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.RowSorter;
    import javax.swing.RowSorter.SortKey;
    import static javax.swing.SortOrder.ASCENDING;
    import static javax.swing.SortOrder.DESCENDING;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.DefaultTableModel;
    import javax.swing.table.JTableHeader;
    
    public class TestColumnHighlight {
    
        public static void main(String[] args) {
            new TestColumnHighlight();
        }
    
        public TestColumnHighlight() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JTable table = new JTable();
                    DefaultTableModel model = new DefaultTableModel(
                                    new Object[]{"abc", "def", "ghi", "jkl"},
                                    0);
    
                    model.addRow(new Object[]{0, 0, 0, 0});
                    model.addRow(new Object[]{0, 0, 0, 0});
                    model.addRow(new Object[]{0, 0, 0, 0});
                    model.addRow(new Object[]{0, 0, 0, 0});
                    model.addRow(new Object[]{0, 0, 0, 0});
    
                    table.setModel(model);
                    table.setTableHeader(new CustomTableHeader(table));
                    table.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer());
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new JScrollPane(table));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class CustomTableHeader extends JTableHeader {
    
            public CustomTableHeader(JTable table) {
                super();
                setColumnModel(table.getColumnModel());
                table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
                    @Override
                    public void valueChanged(ListSelectionEvent e) {
                        repaint();
                    }
                });
            }
    
            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
                repaint();
            }
    
        }
    
        public class ColumnHeaderRenderer extends DefaultTableHeaderCellRenderer {
    
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
                super.getTableCellRendererComponent(table, value, selected, focused, row, column);
    
                int selectedColumn = table.getSelectedColumn();
                System.out.println("Selected " + selectedColumn + "-" + column);
                if (selectedColumn == column) {
                    Color bg = table.getSelectionBackground();
                    setBackground(bg);
                    setOpaque(true);
                } else {
                    setOpaque(false);
                }
    
                return this;
            }
    
        }
    
        public class DefaultTableHeaderCellRenderer extends DefaultTableCellRenderer {
    
            public DefaultTableHeaderCellRenderer() {
                setHorizontalAlignment(CENTER);
                setHorizontalTextPosition(LEFT);
                setVerticalAlignment(BOTTOM);
                setOpaque(false);
            }
    
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                            boolean isSelected, boolean hasFocus, int row, int column) {
                super.getTableCellRendererComponent(table, value,
                                isSelected, hasFocus, row, column);
                JTableHeader tableHeader = table.getTableHeader();
                if (tableHeader != null) {
                    setForeground(tableHeader.getForeground());
                }
                setIcon(getIcon(table, column));
                setBorder(UIManager.getBorder("TableHeader.cellBorder"));
                return this;
            }
    
            protected Icon getIcon(JTable table, int column) {
                SortKey sortKey = getSortKey(table, column);
                if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) {
                    switch (sortKey.getSortOrder()) {
                        case ASCENDING:
                            return UIManager.getIcon("Table.ascendingSortIcon");
                        case DESCENDING:
                            return UIManager.getIcon("Table.descendingSortIcon");
                    }
                }
                return null;
            }
    
            protected SortKey getSortKey(JTable table, int column) {
                RowSorter rowSorter = table.getRowSorter();
                if (rowSorter == null) {
                    return null;
                }
    
                List sortedColumns = rowSorter.getSortKeys();
                if (sortedColumns.size() > 0) {
                    return (SortKey) sortedColumns.get(0);
                }
                return null;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题