How to keep a single column from being reordered in a JTable?

前端 未结 8 1791
时光说笑
时光说笑 2020-11-30 09:17

I have a JTable and I need to be able to reorder the columns. However I want the first column to not be able to be re-ordered. I used the following to enable re

相关标签:
8条回答
  • 2020-11-30 09:46

    At first, I used the very last Gnoupi's suggestion consisting in subclassing the TableColumnModel and overriding moveColumn but there were still some annoying jumps.

    This is "my" fully working and tested solution with no nasty jump, it mainly relies on StanislavKo and kleopatra's suggestions. I added a more complicated mechanism to revert the unwanted move when releasing the mouse button :

    table.getTableHeader().setUI(new WindowsTableHeaderUI() {
            @Override
            protected MouseInputListener createMouseInputListener() {
                return new BasicTableHeaderUI.MouseInputHandler() {
    
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        if (header.isEnabled() && header.getReorderingAllowed() && header.getDraggedColumn() != null && header.getDraggedColumn().getModelIndex() == frozenColumnModelIndex) {
                            header.setDraggedDistance(0);
                            header.setDraggedColumn(null);
                            return;
                        }
                        super.mouseDragged(e);
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        if (header.isEnabled() && header.getReorderingAllowed() && header.getDraggedColumn() != null &&
                            0 <= illegalTableColumnMoveFromIndex && illegalTableColumnMoveFromIndex < header.getTable().getColumnModel().getColumnCount()) {
                            header.setDraggedDistance(0);
                            header.setDraggedColumn(null);
                            header.getTable().getColumnModel().moveColumn(illegalTableColumnMoveToIndex, illegalTableColumnMoveFromIndex);
                            illegalTableColumnMoveFromIndex = -1;
                            illegalTableColumnMoveToIndex = -1;
                            return;
                        }
                        super.mouseReleased(e);
                    }
                };
            }
        });
        table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
            @Override
            public void columnAdded(TableColumnModelEvent e) {
            }
    
            @Override
            public void columnRemoved(TableColumnModelEvent e) {
            }
    
            @Override
            public void columnMoved(TableColumnModelEvent e) {
                if (e.getFromIndex() != e.getToIndex() && table.getColumnModel().getColumn(e.getFromIndex()).getModelIndex() == frozenColumnModelIndex) {
                    illegalTableColumnMoveFromIndex = e.getFromIndex();
                    illegalTableColumnMoveToIndex = e.getToIndex();
                } else {
                    illegalTableColumnMoveFromIndex = -1;
                    illegalTableColumnMoveToIndex = -1;
                }
            }
    
            @Override
            public void columnMarginChanged(ChangeEvent e) {
            }
    
            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
            }
        });
    

    Note that the latest valid move is accepted instead of completely reverting the column drag.

    frozenColumnModelIndex is the index of the "frozen" column in the table model.

    illegalTableColumnMoveFromIndex is the index of the column from where it was moved when the latest illegal move was detected.

    illegalTableColumnMoveToIndex is the index of the column to where it was moved when the latest illegal move was detected.

    The code inside mouseDragged is enough to prevent the frozen column from being dragged, the rest allows to prevent another column from being dragged to the frozen column.

    It works as is under Microsoft Windows as I extend WindowsTableHeaderUI but rather use the reflection API to set the mouse input listener of the table header UI, call uninstallerListeners() and finally call header.addMouseListener(mouseInputListener) and header.addMouseMotionListener(mouseInputListener) in order to drive my solution cross-platform without making any assumption on the name of the class for each table header UI.

    I admit it might be a bit less robust than kleopatra's solution. I thank you all for your help, I'm really grateful and I'm really happy to see that collaborative work just works :)

    0 讨论(0)
  • 2020-11-30 09:48

    First you need to define a better and simpler way. What don't you like about the 2 table approach?

    You can't use a TableColumnModelListener, because the event is fired "after" the column has already been moved.

    The code for dragging the column is found in the BasicTableHeaderUI. So you could try overriding the code there, but then you would need to do it for all LAFs.

    The above code invokes JTableHeader.getReorderingAllowed() on a mousePressed event to determine if column reordering is allowed. I guess you could override that method in the JTableHeader and perhaps use the MouseInfo class to get the current mouse location to determine if it was over the first column and then return false. But then now you would also need to create a custom JTable that uses the custom table header.

    Of course with either of the above suggestions you might be able to prevent the first column from being moved. But don't forget you also need to prevent the 2nd column from being inserted before the first column. I don't believe there is a short simple answer to the question.

    Fixed Column Table is my version of how this would be imlemented with two tables. Is it better? I don't know, but it is simple since its only a single line of code to use it.

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