Java Forum / GUI / February 2005
Cell focus in JTable - avoid focus on non-editable cells?
Joe Knapka - 16 Feb 2005 21:05 GMT Hi everyone,
I googled c.l.j.gui and the web for this, but while the question seems to have been asked many times, I did not encounter a definitive answer.
I have a JTable that has a number of non-editable cells, and I would like to prevent non-editable cells from getting the keyboard focus. When the user tabs out of an editable cell, I want the focus to go immediately to the next editable cell in the focus cycle. Is there a straightforward way to accomplish that? (A pointer to a FAQ, if applicable, would be more than sufficient.)
Thank you,
-- Joe Knapka
 Signature pub 1024D/BA496D2B 2004-05-14 Joseph A Knapka Key fingerprint = 3BA2 FE72 3CBA D4C2 21E4 C9B4 3230 94D7 BA49 6D2B If you really want to get my attention, send mail to jknapka .at. kneuro .dot. net.
mitch - 18 Feb 2005 19:36 GMT I think the common thing to do, in Swing GUIs and other GUIs, is to let focus go to all cells whether editable or not. The GUI will look and feel different in an editable cell versus a non-editable one. I think users would be surprised if they use the TAB key and it doesn't go from one cell to the next, whether or not the cells are editable.
If you really wanted to do this you probably could by overriding JTable.changeSelection() but you would have to remember the previously selected cell so you'll know whether to go backwards or forwards on TAB and shift-TAB. Also you might want to do different things depending whether the user is selecting a cell with the keyboard or the mouse.
It's probably doable but your users might be confused by the results.
- Mitch Gart
Joe Knapka - 18 Feb 2005 21:39 GMT > I think the common thing to do, in Swing GUIs and other GUIs, is to > let focus go to all cells whether editable or not. The GUI will look > and feel different in an editable cell versus a non-editable one. I > think users would be surprised if they use the TAB key and it doesn't > go > from one cell to the next, whether or not the cells are editable. My user base is accustomed to old (I mean o_l_d) VDT apps, in which a tab takes you to the next editable "field". I'm basically using a JTable to simulate that kind of UI; which means many of the cells (upwards of 50% in many cases) contain only descriptive labels, and the users hate that the focus arrives on those non-editable cells. They haven't caught on yet that the arrow keys are probably more efficient than tabs for moving around a sparse table; even at that, having to monkey around with the arrows really gets in the way of the "tab,type some data,tab,type some data" cycle which is almost a Zen mantra for these people. OTOH they're the users, and it's my job to make them happy; and giving them heroin instead of software is not currently an option.
Using JTable for this sort of UI seemed like a good idea at the time; is there a better way? I suppose I could use a panel with a GridLayout and a bunch of individual controls instead, but then the connection between the UI and the model for each screen will be considerably more complicated -- I can handle that generically with JTable and TableModel, which is a big win for me, because I've got many hundreds of screens (==JTables) to maintain.
> If you really wanted to do this you probably could by overriding > JTable.changeSelection() but you would have to remember the > previously selected cell so you'll know whether to go backwards or > forwards on TAB and shift-TAB. Also you might want to do different > things depending whether the user is selecting a cell with the > keyboard or the mouse. Thanks, I'll look into that. I have managed to avoid truly comprehending the Swing focus model thus far, but I guess the days of wine and roses are over.
> It's probably doable but your users might be confused by the results. I can do it both ways and let them decide which they like better :-)
Thank you,
-- Joe
 Signature A real God would simply Be, and it would be as rare to find a person who did not acknowledge God's existence as it is to find someone who denies the existence of the earth. -- Mark Nutter -- pub 1024D/BA496D2B 2004-05-14 Joseph A Knapka Key fingerprint = 3BA2 FE72 3CBA D4C2 21E4 C9B4 3230 94D7 BA49 6D2B If you really want to get my attention, send mail to jknapka .at. kneuro .dot. net.
John McGrath - 20 Feb 2005 06:29 GMT > Thanks, I'll look into that. I have managed to avoid truly > comprehending the Swing focus model thus far, but I guess the > days of wine and roses are over. The (actually AWT) focus model is not involved here. That works with components, and a JTable is a single component. The cells do not actually contain components, which is pretty much the whole idea of a JTable. If you created a component for every cell of a large table, the resources required would be prohibitive.
What you need to track and modify is the selection for the JTable. What makes this ugly is that there are actually two different selections models: row and column. You get the row selection model with getSelectionModel(). The column selection model is held by the TableColumnModel.
In single selection mode, which I presume you are using, the selected cell is identified by the selected row and column in the two different models. What may cause problems, since the two models are updated separately. If the user switches from [3,4] to [6,7] with the mouse, it will appear as two separate selection changes, one for the row and one for the column. That will make it difficult to know what to skip over.
> the connection between the UI and the model for each screen will be > considerably more complicated -- I can handle that generically with > JTable and TableModel, which is a big win for me, because I've got > many hundreds of screens (==JTables) to maintain. I think you could handle this generically with separate fields, too. You can attach a name to a field (all Java components have a "name" property), so you could traverse the UI hierarchy of the form and attach the wiring that you needed to talk to the model based on the name of the field and the class of the component. You can also attach arbitrary client properties to Swing components.
 Signature Regards,
John McGrath
Joe Knapka - 22 Feb 2005 21:01 GMT > > Thanks, I'll look into that. I have managed to avoid truly > > comprehending the Swing focus model thus far, but I guess the [quoted text clipped - 30 lines] > the class of the component. You can also attach arbitrary client > properties to Swing components. I wasn't aware of that. However, I've got the JTable working the way I want. Here's the code (below), in case anyone else every needs something similar. The deal is that if the user tabs right or shift-tabs left, we go to the next editable cell in the "natural" (as in "natural for Americans and other English speakers") cell order - left-to-right, top-to-bottom. The same happens upon a left- or right-arrow. If the user uses the up or down arrow, we try to go directly up or down to another editable cell in the same column. If the user clicks a non-editable cell, we move to the next editable cell in the "natural" order. If we can't find an editable cell to move to, we just stay where we are and do the default JTable select behavior.
Thanks for the pointers, everyone. I'm sure there's lots wrong with this code (among other things, it's not dealing with the "toggle" and "expand" parameters in their full glory), but it works for what I need :-)
public CustomSelectTable extends JTable {
public void changeSelection(int row,int col,boolean toggle,boolean expand) { // This method is called when the user tries to move to a diffferent cell. // If the cell they're trying to move to is not editable, we look for // then next cell in the proper direction that is editable. if (!getModel().isCellEditable(row,col)) { // Find the row and column we're coming from. int curRow = getEditingRow(); int curCol = getEditingColumn(); if (curRow == -1) curRow = getSelectedRow(); if (curCol == -1) curCol = getSelectedColumn();
// We may need to wrap-around. int nRows = getRowCount(); int nCols = getColumnCount();
// If we can't find a cell to move to, we'll stay here. int nextRow = row; int nextCol = col;
if (col==curCol) { // Up or down motion - go only up or down. int direction = row-curRow; if (direction>1) direction=1; if (direction<-1) direction=-1; nextRow = findNextEditableRow(row,col,direction,nRows,nCols); } else if (row == curRow) { // Left-or-right motion - use the "natural" (for Americans) order: // left-to-right, top-to-bottom, or vice-versa if we're trying // to move to the left. We'll wrap from the bottom row to the top // and vice-versa if necessary. int direction = col-curCol; if (direction>1) direction=1; if (direction<-1) direction=-1; int[] nextCell = findNextEditableCell(row,col,direction, nRows,nCols); nextRow = nextCell[0]; nextCol = nextCell[1]; } else { // Both row and column differ. This probably means we've // moved off the end of a row, or else the user has clicked // on some random cell. The direction is controlled // by the row difference (this doesn't always do something // intuitive; always setting direction=1 might work better). int direction = row-curRow; if (direction>1) direction=1; if (direction<-1) direction=-1; if ((row==0) && (curRow==nRows-1)) direction=1; int[] nextCell = findNextEditableCell(row,col, direction,nRows,nCols); nextRow = nextCell[0]; nextCol = nextCell[1]; } // Go to the cell we found. super.changeSelection(nextRow,nextCol,toggle,expand); } else { // It's an editable cell, so leave the selection here. super.changeSelection(row,col,toggle,expand); } }
// Search for an editable cell starting at row,col and using the // "natural" order. int[] findNextEditableCell(int row,int col, int direction,int nRows,int nCols) { int origRow=row; int origCol=col; do { col = col+direction; if (col>=nCols) { col = 0; row += direction; } if (col<0) { col = nCols-1; row += direction; } if (row>=nRows) row = 0; if (row<0) row = nRows-1; System.out.println("FNEC looking at "+row+','+col); if (isCellEditable(row,col)) return new int[]{row,col}; } while (!((row==origRow)&&(col==origCol)));
// Nothing editable found; stay here. return new int[]{origRow,origCol}; }
// Search directly above/below for an editable cell. int findNextEditableRow(int row,int col,int direction,int nRows,int nCols) { int origRow = row; do { row = row+direction; if (row<0) row = nRows-1; if (row>=nRows) row=0; if (isCellEditable(row,col)) return row; } while (row != origRow); // Nothing editable found, stay here. return origRow; }
} // End class CustomSelectTable.
Cheers,
-- Joe
 Signature A real God would simply Be, and it would be as rare to find a person who did not acknowledge God's existence as it is to find someone who denies the existence of the earth. -- Mark Nutter -- pub 1024D/BA496D2B 2004-05-14 Joseph A Knapka Key fingerprint = 3BA2 FE72 3CBA D4C2 21E4 C9B4 3230 94D7 BA49 6D2B If you really want to get my attention, send mail to jknapka .at. kneuro .dot. net.
John McGrath - 20 Feb 2005 06:29 GMT > If you really wanted to do this you probably could by overriding > JTable.changeSelection() but you would have to remember the > previously selected cell so you'll know whether to go backwards or > forwards on TAB and shift-TAB. That may be a problem. According to the JavaDocs for changeSelection():
Some UIs may need more functionality than this method provides, such as when manipulating the lead for discontiguous selection, and may not call into this method for some selection changes.
This might suggest that this method will be used in the simpler cases, such as when using single selection, but I do not think you can count on that based on the documentation.
Unfortunately, the alternatives present their own problems.
 Signature Regards,
John McGrath
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|