f



Cell focus in JTable - avoid focus on non-editable cells?

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

-- 
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.
0
Joe
2/16/2005 9:05:51 PM
comp.lang.java.gui 8286 articles. 0 followers. Post Follow

5 Replies
3741 Views

Similar Articles

[PageSpeed] 17

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

0
mitch
2/18/2005 7:36:41 PM
"mitch" <mgart@kronos.com> writes:

> 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

-- 
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.
0
Joe
2/18/2005 9:39:23 PM
On 2/18/2005 at 2:36:41 PM, mitch wrote:

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

-- 
Regards,

John McGrath
0
John
2/20/2005 6:29:34 AM
On 2/18/2005 at 4:39:23 PM, Joe Knapka wrote:

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

-- 
Regards,

John McGrath
0
John
2/20/2005 6:29:50 AM
"John McGrath" <ng@jpmcgrath.net> writes:

> On 2/18/2005 at 4:39:23 PM, Joe Knapka wrote:
> 
> > 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.

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

-- 
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.
0
Joe
2/22/2005 9:01:35 PM
Reply: