-
-
Save exhuma/976531 to your computer and use it in GitHub Desktop.
package lu.statec.gui.blaise; | |
import java.awt.event.KeyEvent; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
import javax.swing.JComponent; | |
import javax.swing.KeyStroke; | |
import javax.swing.table.TableModel; | |
import org.jdesktop.swingx.JXTable; | |
/** | |
* This table overrides the selection behavior. If the selection happens to land | |
* on a non-editable cell, the selection is forwarded to the next editable cell. | |
* | |
* Additionally, the "Enter"/"Return" key is rebound, so it selects the next | |
* cell instead of next row. | |
* | |
* NOTE: | |
* It extends JXTable from swingx. This is for convenience only. If you don't | |
* have or want to use swingx, you can simply replace it with a simple JTable | |
* in the class definition. | |
* | |
* Original idea by Joe Knapka can be found at: | |
* http://www.javakb.com/Uwe/Forum.aspx/java-gui/3796/Cell-focus-in-JTable-avoid-focus-on-non-editable-cells | |
* | |
* @author Michel Albert | |
*/ | |
public class QuickEditTable extends JXTable { | |
public static enum DIR { | |
Up, Down, Left, Right | |
} | |
/** | |
* The logger | |
*/ | |
private static final Logger LOG = Logger.getLogger(QuickEditTable.class.getCanonicalName()); | |
/** | |
* Standard constructor | |
*/ | |
public QuickEditTable() { | |
init(); | |
} | |
/** | |
* Default constructor, initialising the table with a TableModel | |
* | |
* @param tableModel | |
*/ | |
public QuickEditTable(TableModel tableModel) { | |
super(tableModel); | |
init(); | |
} | |
/** | |
* Initialisations common to all constructors. | |
*/ | |
private void init() { | |
// When pressing enter, move to the next cell instead of the next row. | |
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) | |
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "selectNextColumnCell"); | |
} | |
@Override | |
public void changeSelection(int row, int col, boolean toggle, boolean expand) { | |
// This method is called when the user tries to move to a different cell. | |
// If the cell they're trying to move to is not editable, we look for | |
// the next cell in the proper direction that is editable. | |
// initialise the new (future) selection to the indices as specified in | |
// the method call. | |
// if everything is "normal" we can just use these values. All special | |
// cases will overwrite the value contained herein. Eventually, these | |
// variables are returned. | |
int targetViewRow = row; | |
int targetViewCol = col; | |
int targetModelRow = convertRowIndexToModel(targetViewRow); | |
int targetModelCol = convertColumnIndexToModel(targetViewCol); | |
if (LOG.isLoggable(Level.FINE)){ | |
LOG.fine(String.format("Attempting to change the table selection " | |
+ "to row %d, col %d, using toggle=%b and expand=%b", | |
targetViewRow, targetViewCol, toggle, expand)); | |
LOG.fine(String.format(" --> this maps to model row %d and col %d", | |
targetModelRow, targetModelCol)); | |
} | |
if (!getModel().isCellEditable(targetModelRow, targetModelCol)) { | |
if (LOG.isLoggable(Level.FINE)){ | |
LOG.fine(String.format("Cell %d,%d (%d,%d) is not editable!", | |
targetViewRow, targetViewCol, targetModelRow, targetModelCol)); | |
} | |
// Find the row and column we're coming from. | |
int oldViewRow = getEditingRow(); | |
int oldViewCol = getEditingColumn(); | |
if (oldViewRow == -1) { | |
oldViewRow = getSelectedRow(); | |
} | |
if (oldViewCol == -1) { | |
oldViewCol = getSelectedColumn(); | |
} | |
if (LOG.isLoggable(Level.FINE)) { | |
LOG.fine(String.format("We came from cell %d,%d", | |
oldViewRow, oldViewCol)); | |
} | |
DIR direction; | |
if (oldViewCol == targetViewCol && oldViewRow < targetViewRow) { | |
direction = DIR.Down; | |
} else if (oldViewCol == targetViewCol && oldViewRow >= targetViewRow) { | |
direction = DIR.Up; | |
} else if (oldViewCol == targetViewCol && oldViewRow == targetViewRow) { | |
direction = DIR.Left; | |
} else { | |
// defaulting to right | |
direction = DIR.Right; | |
} | |
LOG.fine(String.format("Moving %s", direction)); | |
// determine next cell position | |
while (!getModel().isCellEditable(targetModelRow, targetModelCol)) { | |
LOG.fine(String.format("Model-Cell %d,%d is still not editable", | |
targetModelRow, targetModelCol)); | |
switch (direction) { | |
case Up: | |
targetViewRow -= 1; | |
if (targetViewRow < 0) { | |
targetViewRow = getRowCount() - 1; | |
} | |
break; | |
case Down: | |
targetViewRow += 1; | |
if (targetViewRow > getRowCount() - 1) { | |
targetViewRow = 0; | |
} | |
break; | |
case Left: | |
targetViewCol -= 1; | |
if (targetViewCol < 0) { | |
targetViewCol = getRowCount() - 1; | |
targetViewRow -= 1; | |
if (targetViewRow < 0) { | |
targetViewRow = getRowCount() - 1; | |
} | |
} | |
break; | |
case Right: | |
targetViewCol += 1; | |
if (targetViewCol > getColumnCount() - 1) { | |
targetViewCol = 0; | |
targetViewRow += 1; | |
if (targetViewRow > getRowCount() - 1) { | |
targetViewRow = 0; | |
} | |
} | |
break; | |
} | |
targetModelRow = convertRowIndexToModel(targetViewRow); | |
targetModelCol = convertColumnIndexToModel(targetViewCol); | |
} | |
LOG.fine(String.format("Trying to move selection to %d,%d instead!", | |
targetViewRow, targetViewCol)); | |
} | |
super.changeSelection(targetViewRow, targetViewCol, toggle, expand); | |
} | |
} |
My current version uses offsets to ensure model indices. I should replace this with properly mapped indices. I am currently working on this.
I just finished the modifications concerning the row/column indices. They are now properly mapped to the underlying model. Along the lines, I added a standard logger and some logging messages.
Rewrote the selection logic slightly. My previous modification had a flawed logic concerning the model <-> view
conversion of column indices. This implementation seems to work correctly. At the same time, I inlined the two separate methods into one block.
Hello, it's a great pleasure to say hello, I do not speak or write in English and I apologize if it does not read well since I use Google translation, I'm a Java beginner and I do not know how to start this class to use a JFrame, I have a project at the university and they ask me to do what they implemented in this class. I do not know if you could help me use your class from a jframe that has a table to evaluate the cells when they have the focus, thanks in advance.
I use the Netbeans IDE and the table is created graphically, not by code, my question is how do I apply its class to the table that I create graphically. So I have tried but it does not work for me:
Object [] col = {"Sku", "Descripcon", "Measure", "Quantity", "Price", "SubTotal"};
// this table is the one I have created from the graphic environment and here I assign it to its class but it does not work
table = new CustomSelectTable (model);
I do not know how it would be the correct way to implement your class to the JTable that you create.
And modelÑ
DefaultTableModel model = new DefaultTableModel(null,col);
This class was first written by Joe Knapka. With his permission, I decided to put it here, to allow easy fixes and edits.
Joe's original post: http://www.javakb.com/Uwe/Forum.aspx/java-gui/3796/Cell-focus-in-JTable-avoid-focus-on-non-editable-cells