How can I put a control in the JTableHeader of a JTable?

前端 未结 3 1884
深忆病人
深忆病人 2020-11-22 00:12

Given a JTable with a column of type Boolean.class, the default renderer is a JCheckBox. It\'s easy enough to select individual cells based on a us

3条回答
  •  太阳男子
    2020-11-22 00:32

    enter image description here

    Use a custom TableCellRenderer:

        // column 1
        col = table.getColumnModel().getColumn(1);
        col.setHeaderRenderer(new EditableHeaderRenderer( new JButton("Button")));
        // column 2     
        col = table.getColumnModel().getColumn(2);
        col.setHeaderRenderer(new EditableHeaderRenderer( new JToggleButton("Toggle")));
        // column 3
        col = table.getColumnModel().getColumn(3);
        col.setHeaderRenderer(new EditableHeaderRenderer( new JCheckBox("CheckBox")));
    
    
    
    class EditableHeaderRenderer implements TableCellRenderer {
    
        private JTable table = null;
        private MouseEventReposter reporter = null;
        private JComponent editor;
    
        EditableHeaderRenderer(JComponent editor) {
            this.editor = editor;
            this.editor.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
        }
    
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
            if (table != null && this.table != table) {
                this.table = table;
                final JTableHeader header = table.getTableHeader();   
                if (header != null) {   
                    this.editor.setForeground(header.getForeground());   
                    this.editor.setBackground(header.getBackground());   
                    this.editor.setFont(header.getFont());
                    reporter = new MouseEventReposter(header, col, this.editor);
                    header.addMouseListener(reporter);
                }
            }
    
            if (reporter != null) reporter.setColumn(col);
    
            return this.editor;
        }
    
        static public class MouseEventReposter extends MouseAdapter {
    
            private Component dispatchComponent;
            private JTableHeader header;
            private int column  = -1;
            private Component editor;
    
            public MouseEventReposter(JTableHeader header, int column, Component editor) {
                this.header = header;
                this.column = column;
                this.editor = editor;
            }
    
            public void setColumn(int column) {
                this.column = column;
            }
    
            private void setDispatchComponent(MouseEvent e) {
                int col = header.getTable().columnAtPoint(e.getPoint());
                if (col != column || col == -1) return;
    
                Point p = e.getPoint();
                Point p2 = SwingUtilities.convertPoint(header, p, editor);
                dispatchComponent = SwingUtilities.getDeepestComponentAt(editor, p2.x, p2.y);
            }
    
            private boolean repostEvent(MouseEvent e) {
                if (dispatchComponent == null) {
                    return false;
                }
                MouseEvent e2 = SwingUtilities.convertMouseEvent(header, e, dispatchComponent);
                dispatchComponent.dispatchEvent(e2);
                return true;
            }
    
            @Override
            public void mousePressed(MouseEvent e) {
                if (header.getResizingColumn() == null) {
                    Point p = e.getPoint();
    
                    int col = header.getTable().columnAtPoint(p);
                    if (col != column || col == -1) return;
    
                    int index = header.getColumnModel().getColumnIndexAtX(p.x);
                    if (index == -1) return;
    
                    editor.setBounds(header.getHeaderRect(index));
                    header.add(editor);
                    editor.validate();
                    setDispatchComponent(e);
                    repostEvent(e);
                }
            }
    
            @Override
            public void mouseReleased(MouseEvent e) {
                repostEvent(e);
                dispatchComponent = null;
                header.remove(editor);
            }
        }
    }
    

    Please note that components with popupmenu (e.g. JComboBox or JMenu) don't work well. See: JComboBox fails to expand in JTable TableHeader). But you can use a MenuButton in the TableHeader:

    enter image description here

    class MenuButtonTableHeaderRenderer extends JPanel implements TableCellRenderer {
    
        private int     column  = -1;
        private JTable  table   = null;
        private MenuButton b;
    
        MenuButtonTableHeaderRenderer(String name, JPopupMenu menu) {
            super(new BorderLayout());
            b = new MenuButton(ResourceManager.ARROW_BOTTOM, menu);
            b.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
            JLabel l = new JLabel(name);
            l.setFont(l.getFont().deriveFont(Font.PLAIN));
            l.setBorder(BorderFactory.createEmptyBorder(1,5,1,1));
            add(b, BorderLayout.WEST);
            add(l, BorderLayout.CENTER);
            setBorder(UIManager.getBorder("TableHeader.cellBorder"));
        }
    
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
    
            if (table != null && this.table != table) {
                this.table = table;
                final JTableHeader header = table.getTableHeader();   
                if (header != null) {   
                    setForeground(header.getForeground());   
                    setBackground(header.getBackground());   
                    setFont(header.getFont());
    
                    header.addMouseListener(new MouseAdapter() {
    
                        @Override
                        public void  mouseClicked(MouseEvent e) {
                            int col = header.getTable().columnAtPoint(e.getPoint());
                            if (col != column || col == -1) return;
    
                            int index = header.getColumnModel().getColumnIndexAtX(e.getPoint().x);
                            if (index == -1) return;
    
                            setBounds(header.getHeaderRect(index));
                            header.add(MenuButtonTableHeaderRenderer.this);
                            validate();
    
                            b.doClick();
    
                            header.remove(MenuButtonTableHeaderRenderer.this);
    
                            header.repaint();   
                        }
                    });
                }
            }
            column = col;
            return this;
        }
    }
    

提交回复
热议问题