How to save one column from reordering in JTable?

I have a JTable and I need to reorder the columns. However, I want the first column to not be redirected. To enable reordering, I used the following:

 table.getTableHeader().setReorderingAllowed(true); 

Columns can now be reordered, including the first column that I don't want. Is there a way to lock the first column?

I saw some solutions that use two tables, with the first column being in a separate table, but maybe better / easier.

+14
java swing jtable
Jul 20 '09 at 18:31
source share
8 answers

I think you need to override the columnMoved() method in TableColumnModelListener . the TableColumnModelEvent class has a getFromIndex() method, which you should look to determine if it is your fixed column, and then you can cancel the event.

Hope this helps. BUT

+3
Jul 20 '09 at 18:58
source share

This is the solution I used to prevent 1st column reordering

 private int columnValue = -1; private int columnNewValue = -1; tblResults.getColumnModel().addColumnModelListener(new TableColumnModelListener() { public void columnAdded(TableColumnModelEvent e) {} public void columnMarginChanged(ChangeEvent e) {} public void columnMoved(TableColumnModelEvent e) { if (columnValue == -1) columnValue = e.getFromIndex(); columnNewValue = e.getToIndex(); } public void columnRemoved(TableColumnModelEvent e) {} public void columnSelectionChanged(ListSelectionEvent e) {} }); tblResults.getTableHeader().addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { if (columnValue != -1 && (columnValue == 0 || columnNewValue == 0)) tblResults.moveColumn(columnNewValue, columnValue); columnValue = -1; columnNewValue = -1; } }); 

Greetings

+7
Feb 08 '10 at 2:00
source share

Almost 4 years later, there is still no optimal solution in sight.

Another suboptimal approach to prevent drag and drop of the first column (and other columns above the first) is to intercept mouseEvents before the mouseInputListener set by uidelegate can handle them ( similar to the recent QA ).

Employees

  • a custom MouseMotionListener that delegates all events to the initial installation, with the exception of drag and drop, if this leads to another column above the first
  • replace original with custom
  • update replacement whenever LAF changes (as the original is controlled by ui). This requires subclassing JTableHeader and posting to updateUI

Custom MouseInputListener:

 /** * A delegating MouseInputListener to be installed instead of * the one registered by the ui-delegate. * * It implemented to prevent dragging the first column or any other * column over the first. */ public static class DragHook implements MouseInputListener { private JTableHeader header; private MouseListener mouseDelegate; private MouseMotionListener mouseMotionDelegate; private int maxX; public DragHook(JTableHeader header) { this.header = header; installHook(); } /** * Implemented to do some tweaks/bookkeeping before/after * passing the event to the original * * - temporarily disallow reordering if hit on first column * - calculate the max mouseX that allowable in dragging to the left * */ @Override public void mousePressed(MouseEvent e) { int index = header.columnAtPoint(e.getPoint()); boolean reorderingAllowed = header.getReorderingAllowed(); if (index == 0) { // temporarily disable re-ordering header.setReorderingAllowed(false); } mouseDelegate.mousePressed(e); header.setReorderingAllowed(reorderingAllowed); if (header.getDraggedColumn() != null) { Rectangle r = header.getHeaderRect(index); maxX = header.getColumnModel().getColumn(0).getWidth() + e.getX() - rx -1; } } /** * Implemented to pass the event to the original only if the * mouseX doesn't lead to dragging the column over the first. */ @Override public void mouseDragged(MouseEvent e) { TableColumn dragged = header.getDraggedColumn(); int index = getViewIndexForColumn(header.getColumnModel(), dragged); // dragged column is at second position, allow only drags to the right if (index == 1) { if (e.getX() < maxX) return; } mouseMotionDelegate.mouseDragged(e); } //-------- delegating-only methods @Override public void mouseReleased(MouseEvent e) { mouseDelegate.mouseReleased(e); } @Override public void mouseClicked(MouseEvent e) { mouseDelegate.mouseClicked(e); } @Override public void mouseEntered(MouseEvent e) { mouseDelegate.mouseEntered(e); } @Override public void mouseExited(MouseEvent e) { mouseDelegate.mouseExited(e); } @Override public void mouseMoved(MouseEvent e) { mouseMotionDelegate.mouseMoved(e); } //------------ un-/install listeners protected void installHook() { installMouseHook(); installMouseMotionHook(); } protected void installMouseMotionHook() { MouseMotionListener[] listeners = header.getMouseMotionListeners(); for (int i = 0; i < listeners.length; i++) { MouseMotionListener l = listeners[i]; if (l.getClass().getName().contains("TableHeaderUI")) { this.mouseMotionDelegate = l; listeners[i] = this; } header.removeMouseMotionListener(l); } for (MouseMotionListener l : listeners) { header.addMouseMotionListener(l); } } protected void installMouseHook() { MouseListener[] listeners = header.getMouseListeners(); for (int i = 0; i < listeners.length; i++) { MouseListener l = listeners[i]; if (l.getClass().getName().contains("TableHeaderUI")) { this.mouseDelegate = l; listeners[i] = this; } header.removeMouseListener(l); } for (MouseListener l : listeners) { header.addMouseListener(l); } } public void uninstallHook() { uninstallMouseHook(); uninstallMouseMotionHook(); } protected void uninstallMouseMotionHook() { MouseMotionListener[] listeners = header.getMouseMotionListeners(); for (int i = 0; i < listeners.length; i++) { MouseMotionListener l = listeners[i]; if (l == this) { listeners[i] = mouseMotionDelegate; } header.removeMouseMotionListener(l); } for (MouseMotionListener l : listeners) { header.addMouseMotionListener(l); } } protected void uninstallMouseHook() { MouseListener[] listeners = header.getMouseListeners(); for (int i = 0; i < listeners.length; i++) { MouseListener l = listeners[i]; if (l == this) { listeners[i] = mouseDelegate; } header.removeMouseListener(l); } for (MouseListener l : listeners) { header.addMouseListener(l); } } } 

Usage that survives when switching LAF, fi:

 JTable table = new JTable(new AncientSwingTeam()) { @Override protected JTableHeader createDefaultTableHeader() { JTableHeader header = new JTableHeader(getColumnModel()) { DragHook hook; @Override public void updateUI() { if (hook != null) { hook.uninstallHook(); hook = null; } super.updateUI(); hook = new DragHook(this); } }; return header; } }; 
+5
Jan 23 '13 at
source share

First you need to determine a better and easier way. What do you dislike about the two-step approach?

You cannot use TableColumnModelListener, because the event is fired "after", the column has already been moved.

The code for dragging a column is in BasicTableHeaderUI. So you can try redefining the code there, but then you will need to do this for all LAFs.

The code above calls JTableHeader.getReorderingAllowed () in the mousePressed event to determine if column reordering is allowed. I think you can override this method in JTableHeader and possibly use the MouseInfo class to get the current location of the mouse, to determine if it was above the first column, and then return false. But now you also need to create a custom JTable that uses its own table header.

Of course, with any of the suggestions above, you can prevent the first column from moving. But do not forget that you also need to prevent the inclusion of a second column before the first column. I do not believe that there is a short simple answer to the question.

A fixed column table is my version of how this will be related to the two tables. It is better? I don’t know, but it’s simple because only one line of code uses it.

+2
Jul 20 '09 at 23:31
source share

I had the same problem and I was looking for it. So far I have found two ways to do this.

  • The "if I rewrote it myself" method : changing base classes from Java.

TableColumn will need a new property, for example, "resizingAllowed", for this, "reorderingAllowed" is required. It follows that changes occur in BasicTableHeaderUI :

Has already:

 private static boolean canResize(TableColumn column, JTableHeader header) { return (column != null) && header.getResizingAllowed() && column.getResizable(); } 

This is also needed:

 private static boolean canMove(TableColumn column, JTableHeader header) { return (column != null) && header.getReorderingAllowed() && column.getReorderable(); } 

(Note: if you do not want the first column not to move, you can do without changing the TableColumns:

 private static boolean canMove(TableColumn column, JTableHeader header) { return (column != null) && header.getReorderingAllowed() && header.getColumnModel().getColumnIndex(column.getIdentifier()) != 0; } 

)

After two places to change in MouseInputListener :

  • in mousePressed by calling canMove() instead of header.getReorderingAllowed() . This ensures that there is no column that should not be moved.
  • But this is not enough, we need to prevent the movement of fixed columns while dragging another. You also need to change mouseDragged when it gets "newColumnIndex":

    if (0 <newColumnIndex && newColumnIndex <cm.getColumnCount ())

You need to add a condition if this new index can be moved, for example, using the canMove () method. Thus, when you drag a column onto this fixed one, you will still drag it, but it will not change them.

Note that for this method, you will need to explicitly configure the user interface for the JTableHeader used for your JTable, which is actually not ideal. But this is most adapted, as it concerns the problem where it should be.




  • "Let's try to block normal behavior with what we have . " Without changing the user interface, this method focuses on the JTableHeader to block commands created by the user interface.

First, to block the drag and drop of the first column, we need a subclass of JTableHeader with this overridden method:

 @Override public void setDraggedColumn(TableColumn pAColumn) { int lIndex = -1; if (pAColumn != null) lIndex = getColumnModel().getColumnIndex(pAColumn.getIdentifier()); if (lIndex != 0) super.setDraggedColumn(pAColumn); } 

This will prevent the user from dragging the first column. But, as described above, this is only one part of the problem, we need to prevent the replacement of another shuffled column with this first one.

So far, I do not have the correct method for this. I tried to subclass TableColumnModel and override the moveColumn() method:

 @Override public void moveColumn(int pColumnIndex, int pNewIndex) { //Move only if the first column is not concerned if (pColumnIndex =! 0 && pNewIndex != 0) super.moveColumn(pColumnIndex, pNewIndex); } 

But this will not work, since the user interface will still update the mouse position in the mouseDragged method, you will have a transition from the dragged column to another location.

So, I'm still looking and wondering if anyone has any suggestions for this part.

+1
Aug 12 '09 at 16:07
source share

I used "The". Try to block normal behavior by using the fact that we have a "method". Gnupi said that he did not solve the second part of the problem. Here is the solution for Windows XP L & F:

  • Copy the XPStyle class for yourself.
  • expand WindowsTableHeaderUI . Check out the source code .
  • use it: getTableHeader().setUI(new TreeTableWindowsTableHeaderUI());

Thanks to Gnoupi for the effort.

0
Oct 25 '09 at 7:25
source share

At first I used the last Gnoupi clause, which subclassed TableColumnModel and redefined moveColumn, but still there were some annoying jumps.

This is β€œmy” fully working and tested solution without an unpleasant jump, it is mainly based on the proposals of StanislavKo and kleopatra. I added a more complex mechanism to return an 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 last valid move was taken instead of returning the column resistance completely.

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

illegalTableColumnMoveFromIndex is the index of the column from which it was moved when the last illegal move was detected.

illegalTableColumnMoveToIndex is the index of the column to which it was moved when the last illegal move was detected.

The code inside mouseDragged is enough to prevent dragging and dropping a frozen column, the rest prevents the transfer of another column to a frozen column.

It works the same as it does on Microsoft Windows, because I am extending the WindowsTableHeaderUI, but instead use the reflection API to set the input listener to enter the header of the table header, call uninstallerListeners () and finally call header.addMouseListener (mouseInputListener) and header .addMouseMotionListener (mouseInputListener) to provide my solution with a cross platform without any assumptions about the class name for each table header user interface.

I admit that this may be slightly less reliable than kleopatra solution. I thank all of you for your help, I am very grateful, and I am very glad to see that teamwork just works :)

0
May 23 '14 at 12:27
source share

I will just return the column after the move is complete. So something like that.

 @Override public void moveColumn(int from, int to) { super.moveColumn(from, to); if (from == 0 || to == 0) { super.moveColumn(to, from); } } 
0
Feb 16 '15 at 22:33
source share



All Articles