-
-
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