Customizing JTable's JTabelHeader

200 views Asked by At

I have an application with several custom JXTables (an extension of JTable) that are updated to reflect information stored in a database.

I would like to add components at the top of the table, above the column headers, that would allow the user to search and filter results within the table. Currently, I've tried creating a JPanel with JTextFields that are added/removed/moved and resized based on a TableColumnModelListener attached to the table, and a PropertyChangeListener attached to each TableColumn.

This is what it currently looks like:

http://i.imgur.com/7bnR36y.jpg

The problem I'm having is that I use the jgoodies jforms layout for almost everything. In this specific panel, I'm just using a BoxLayout, and the components will resize (almost) perfectly, but start pushing off the screen or disappearing once I add/remove columns.

Based on the image and what I'm wanting it to do, does anyone have a suggestion on either A) how to effectively bind the components to the location/size of each column, or B) how to customize the table's columns themselves and add additional components on top of them?

Here's the code if it helps:

    private final KTable table;
    private final ArrayList<Object> columnIds = new ArrayList<>();
    private final ArrayList<JTextField> filters = new ArrayList<>();

    private final PropertyChangeListener pcm = new PropertyChangeListener() {           
        @Override           
        public void propertyChange(PropertyChangeEvent evt) {              
            switch (evt.getPropertyName()) {
                case "width":
                case "preferredWidth":
                    setFilterColumnWidth((TableColumn)evt.getSource(),                   
                            (int)evt.getNewValue());
                    break;
                case "headerValue":
                    setFilterColumnName((TableColumn)evt.getSource(),                   
                            (String)evt.getNewValue());
                    break;
                case "visible":
                    setFilterColumnVisible((TableColumn)evt.getSource(),
                            (boolean)evt.getNewValue());
                    break;
                default:
                    System.out.println(evt.getPropertyName() + " : " + evt.getOldValue() + " | " + evt.getNewValue());
            }
        }       
    };

    public KTableFilterPanel(KTable table) {
        this.table = table;
        registerListeners();

        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        for (TableColumn column : table.getColumns()) {
            addFilterColumn(column);
        }
    }

    private void addFilterColumn(TableColumn column) {
        addFilterColumn(column, -1);
    }
    private void addFilterColumn(TableColumn column, int index) {
        Object id = column.getIdentifier();
        if (columnIds.contains(id))
            return;
        JTextField filter = new JTextField(column.getHeaderValue().toString());
        if (index == -1) {
            columnIds.add(id);
            filters.add(filter);
        }
        else {
            columnIds.add(index, id);
            filters.add(index, filter);
        }
        add(filter, filters.indexOf(filter));

        revalidate();
    }
    private void removeFilterColumn(TableColumn column) {
        Object id = column.getIdentifier();
        if (!columnIds.contains(id))
            return;

        removeFilterColumn(columnIds.indexOf(id));
    }
    private void removeFilterColumn(int index) {
        JTextField filter = filters.remove(index);
        columnIds.remove(index);

        remove(filter);

        revalidate();
    }    
    private void moveFilterColumn(int from, int to) {
        if (from == to)
            return;
        Object id = columnIds.remove(from);
        JTextField filter = filters.remove(from);
        if (id == null || filter == null)
            return;

        columnIds.add(to, id);
        filters.add(to, filter);

        remove(filter);
        add(filter, to);

        revalidate();
    }
    private void setFilterColumnVisible(TableColumn column, boolean visible) {
        Object id = column.getIdentifier();
        if (!columnIds.contains(id))
            return;
        filters.get(columnIds.indexOf(id)).setVisible(visible);

        revalidate();
    }    
    private void setFilterColumnWidth(TableColumn column, int width) {
        Object id = column.getIdentifier();
        if (!columnIds.contains(id))
            return;
        JTextField filter = filters.get(columnIds.indexOf(id));

        Dimension old = filter.getPreferredSize();
        filter.setPreferredSize(new Dimension(width - 40, old.height));

        revalidate();
    }
    private void setFilterColumnName(TableColumn column, String name) {

    }

    private void registerListeners() {
        table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
            @Override
            public void columnAdded(TableColumnModelEvent e) {
                TableColumn column = table.getColumnModel().getColumn(e.getToIndex());
                addFilterColumn(column);
                column.addPropertyChangeListener(pcm);
            }
            @Override
            public void columnRemoved(TableColumnModelEvent e) {
                removeFilterColumn(e.getFromIndex());
            }
            @Override
            public void columnMoved(TableColumnModelEvent e) {
                moveFilterColumn(e.getFromIndex(), e.getToIndex());
            }
            @Override
            public void columnMarginChanged(ChangeEvent e) {}
            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {}
        });
    }

Much appreciated!

0

There are 0 answers